Overview
Realtime models run over a long-lived WebSocket connection: audio streams in, audio streams out, and the model can be interrupted mid-sentence — no “record, upload, wait, play back” cycle. The difference from stitching ASR + a text model + TTS is that this is end-to-end: the model hears tone, pauses and emotion directly, and speaks directly. Latency lands in the sub-second range. APIYI currently offers 4 models across 2 protocols, sharing one endpoint and one key:gpt-realtime-2.1/gpt-realtime-2.1-mini— OpenAI Realtime GA protocolqwen3.5-omni-plus-realtime/qwen3.5-omni-flash-realtime— Alibaba Cloud Model Studio protocol
server_vad and semantic_vad turn detection, full function-calling round trip (including result injection), image input, and usage broken out per modality. All of the above verified on all four models (2026-08-24, UTC+8).model parameter without changing the request body will not work — this is by far the most common integration failure. The differences amount to 6 fields and 3 event names, all listed under “Protocol Comparison” below.Request Beta Access
API Manual
Keys and Groups
Call Logs
Let an AI Agent Do the Integration
.md to any docs URL), then write code for your stack — the two field families, the sample-rate red line, cancel semantics and idle disconnects are all baked into the requirements.Have a coding agent integrate or troubleshoot Realtime voice. Copy and paste into Codex, Claude Code, Cursor and similar tools.
What this prompt saves you from
What this prompt saves you from
Why APIYI for Realtime Voice
One key, four models
wss endpoint, same auth. Switching models means changing the model parameter and the matching field template — no second vendor account to maintain.Direct access, no overseas setup
api.apiyi.com from mainland data centers, home broadband or overseas nodes. No upstream vendor account, identity verification or prepayment required.Protocol differences already mapped
Zero-cost self-test over text
Measured latency and concurrency
Direct support during the beta
Core Capabilities
Bidirectional streaming, interruptible
response.cancel at any time. The session survives and context is preserved. Verified on all four models.Two turn-detection modes
server_vad splits on silence duration, semantic_vad splits on intent (better at ignoring filler words like “uh-huh”). Both verified on all four models.Full function-calling loop
function_call_output injects the result, and the model continues speaking. Verified end to end on all four models.Image input, per-modality usage
usage returns text / audio / image tokens separately so cost can be attributed. Verified on all four models.Supported Models
Pricing
gpt-realtime-2.1, audio input $32 vs text input $4; audio output $64 vs text output $24). Run text-only during integration and switch to audio once the chain is verified — see “Start With Text” below.Realtime GA protocol
Model Studio protocol
The billing dimensions differ: image input is folded into the text tier, and output is split into “text only” and “text + audio” (only the audio portion is charged at the latter rate).Access Group
Technical Specs
Measured latency and concurrency
Measured 2026-08-24 (UTC+8) over the publicapi.apiyi.com path, 20 concurrent sessions × 2 models, single-turn text-only exchange:
Endpoint
model query parameter selects which one you reach.
⚠️ Protocol Comparison (read before switching models)
The two families share the endpoint, the auth scheme and the overall event flow. The differences are concentrated in thesession.update field structure and a few server event names.
Request field comparison
Server event comparison
session.created, session.updated, conversation.item.create, input_audio_buffer.append, input_audio_buffer.commit, response.create, response.cancel, response.done — are named identically in both.
Two minimal session.update payloads
The same thing written twice; copy directly. Model Studio protocol:Start With Text: What the Text Channel Is For, and a Three-Step Self-Test
An audio pipeline involves microphone capture, resampling, chunking and turn detection. Any broken link shows up as “nothing happens”, which is hard to diagnose. So do not start with a microphone.Text is the control plane, not a fallback input
In a realtime voice model, text is not “another way to send input” — it is the entire control channel other than the audio stream:Three-step self-test
Step 1: text only, no microphone
output_modalities to text only, disable turn detection, and send one input_text. That alone verifies the handshake, the key and group, whether you picked the right field template, whether session.update took effect, whether tools inject correctly, whether multi-turn context holds, and how concurrency behaves. No audio tokens are produced at all.Step 2: replay a local wav file
input_audio_buffer.append in 100 ms chunks. This decouples the audio pipeline (format, sample rate, chunking, commit, VAD triggering) from your business logic and makes it repeatable — the same file should produce the same result twice.Step 3: connect the live microphone
A runnable text smoke test
Depends only onwebsockets (pip install websockets). Flip one variable to switch protocols:
Session Features: Voice, Turn Detection, Tools, Images
Voice
Turn detection: server_vad and semantic_vad
server_vad— splits on silence duration, with straightforward parameters (threshold,silence_duration_ms,prefix_padding_ms).semantic_vad— splits on conversational intent, ignoring filler words and meaningless background noise. More robust in multi-speaker environments.- You can also disable turn detection (
nullornone) and run in manual mode: sendinput_audio_buffer.commityourself, thenresponse.create. This suits push-to-talk interfaces where the UI controls turns.
Function calling
Event order: the model emits aresponse.output_item.done of type function_call (carrying call_id and arguments) → the client executes it → the result is injected → another response.create lets the model continue.
Image input
Realtime GA protocol: putinput_image directly into the message; the value can be a data URI.
Error append image before append audio.. In testing, the working approach is to interleave input_image_buffer.append into the input_audio_buffer.append stream at roughly one frame per second.
Known Limitations (beta)
All four items below are measured, and all of them affect client code. Read this before integrating.Best Practices
Pick the field template by protocol family first
session.update payloads as two config constants selected by model name, rather than scattering if-branches. This is the part most likely to break during maintenance six months later.Pin session parameters in the first frame
output_modalities, voice, speed, turn_detection and transcription in the very first session.update. Voice especially — once audio has been produced it is too late.Pass a text smoke test before adding audio
Convert sample rate and channels on the client
Close out on output_item.done with a timeout
response.done alone. This approach is correct on both families and avoids hanging a turn when the user interrupts.Add keepalive and reconnect for long sessions
expires_at on Realtime GA. After reconnecting, replay session.update and any required context, otherwise the new session runs with defaults.Use a backend relay in production
Errors and Retries
event_id of each event and the session.id of the session, and include them when reporting an issue — it shortens diagnosis considerably. Note also that Realtime GA error objects carry code and param (naming the exact field and its accepted values), while Model Studio error messages are coarser. Validate field syntax on the former first when debugging.FAQ
Why is there no interactive playground on this page?
Why is there no interactive playground on this page?
Can I swap between the four models by changing only the model name?
Can I swap between the four models by changing only the model name?
modalities ↔ output_modalities, voice ↔ audio.output.voice, input_audio_format ↔ audio.input.format, turn_detection ↔ audio.input.turn_detection, input_audio_transcription ↔ audio.input.transcription, plus the event names response.text.delta ↔ response.output_text.delta and response.audio.delta ↔ response.output_audio.delta. See the Protocol Comparison section for the full mapping.The handshake fails outright. How do I debug it?
The handshake fails outright. How do I debug it?
wss://, not https://; 2. the endpoint includes ?model=<model-name>; 3. the Authorization: Bearer <key> header is present; 4. the key is enabled for the beta group (503 with “no available channel” if not); 5. no reverse proxy in between is stripping the Upgrade header — this is a common issue when relaying through your own gateway.Can I connect from the browser? Will my key leak?
Can I connect from the browser? Will my key leak?
Sec-WebSocket-Protocol subprotocol, so a browser WebSocket can connect directly. But that hands your key to the browser, where any visitor can read it from the network panel, so it is only suitable for local verification. In production write a backend relay: the backend holds the key and opens the connection to APIYI, and the frontend talks only to your own service.Sending 16 kHz audio to gpt-realtime-2.1 fails. Why?
Sending 16 kHz audio to gpt-realtime-2.1 fails. Why?
integer_below_min_value. The correct form is "audio": {"input": {"format": {"type": "audio/pcm", "rate": 24000}}}. The two Model Studio models require 16 kHz instead — the two are not interchangeable.I have no microphone / audio is hard to test. What now?
I have no microphone / audio is hard to test. What now?
say and afconvert — the commands are in that section.After sending response.cancel I never receive response.done.
After sending response.cancel I never receive response.done.
response.text.done, response.content_part.done and response.output_item.done, but response.done is not delivered. Use response.output_item.done as the end-of-turn signal and add a timeout as a backstop. The session itself is unaffected and the conversation continues normally. The two Realtime GA models behave correctly here.My connection drops after about 5 minutes.
My connection drops after about 5 minutes.
session.update, for instance), or accept the disconnect and reconnect automatically. Remember to replay session.update and any required context after reconnecting.How long can a single session stay open?
How long can a single session stay open?
session.created event carries expires_at, measured at roughly 30 minutes from connect, after which you need to reconnect. On the Model Studio protocol the constraint we mainly observed is the 300-second idle disconnect. Design long conversations on the assumption that sessions expire, and plan how context carries across sessions.How do I set the voice, and why does changing it return cannot_update_voice?
How do I set the voice, and why does changing it return cannot_update_voice?
session.update: top-level voice on Model Studio, audio.output.voice on Realtime GA. Once the session has produced audio output the voice can no longer be changed — this applies to both protocols and returns cannot_update_voice. Pin it in the first frame and open a new session to switch. Also, do not send an empty string as the voice on Model Studio; it returns 400.I get no input transcription in manual commit mode.
I get no input transcription in manual commit mode.
flash model on Model Studio does not deliver the transcription completion event in manual commit mode (reproduced consistently across runs); the plus model does, and both work in VAD mode. Switch to server_vad or semantic_vad. Testing shows the transcript text lands in an undocumented field on the delta events in this case, but that field may change at any time and should not be relied upon. Note this only affects displaying what the user said in your UI — the conversation is unaffected, and the model understands and answers the audio correctly.Is image input supported? Why do I get Error append image before append audio.?
Is image input supported? Why do I get Error append image before append audio.?
input_image directly in the message. On Model Studio images are treated as video frames, so audio must be appended before any image, which is what triggers that error. In testing the working approach is to interleave image frames into the audio stream at roughly one frame per second.Is there prompt caching? How do I confirm a hit?
Is there prompt caching? How do I confirm a hit?
usage.input_token_details.cached_tokens. No cache hits were observed on the two Model Studio models.How do I estimate cost? Are text and audio billed separately?
How do I estimate cost? Are text and audio billed separately?
usage object on response.done reports tokens per modality (text / audio / image, separately for input and output), so cost can be attributed. Audio tiers are substantially higher than text, which is why text-only is recommended during integration. For actual charges, refer to the call logs.