Skip to Content
Realtime Audio

Realtime Audio Conversations

PickLayer provides a multi-provider realtime audio conversation API that mirrors OpenAI’s Realtime API event format. The system acts as a thin normalization layer, translating between the canonical format and each provider’s native WebSocket protocol.

Supported Providers

  • OpenAI: openai/gpt-4o-realtime-preview-* models
  • Google Gemini: gemini/gemini-2.0-flash-exp and other Live API models
  • xAI (Grok): xai/grok-* models (experimental)

Connection Protocols

PickLayer supports two connection protocols:

Native WebSocket (OpenAI SDK compatible)

wss://{HOST}/v1/realtime

Connect using standard WebSocket with Authorization: Bearer {token} header. This endpoint is compatible with the OpenAI Realtime SDK.

Socket.IO (enhanced features)

wss://{HOST}/v1/realtime-socketio

Connect using Socket.IO client with token in auth/query params. Supports automatic reconnection and room-based session management.

Query Parameters

Both protocols accept the following query parameters:

ParameterDescription
token or authTokenBearer JWT
org / organizationIdOrganization identifier
app / applicationIdApplication identifier
envEnvironment (default: prod)
modelProvider-prefixed model (e.g., openai/gpt-4o-realtime-preview-2024-12-17)
sessionId / session_idFor reconnection to existing sessions
voiceVoice selection (e.g., alloy, echo, nova)
modalitiesComma-separated: text,audio
instructionsSystem prompt

Turn Detection (VAD) Parameters

ParameterDescription
turn_detection_typeserver_vad (default) or semantic_vad
vad_thresholdActivation threshold 0-1 (default: 0.5)
silence_duration_msSilence duration to detect speech stop (default: 500)
create_responseAuto-respond when speech stops: true (default) or false
interrupt_responseAllow interrupting model audio: true (default) or false

Session Lifecycle

  1. Connect → session.created event with session configuration
  2. Exchange audio/text via canonical events
  3. Disconnect triggers billing finalization
  4. Reconnection supported via sessionId within TTL (90s default)

Event Format (OpenAI GA API)

Client → Server Events

EventDescription
input_audio_buffer.appendStream audio: { type: "input_audio_buffer.append", audio: "<base64>" }
input_audio_buffer.commitCommit audio buffer
input_audio_buffer.clearClear uncommitted audio
conversation.item.createAdd text/audio items
response.createRequest a response
session.updateUpdate session config

Server → Client Events

EventDescription
session.createdSession initialized
session.updatedConfig changes applied
conversation.item.createdNew conversation item
conversation.item.input_audio_transcription.completedUser speech transcription
response.createdResponse started
response.output_audio.deltaAudio chunk: { delta: "<base64>" }
response.output_audio.doneAudio stream complete
response.output_audio_transcript.deltaModel speech transcript chunk
response.output_audio_transcript.doneModel speech transcript complete
response.text.deltaText response chunk
response.doneResponse complete with usage
errorError details
warningNon-fatal warnings (e.g., unsupported parameters)

Session Configuration

Important: output_modalities only supports ["text"] OR ["audio"], not both together. For voice conversations, use ["audio"] - transcripts still come via response.output_audio_transcript.delta events.

{ "type": "session.created", "session": { "id": "<session-id>", "object": "realtime.session", "model": "gpt-4o-realtime-preview-2024-12-17", "output_modalities": ["audio"], "instructions": "...", "audio": { "input": { "format": { "type": "audio/pcm", "rate": 24000 }, "transcription": { "model": "whisper-1" }, "turn_detection": { "type": "server_vad", "threshold": 0.5, "silence_duration_ms": 500, "create_response": true, "interrupt_response": true } }, "output": { "format": { "type": "audio/pcm", "rate": 24000 }, "voice": "alloy" } } } }

Audio Format

  • Default: PCM16 (16-bit, 24kHz, mono)
  • Configurable via input_audio_format / output_audio_format

Legacy Events (backwards compatibility)

Legacy EventCanonical Equivalent
input_text { text }conversation.item.create
input_audio { data|audio }input_audio_buffer.append + commit

Billing

  • Reserve on connect (estimated 5 minutes)
  • Finalize on session expiry with actual usage
  • Meters: audio seconds in/out, text tokens in/out, session duration
  • Guard actions: guard.realtime-reserve / guard.realtime-finalize

Example: Native WebSocket (JavaScript)

// Native WebSocket - works with OpenAI SDK const ws = new WebSocket( "wss://api.picklayer.dev/v1/realtime?model=openai/gpt-4o-realtime-preview-2024-12-17&voice=alloy", { headers: { "Authorization": "Bearer <JWT>" } } ); ws.onmessage = (event) => { const data = JSON.parse(event.data); switch (data.type) { case "session.created": console.log("Session ready:", data.session.id); break; case "response.output_audio.delta": playAudio(data.delta); // base64 PCM16 break; case "response.done": console.log("Usage:", data.response.usage); break; } }; // Send audio ws.send(JSON.stringify({ type: "input_audio_buffer.append", audio: audioBase64 })); ws.send(JSON.stringify({ type: "input_audio_buffer.commit" }));

Example: Socket.IO (JavaScript)

import { io } from "socket.io-client"; const socket = io("wss://api.picklayer.dev", { path: "/socket.io", auth: { token: "<JWT>", org: "acme", app: "voice-assistant", model: "openai/gpt-4o-realtime-preview-2024-12-17", voice: "alloy", modalities: "text,audio" } }); // Connect to the realtime namespace socket.on("connect", () => { socket.emit("join", "/v1/realtime-socketio"); }); socket.on("session.created", (data) => { console.log("Session ready:", data.session.id); }); socket.on("response.output_audio.delta", (data) => { playAudio(data.delta); });

Example: Python SDK

from picklayer import PickLayerClient from picklayer.realtime import RealtimeSession, RealtimeSessionConfig client = PickLayerClient("org", "app") client.set_token(access_token) config = RealtimeSessionConfig( model="openai/gpt-4o-realtime-preview-2024-12-17", voice="alloy", ) # Native WebSocket (OpenAI compatible) session = RealtimeSession(client, config, protocol="websocket") # Or Socket.IO (enhanced features) # session = RealtimeSession(client, config, protocol="socketio") @session.on("response.output_audio.delta") def handle_audio(event): play_audio(event.delta) session.connect() session.send_audio(audio_base64) session.disconnect()

Live Transcription

PickLayer also supports live streaming speech-to-text over the realtime endpoints. Use transcription models instead of conversation models.

Supported Transcription Models

  • openai/gpt-4o-mini-transcribe
  • openai/gpt-4o-transcribe

Transcription Mode Behavior

  • Session type is transcription (not realtime)
  • Output is text-only (output_modalities: ["text"])
  • No audio output config is sent (no voice, no output audio format)
  • Primary events:
    • conversation.item.input_audio_transcription.delta
    • conversation.item.input_audio_transcription.completed
  • Billing uses audio_stt per-second rates (guard.audio-stt-reserve / guard.audio-stt-finalize)

Transcription Query Parameters

ParameterDescription
languageISO-639-1 hint (e.g., en, es, ja)
noise_reductionnear_field or far_field

Example: Native WebSocket (JavaScript)

const ws = new WebSocket( "wss://api.picklayer.dev/v1/realtime?model=openai/gpt-4o-mini-transcribe&language=en", { headers: { Authorization: "Bearer <JWT>" } } ); ws.onmessage = (event) => { const data = JSON.parse(event.data); if (data.type === "conversation.item.input_audio_transcription.delta") { process.stdout.write(data.delta); } if (data.type === "conversation.item.input_audio_transcription.completed") { console.log("\nFinal:", data.transcript); } }; ws.send(JSON.stringify({ type: "input_audio_buffer.append", audio: audioBase64 })); ws.send(JSON.stringify({ type: "input_audio_buffer.commit" }));

Example: Socket.IO (JavaScript)

import { io } from "socket.io-client"; const socket = io("wss://api.picklayer.dev", { path: "/socket.io", auth: { token: "<JWT>", model: "openai/gpt-4o-mini-transcribe", modalities: "text", language: "en", }, }); socket.on("event", (event) => { if (event.type === "conversation.item.input_audio_transcription.delta") { process.stdout.write(event.delta); } if (event.type === "conversation.item.input_audio_transcription.completed") { console.log("\nFinal:", event.transcript); } }); socket.emit("event", { type: "input_audio_buffer.append", audio: audioBase64 }); socket.emit("event", { type: "input_audio_buffer.commit" });

Example: Python SDK

from picklayer.realtime import RealtimeSession, RealtimeSessionConfig config = RealtimeSessionConfig.transcription( model="openai/gpt-4o-mini-transcribe", language="en", ) session = RealtimeSession(client, config) @session.on("conversation.item.input_audio_transcription.delta") def on_transcript_delta(event): print(event.delta, end="", flush=True) @session.on("conversation.item.input_audio_transcription.completed") def on_transcript_done(event): print("\nFinal:", event.transcript) session.connect() session.send_audio(audio_base64) session.disconnect()

Provider Translation

ProviderBehavior
OpenAIPassthrough (canonical format)
GeminiTranslates to/from Gemini Live API format (realtimeInput.mediaChunks, serverContent.modelTurn, etc.)
xAIOpenAI-compatible with voice mapping (alloy→Ara, echo→Rex, etc.)

Error Handling

  • error events include type, code, message
  • Unsupported provider features emit warning events with unsupported_options array
Last updated on