Endpoints
base_url="https://gateway.langwatch.ai" and the virtual key in place of the ElevenLabs key. The key goes in the xi-api-key header the SDK already sends.
The ElevenLabs key itself stays on the organization’s ElevenLabs model provider. An SDK that still sends it gets 401 invalid_api_key, because the gateway reads that header as a virtual key.
The audio paths are served only by an ElevenLabs credential. A key that cannot reach ElevenLabs answers 400 model_provider_not_bound and no provider is called. There is no fallback to another provider.
Text to speech
/stream and /stream/with-timestamps take the same body and query string and reach the same paths on ElevenLabs. They are gated and metered exactly like the plain path.
/stream/with-timestamps answers with a stream of JSON objects, each carrying audio_base64, alignment and normalized_alignment:
The request body is capped at 1 MB; over the cap:
413 payload_too_large. The audio response is capped at 32 MiB, counted as it is relayed: a longer response is cut at the cap.
Speech to text
Request and response headers
TheX-LangWatch-End-User-Id, X-LangWatch-Metadata and Traceparent request headers work as on Chat Completions.
The audio paths return the same response headers as Chat Completions, plus ElevenLabs’ own response headers. A forwarded ElevenLabs error carries X-LangWatch-Provider: elevenlabs and the vendor’s Retry-After when it sent one.
Streaming
All three text to speech paths answer with a chunked body that is written and flushed as ElevenLabs sends it. If ElevenLabs fails mid-stream the connection is closed without the terminating chunk, so the HTTP client reports a truncated body. Speech to text does not stream. The transcript is returned complete.Single-use tokens
langwatch.session_id added. The same id is on the X-LangWatch-Session-Id response header. A token is valid for 15 minutes and opens one socket.
The socket runs from your client to ElevenLabs and does not pass through the gateway. The gateway does not see what the socket used, so your client reports it.
Any other
token_type answers 400 bad_request.
ElevenLabs’ token route takes no model, so the gateway reads one from the model_id query parameter. It is resolved through the key’s aliases and allowlist and is the model the session is billed under. Pass the model your socket will use. Outside the allowlist: 400 model_not_allowed. model_id is not forwarded to ElevenLabs.
The route is served only by an ElevenLabs credential, and a customer on a residency host is minted on that host.
Opening the socket
The query parameter that carries the token differs per socket.eleven_v3 and eleven_v4 models run on the Text to Dialogue socket, not on stream-input. Mint a ttd_websocket token for it. ElevenLabs’ reference does not list that token type, and the Text to Dialogue socket accepts no other: a tts_websocket token is refused with close code 1008 and invalid_token_type.
Reporting usage and closing
ElevenLabs sockets send no usage. Count it in your client and post it to the session:id names the report. Reports with different ids add up, and a report resent with the same id is recorded once. A report with no id and no final is read as the session total and closes the session. Add "final": true to any report to close the session after it is recorded.
To close without usage:
Relayed sockets
The gateway also serves the ElevenLabs sockets itself. The client opens the socket on the gateway with its virtual key, the gateway opens the same path at ElevenLabs with the stored key and passes frames both ways. Use this when the client should hold no ElevenLabs credential at all and should not report its own usage. A single-use token keeps the socket client to ElevenLabs and saves the hop.
Pass the virtual key as
Authorization: Bearer, as the xi-api-key header, or as the xi-api-key or authorization query parameter. The gateway removes the key parameters from the query string and forwards the rest as written (output_format, audio_format, language_code and so on). model_id goes through the key’s aliases and allowlist; outside the allowlist the request answers 400 model_not_allowed before the upgrade.
xi-api-key, xi_api_key or authorization, the gateway strips those fields from that frame. Every other frame is forwarded byte for byte, in both directions.
How relayed sockets are metered
ElevenLabs sockets state no usage, so the gateway counts what the client sends.- Speech. The characters of every
textfield the client sends:textonstream-inputand on each context ofmulti-stream-input, and eachinputs[].texton Text to Dialogue. The keep-alive" "counts one character and the closing""counts none. - Transcription. The seconds of audio sent: the decoded length of each
audio_base_64chunk divided by the byte rate ofaudio_format.pcm_16000, the default, is 32,000 bytes per second, andulaw_8000is 8,000.
1008), a revoked key (1008) and a deploy (1012). The codes and what the client should do are on Realtime voice.
Post-call webhook
{model_provider_id} is the id of the ElevenLabs model provider row in Settings, Model Providers. Store the webhook secret from ElevenLabs on that same provider row, under ELEVENLABS_WEBHOOK_SECRET.
The route takes no virtual key. Each delivery authenticates itself: the gateway relays the raw bytes and the ElevenLabs-Signature header to LangWatch, which computes the HMAC with the provider’s stored secret and accepts a signature timestamp at most 30 minutes old.
What happens with a delivery:
Responses:
The webhook is the fast path. Two minutes after a mint, LangWatch also reads the conversation back from ElevenLabs by its own id, so a session bills even when no delivery arrives.