/v1/realtime, and @eesi/realtime is an
internal package rather than something to install.
Before you start
An API key, kept server-side
An API key, kept server-side
Create one under Developer → API keys in the
console. It never reaches the browser: the page
below asks your own server for a short-lived ticket instead. See
Authentication.
A realtime model this deployment serves
A realtime model this deployment serves
GET /v1/audio/models and take an id whose kind is realtime. The
examples use nur-realtime-v1.A voice id, or none
A voice id, or none
GET /v1/voices gives you ev_… ids for built-in and cloned voices. Omit
the field and the model uses its default. Note that
The retired omni realtime id ignored a cloned voice rather than refusing it.1. The ticket route
A browser cannot put anAuthorization header on a WebSocket handshake, and a
key in a URL is a key in your access logs. Your server authenticates the
visitor however it already does, then mints a credential that dies on first use.
2. Capture the microphone at the wire rate
The wire is 16 kHz mono PCM16, base64, in small chunks paced in real time. The pacing is not a detail: end-of-turn detection reads the arrival timing of frames, so audio delivered faster than it was spoken produces bad endpointing. Live microphone capture paces itself, which is why this is easy in a browser and fiddly from a file.3. Play the reply, and be able to stop it instantly
Reply audio is 16 kHz PCM16 inresponse.output_audio.delta. Schedule each
chunk at a running playhead so consecutive chunks stitch sample-accurately, and
keep every scheduled node so barge-in can stop all of them at once.
4. The session
One socket, onesession.update, then a loop over events.
Handling events
Four rules do most of the work, and three of them are places a naive client goes wrong.This server emits the canonical event names. The legacy OpenAI spellings
without
output_ — response.audio.delta, response.audio_transcript.done
— never arrive here, but folding both onto the canonical name at your
decoder’s edge costs nothing and keeps the client working against either.
The corpus that pins these rules is spec/realtime/v1/.5. Surviving a drop
A deploy, a screen lock, a train tunnel. The gateway checkpoints your session at every turn boundary and hands you asession_id and a resume_token in the
eesi.session greeting; reconnect with both and the conversation continues
with its context replayed into a fresh pipeline. At most the turn in flight is
lost.
The close code decides what to do, and two of them mean opposite things:
1008 is a limit or a rejection and redialling it repeats it. 1011 is the
backend being down and retrying changes nothing until it is back. Rendering
both as “all sessions are busy, try again” is a real bug: it tells users an
outage is normal load and sends them into a retry loop that cannot succeed.
A resume that misses — expired, ended, or not yours — is not a refusal. You
get a fresh session and a new handle in the greeting, because a client that
treated it as fatal would abandon a conversation the person is still trying
to have.
6. Start it from a click
The autoplay policy needs a user gesture before any audio plays, andgetUserMedia needs one for the permission prompt.
What it costs
$0.001 per connected minute, metered from the moment the upstream pipeline comes up. The balance and the free-tier day are re-checked once a minute while the call is up, which is why theeesi.session limit frame exists. See
Pricing and limits.
Recording is on unless the deployment or the workspace turned it off. The
gateway sends an eesi.recording_disclosure event once after session.created
carrying the wording to show a person before they speak — showing it is the
deployer’s duty, not the platform’s, and your agent should be built to show it.
See Compliance.
Next
Realtime events
Every event, and the rules this page implements.
Turn-taking and barge-in
How the server decides you have stopped, and what still goes wrong.
Connections that survive
Tickets, keepalives, close codes and resumption in full.
Duet
Two of these sessions, cross-piped, to test the persona.