GET
https://your-instance.com/v1/realtimeUpgrades to a WebSocket instead of returning a body. Audio flows both ways over the same connection, so the model can be interrupted mid-sentence — which is what makes a spoken conversation feel like one.
Connecting
Pass the model as a query parameter and your key as a bearer token. Browsers cannot set headers on a WebSocket handshake, so authenticate from your server and relay, rather than putting a key in front-end code.
import WebSocket from "ws";
const ws = new WebSocket(
"wss://your-instance.com/v1/realtime?model=gpt-realtime",
{ headers: { Authorization: `Bearer ${process.env.CLAWROUTER_API_KEY}` } },
);
ws.on("open", () => {
ws.send(JSON.stringify({
type: "session.update",
session: { modalities: ["text", "audio"], voice: "alloy" },
}));
});
ws.on("message", (raw) => {
const event = JSON.parse(raw.toString());
if (event.type === "response.audio.delta") {
// event.delta is base64 PCM — append it to your playback buffer
}
});Event flow
| Direction | Event | Meaning |
|---|---|---|
→ send | session.update | Set voice, modalities and turn detection |
→ send | input_audio_buffer.append | Push a chunk of microphone audio |
→ send | response.create | Ask for a reply now |
← receive | response.audio.delta | A chunk of spoken reply |
← receive | response.text.delta | A chunk of the transcript |
← receive | response.done | The turn is complete |
