Overview
wss://api.meshapi.ai/v1/realtime is a WebSocket gateway for low-latency
realtime audio. It supports two modes: bidirectional speech-to-speech via
OpenAI’s Realtime API (served by OpenAI or Azure AI Foundry), and realtime
speech-to-text via ElevenLabs Scribe.
- Same auth surface as the rest of Mesh — your
rsk_...data-plane token. - For speech-to-speech models the wire format is identical to OpenAI’s
Realtime API. Mesh passes JSON event bodies through verbatim in both
directions, so any client written against the upstream spec works against
Mesh by switching the WebSocket URL.
elevenlabs/scribe_v2_realtimespeaks ElevenLabs’ Scribe frames instead. See Speech to Text. - Billed on usage, settled every 60 seconds during the session and at close.
Quickstart
Open a WebSocket towss://api.meshapi.ai/v1/realtime with a model query
parameter, send a session.update, then stream audio chunks via
input_audio_buffer.append events.
- Browser (raw WebSocket)
- curl-style probe
Authentication
Two methods are supported. Both require TLS —ws:// is rejected.
1. Subprotocol header (preferred). Send your key in the Sec-WebSocket-Protocol
header alongside the literal protocol marker:
?api_key=<YOUR_RSK_KEY> to the URL. The key is
redacted from server access logs but will appear in client-side history,
so prefer the subprotocol method anywhere you control the runtime.
Message protocol
Mesh is a transparent proxy for OpenAI’s Realtime API. Every event you send and receive is shaped exactly as upstream documents it — Mesh does not rewrite event types, field names, or payloads. See the OpenAI Realtime API reference for the full event catalog. The most common types you’ll exchange:Realtime uses OpenAI’s GA event protocol.
session.update must use the GA
shape ({"type":"realtime","output_modalities":[...],"audio":{...}}) — the
older beta shape (modalities/voice/input_audio_format) is rejected.
Audio travels as base64 inside JSON text events, as OpenAI’s protocol
defines. Mesh forwards binary WebSocket frames unchanged, but send audio as
input_audio_buffer.append events.Supported models
Themodel query parameter is required. Realtime supports two provider modes:
Consult
GET /v1/models for the current set of realtime-capable models — the
catalog is live and this table is a snapshot.
Pricing
MeshAPI charges OpenAI’s exact rates for realtime models — zero markup, no
surprises. Rates are subject to OpenAI’s pricing changes; consult
/v1/models
for the canonical current values./v1/usage history and the
dashboard. There is no in-stream cost message on the WebSocket — query
/v1/usage after the session completes.
Pre-flight pricing
The/v1/models response indicates which models support realtime and
includes per-million-token rates for text, audio, and cached audio inputs
and outputs. Use these to display estimates in your UI before opening a
session — no need to hard-code rates in the client.
Billing
- Balance hold. Opening a session holds up to $10 of your balance
until it closes (less for models priced by duration or sessions with a
token cap; no hold on BYOK). If your balance can’t cover the hold, the
session is refused with
insufficient_quota. If your account balance is exhausted during a session, the connection is closed with aninsufficient_quotaerror. Top up to reconnect. Partial responses up to the point of disconnect are still billed. - Concurrent sessions. An account can hold 5 concurrent realtime
sessions by default (a model can set its own cap in
realtime_max_concurrent_per_owneronGET /v1/models). The count is shared with streaming TTS and STT sessions. - Session token caps. Sessions configured with a max-token cap close
with a
session_token_cap_exceedederror once the cap is reached.
GET /v1/usage and the
dashboard. Sessions that get cut
short (network drop, browser tab close) still bill for the tokens that
were processed. Query /v1/usage for canonical numbers.
Limits and known caveats
- Session length. Mesh closes a session after 30 minutes with
session_duration_exceeded. Long-running agents should reconnect and resume application-level state. - Idle timeout. Mesh closes a socket that receives no client→server
frame for 60 seconds, with
idle_timeout. Send asession.updateping or keep the audio buffer flowing. - Browsers / Safari. Browsers can’t set request headers on a WebSocket and
can’t reliably send the space-separated
Bearer <key>subprotocol token. In the browser, authenticate with the?api_key=<rsk_...>query fallback. - No HTTP fallback. This endpoint only exists as a WebSocket upgrade;
a plain HTTP request to
/v1/realtimeis not served.
Errors
Realtime errors are delivered as a JSON frame ({ "type": "error", "error": { "code", "message" }, "request_id": "..." })
immediately before the WebSocket is closed. Use error.code for
programmatic handling — it is the stable, semantic identifier. The
WebSocket close code that follows is incidental.
error.code reference
In-band errors during a live session arrive as a regular
error event
with the OpenAI-shaped envelope shown above and are not accompanied by a
socket close.
WebSocket close codes (incidental)
These close codes accompany the JSON error frame on session-terminating errors. Checkerror.code for the semantic reason; the close code below
is informational only.
Next steps
- For the ElevenLabs Scribe realtime STT frame protocol, see Speech to Text → WebSocket Real-Time STT.
- Symptom-by-symptom fixes live in Troubleshooting → Realtime Audio.
- Review the Authentication guide for key rotation and scoping.
- See the API reference entry for the OpenAPI stub.
- Watch the upstream OpenAI Realtime API reference for new event types — Mesh forwards them without code changes.