OpenAI Realtime GA migration: drop the OpenAI-Beta header
Beta Realtime integrations must move to GA and stop sending OpenAI-Beta: realtime=v1. A short checklist, a code scan for the header, and where Sume jobs fit.

If your realtime voice code still sends the header OpenAI-Beta: realtime=v1, it is a beta integration. OpenAI's Realtime guide says beta integrations must migrate to the GA interface and drop that header.
This page is the checklist: what the guide asks for, a script that finds every place the header is set, and the one boundary to keep in mind if the voice session also triggers Sume generation jobs.
What the guide asks for
Four facts from the guide, as read on 2026-10-03. Nothing here is inferred beyond that page.
| Topic | What the guide says |
|---|---|
| Beta integrations | Must migrate to GA |
| Beta header | Drop OpenAI-Beta: realtime=v1 |
| Transport in a browser | Connect with WebRTC |
| Transport on a server | Connect with WebSocket |
| Safety header | Send OpenAI-Safety-Identifier |
Find every place the header is set
The header tends to live in more than one place: a server proxy, a test harness, a mobile client, a sample copied into docs. A plain text scan is enough to list them. This script walks a directory and prints each file and line that mentions the beta value.
import os
import sys
NEEDLE = "realtime=v1"
SKIP_DIRS = {".git", "node_modules", ".venv", "dist", "build"}
def scan(root):
hits = []
for folder, dirs, files in os.walk(root):
dirs[:] = [d for d in dirs if d not in SKIP_DIRS]
for name in files:
path = os.path.join(folder, name)
try:
with open(path, encoding="utf-8") as handle:
for number, line in enumerate(handle, 1):
if NEEDLE in line:
hits.append((path, number, line.strip()))
except (UnicodeDecodeError, OSError):
continue
return hits
if __name__ == "__main__":
root = sys.argv[1] if len(sys.argv) > 1 else "."
for path, number, line in scan(root):
print(f"{path}:{number}: {line}")Order of work
Do the migration in small steps so a regression is easy to place.
- List every client that opens a realtime session, and mark each as browser or server. The guide's transport rule follows that split: WebRTC in the browser, WebSocket on the server.
- Remove the beta header from one client at a time, starting with the server path, and run a short call end to end before moving on.
- Add
OpenAI-Safety-Identifierto the requests that open sessions, so the value is present from the first GA call rather than added later. - Delete the beta references from your own docs and examples, so the next teammate does not copy them back in.
Where Sume jobs fit
A realtime session is a live connection. Sume generation is not: the Developer API has no SSE or WebSocket transport, and the jobs docs say GET /v1/jobs/:id/events is a pull snapshot, not a stream. A voice assistant that decides to render an image or a clip should start the job from its server, then poll the status URL or take a webhook for the terminal event.
That server is also where the Sume key belongs. The authentication docs say browser clients should call your backend, and your backend attaches the key. The same split keeps a browser WebRTC session from ever holding a Sume credential.
Sources
Related posts
More in Developers
- OpenAI TTS: 13 built-in voices vs 9 legacy ones, pick the model first
OpenAI's guide lists gpt-4o-mini-tts with 13 built-in voices and legacy tts-1 and tts-1-hd with 9. Formats, custom voice consent and disclosure, as a checklist.
- OpenTelemetry spans for MCP tools: tag the Sume request_id
Claude Code v2.1.283 adds MCP tool outputs to OpenTelemetry spans. Put the Sume request_id on the span and keep signed URLs off it.
- Parallel tool calls: fan out Sume renders, wait once
ElevenAgents can run multiple tools in one turn. On Sume's hosted MCP, submit several jobs, then wait on all of them with one jobs_wait call of up to 20 ids.
- Pause between narration lines: TTS pause markers or audio concat?
Deepgram Flux TTS allows pause markers of 500 to 3000 ms, max 8 per request. Sume's timeline audio concat joins lines with no gap. Where to put the pause.
Written by Sume