Skip to main content

OpenAI Realtime API — current wire protocol

As of 2026.

Endpoints

PurposeMethod + URL
Mint ephemeral tokenPOST https://api.openai.com/v1/realtime/client_secrets
WebRTC SDP exchangePOST https://api.openai.com/v1/realtime/calls?model=<model>

Model + voices

  • Model: gpt-realtime (GA).
  • Voices: alloy, ash, ballad, cedar, coral, echo, marin, sage, shimmer, verse.
  • Recommended defaults: marin (warm, natural) or coral (friendly).

Token request

POST /v1/realtime/client_secrets
Authorization: Bearer <apiKey>
Content-Type: application/json

{
"session": {
"type": "realtime",
"model": "gpt-realtime",
"audio": { "output": { "voice": "marin" } }
}
}

Response (top-level value is the ephemeral token, prefixed ek_):

{ "value": "ek_...", "expires_at": 1234567890, "session": { } }

SDP exchange

POST /v1/realtime/calls?model=gpt-realtime
Authorization: Bearer <ephemeralToken>
Content-Type: application/sdp

<raw SDP offer>

Returns raw SDP answer text (Content-Type: application/sdp).

session.update event (over data channel)

Send this the moment the data channel opens, and again after every state mutation. VCI uses manual turn detection — the client explicitly demarcates every user turn via input_audio_buffer.clear on Push-to-Talk press and input_audio_buffer.commit on release.

{
"type": "session.update",
"session": {
"type": "realtime",
"instructions": "<see Adapting → Session instructions>",
"tools": [ /* see Adapting → Tool schemas */ ],
"tool_choice": "auto",
"audio": {
"input": {
"transcription": { "model": "whisper-1" },
"turn_detection": null
},
"output": { "voice": "marin" }
}
}
}

If you prefer hands-free conversation instead of push-to-talk, swap turn_detection: null for the server-VAD block below and skip the PTT button; the model will auto-detect turn starts/stops:

"turn_detection": {
"type": "server_vad",
"threshold": 0.5,
"prefix_padding_ms": 300,
"silence_duration_ms": 500
}

Function call round-trip

When the model calls a tool, the data channel emits:

{
"type": "response.function_call_arguments.done",
"call_id": "call_...",
"name": "add_note",
"arguments": "{\"title\":\"...\"}"
}

Reply with the tool result:

{
"type": "conversation.item.create",
"item": {
"type": "function_call_output",
"call_id": "<same call_id>",
"output": "<JSON.stringify(result)>"
}
}

Then trigger the spoken confirmation:

{ "type": "response.create" }

Useful events to listen for

Event typeUse for
input_audio_buffer.speech_startedstatus → "listening"
input_audio_buffer.speech_stoppedstatus → "thinking"
conversation.item.input_audio_transcription.completedlog the heard user text
response.function_call_arguments.doneexecute tool → reply → respond
response.createdstatus → "speaking"
response.audio_transcript.donelog the assistant's text
response.donestatus → "idle"
errorlog + status → "error"