Skip to main content

Realtime

WSS wss://test.kailin.com.cn/v1/realtime

WebSocket-based realtime bidirectional voice conversations (OpenAI Realtime protocol) — built for voice assistants, live translation, and other low-latency scenarios.

Connecting​

The model name goes in the query string; auth is the same as the HTTP endpoints:

wss://test.kailin.com.cn/v1/realtime?model=gpt-4o-realtime-preview
const ws = new WebSocket(
'wss://test.kailin.com.cn/v1/realtime?model=gpt-4o-realtime-preview',
{
headers: {
Authorization: 'Bearer sk-your-token',
'OpenAI-Beta': 'realtime=v1',
},
}
);
note

Browser new WebSocket cannot set custom headers. Either pass the token via subprotocol parameters, or proxy the WebSocket through your own backend (recommended, keeps the token off the frontend).

Message Format​

All messages are JSON text frames with a type field.

Session Setup​

After connecting, the server sends session.created. Clients usually send session.update first to configure voice and turn detection:

{
"type": "session.update",
"session": {
"instructions": "You are a voice assistant. Keep answers short.",
"voice": "alloy",
"input_audio_format": "pcm16",
"output_audio_format": "pcm16",
"input_audio_transcription": { "model": "whisper-1" },
"turn_detection": { "type": "server_vad" }
}
}

Sending User Audio​

Audio is sent in chunks as Base64-encoded PCM16 (24kHz mono):

{ "type": "input_audio_buffer.append", "audio": "<base64 pcm16>" }
{ "type": "input_audio_buffer.commit" }

With server_vad enabled, the server detects the end of speech and commits automatically — no manual commit needed.

Triggering a Response​

{
"type": "response.create",
"response": { "modalities": ["text", "audio"], "instructions": "Be enthusiastic." }
}

Server Events​

EventDescription
session.created / session.updatedSession created / config applied
input_audio_buffer.speech_started / _stoppedVAD detected speech start / end
input_audio_buffer.committedAudio buffer committed
conversation.item.createdConversation item created
response.audio_transcript.delta / _doneReply transcript delta / done
response.audio.delta / _doneReply audio delta (Base64 PCM16)
response.text.delta / _doneText-only reply delta
response.doneCurrent response finished
errorError event

Full Flow Example​

const ws = new WebSocket(url);

ws.onopen = () => {
ws.send(JSON.stringify({
type: 'session.update',
session: { voice: 'alloy', turn_detection: { type: 'server_vad' } },
}));
// send an audio chunk…
ws.send(JSON.stringify({
type: 'input_audio_buffer.append',
audio: btoa(String.fromCharCode(...pcmChunk)),
}));
};

ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
switch (msg.type) {
case 'response.audio.delta':
playPcmChunk(atob(msg.delta));
break;
case 'response.audio_transcript.delta':
appendSubtitle(msg.delta);
break;
case 'response.done':
console.log('turn finished', msg.response.usage);
break;
}
};
caution

Realtime endpoints bill by audio duration and cost significantly more than text. Watch your session length while testing. Availability depends on the models configured in your channel.