type. This page is
the reference for both directions. If you are writing a client from scratch,
read it end to end; the two warnings near the bottom are the ones that cost
production incidents.
The handshake
Four frames open every socket, in this order:eesi.synthetic_audioeesi.recording_disclosureeesi.sessionsession.created
session.created reads a synthetic-audio marker instead, and the
field it wanted is not there.
session.created is the model’s opening frame, and it tells you what this end
supports instead of making you probe for it.
Both extra fields are additive. An OpenAI-compatible client that ignores them is
still correct; an EESI client reads them rather than guessing.
What you send
Anything else answers an
error with type unknown_or_invalid_event. That
includes eesi.keepalive on a gateway that does not advertise it — check the
eesi.session greeting first.
What arrives
Three more are the gateway’s own. They open the socket, in the order below,
before any model frame reaches you, and are namespaced
eesi. so an
OpenAI-compatible client can ignore all three:
The two events that read backwards
The recorded event streams inspec/realtime/v1/ pin this behaviour, and every
EESI client — the console, the iPhone app, the Mac engines, the gateway’s own
recorder — replays that corpus. There is one reducer behind all of them,
@eesi/realtime, but it is an internal package: it is not published, so write
your own decoder against the rules above rather than reaching for it.
Legacy spellings
Older OpenAI variants spell four events withoutoutput_:
This server emits only the canonical names. If your client also talks to a
backend that uses the legacy ones, fold both onto one name at the edge of your
decoder — handling one is how a client goes silent against exactly one backend.
A worked turn
What one exchange looks like on the wire, with a barge-in at the end:delta and a done carrying the same bytes,
so a client that concatenates deltas and one that replaces on done see the
same text — as long as the second one accumulates across segments. The reply is
“It’s sunny. And mild.” Keeping only the last done gives you “And mild.”
Next
Turn-taking and barge-in
What decides
speech_stopped, and what a cancelled turn owes your client.Connections that survive
The
eesi.session frames in full, and every close code.Errors
Every failure this API produces, and which are worth a retry.
OpenAI compatibility
What an existing realtime client has to branch on.