Skip to main content

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_realtime speaks ElevenLabs’ Scribe frames instead. See Speech to Text.
  • Billed on usage, settled every 60 seconds during the session and at close.
It’s intended for voice agents, live transcription with response, and any half-duplex / full-duplex audio UX where round-trip latency matters.

Quickstart

Open a WebSocket to wss://api.meshapi.ai/v1/realtime with a model query parameter, send a session.update, then stream audio chunks via input_audio_buffer.append events.

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:
This matches OpenAI’s upstream auth and keeps the key out of URL logs. 2. Query string fallback. For browsers and tools that can’t customize the subprotocol cleanly, append ?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.
If both are present, the subprotocol wins.

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

The model 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.
Per-session usage and cost lands in your existing /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 an insufficient_quota error. 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_owner on GET /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_exceeded error once the cap is reached.
Usage is settled into your account’s usage log every 60 seconds while the session is open and again at close, accessible via 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 a session.update ping 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/realtime is 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. Check error.code for the semantic reason; the close code below is informational only.

Next steps