1. Threads
  2. Realtime Audio

​
Connect

wss://app.backboard.io/api/threads/realtime

Authenticate with the X-API-Key header. Send a JSON text frame containing the session configuration, then wait for session.begin before sending audio. Provider setup/history events can arrive before session.begin; keep reading until it arrives. API keys in query parameters are not accepted on this endpoint. For working clients, see the Python and Node.js guide.

{
  "provider": "openai",
  "model": "gpt-realtime-mini",
  "provider_options": {
    "audio": {"output": {"voice": "marin"}}
  },
  "memory": "off"
}

No separate assistant/thread creation request is needed. Omit both IDs to create a fresh conversation, send thread_id to continue one, or send only assistant_id to start a new thread under that assistant. session.begin returns both IDs. When both IDs are supplied, the thread takes precedence. This is the same ID lifecycle as POST /threads/messages, with a WebSocket for two-way audio. Choose a supported model from GET /models?model_type=realtime.

​
Session parameters

FieldValuesDefault / behavior
thread_idStringOptional. Existing conversation to continue.
assistant_idStringOptional. Without a thread ID, create a new thread under this assistant.
system_promptStringSession-only instructions. Omit/null inherits saved instructions; "" clears them.
toolsArraySession-only tool definitions. Omit/null inherits saved tools; [] clears them. Hosted tool selections below are added separately.
provideropenai, google, xaiRequired. Must match the selected model.
modelStringRequired. Realtime model name from the catalog.
provider_optionsObjectOptional native configuration; see examples below.
memoryoff, Readonly, Autooff. Search only, or search and save memories.
memory_prooff, Readonly, AutoOmit unless using PRO memory. When supplied, omit memory or set it to off.
web_searchoff, AutoOff unless enabled by the request or an assistant web-search tool. Explicit off disables it.
image_generationoff, autooff. Makes image generation available as a tool.
image_model_providerStringRequired when image generation is auto.
image_model_nameStringRequired when image generation is auto.
image_configObjectOptional settings supported by the selected image model; requires generation enabled.
video_generationoff, autooff. Makes video generation available as a tool.
video_model_provideropenrouterRequired when video generation is auto.
video_model_nameStringRequired when video generation is auto.
video_configObjectOptional settings supported by the selected video model; requires generation enabled.

Values are case-sensitive: memory and search use Auto; media generation uses auto. Tool selection applies to the session. Reconnect to apply a different selection. Session overrides are not saved to the assistant; re-pass them on later connections. Native instruction fields in provider_options take precedence over system_prompt.

​
Provider settings

Put native fields directly inside provider_options—do not add another session, setup, or provider-name wrapper. Supplied fields override defaults; unspecified nested fields retain their defaults. Settings must be supported by your selected model. provider_options cannot change the selected model.

  • OpenAI

  • Google

  • xAI

{
  "thread_id": "YOUR_THREAD_ID",
  "provider": "openai",
  "model": "gpt-realtime-mini",
  "provider_options": {
    "instructions": "Speak warmly and keep replies under two sentences.",
    "max_output_tokens": 1024,
    "audio": {
      "input": {
        "format": {"type": "audio/pcm", "rate": 24000},
        "turn_detection": {"type": "semantic_vad"},
        "transcription": {"model": "gpt-4o-mini-transcribe", "language": "en"}
      },
      "output": {
        "voice": "cedar",
        "speed": 1.1,
        "format": {"type": "audio/pcm", "rate": 24000}
      }
    }
  }
}

Defaults: voice marin, semantic voice activity detection, mono PCM16 at 24 kHz, and input transcription with gpt-4o-mini-transcribe.

Set audio.input.turn_detection.type to server_vad for silence-based turn detection. Set audio.input.turn_detection to null for manual turns. Output speed can be set from 0.25 to 1.5.

Other native controls include tool_choice, output_modalities, reasoning, truncation, and include. Support varies by model; consult the OpenAI Realtime reference.

Custom instructions override the assistant’s session instructions. Leave them unset to use the assistant configuration. Provider-native functions in tools are added alongside assistant and Backboard tools; they cannot replace an existing function with the same name. Provider-hosted tools and provider-stored prompts or resumed sessions may require a stored BYOK key. Prefer the Backboard tool parameters above for credit-funded sessions.

​
Transcription settings

OpenAI’s input transcription is optional and separately billed. To keep voice conversation but disable the saved user transcript:

{"audio": {"input": {"transcription": null}}}

Use that object as provider_options. Alternatively, change the transcription model or language in audio.input.transcription. Input transcription does not route the spoken conversation through a text model. See history and transcripts.

​
Audio and events

session.begin includes session_id, thread_id, input_format, and output_format:

{
  "type": "session.begin",
  "session_id": "SESSION_ID",
  "thread_id": "THREAD_ID",
  "assistant_id": "ASSISTANT_ID",
  "input_format": {"encoding": "pcm16", "sample_rate": 24000, "channels": 1},
  "output_format": {"encoding": "pcm16", "sample_rate": 24000, "channels": 1}
}

Send audio as binary frames matching input_format. For PCM16, use signed 16-bit little-endian samples, not a WAV/MP3 file. Output audio.delta.data is base64-encoded audio; decode it and play using the event’s format. Receive events while sending microphone frames rather than waiting for the microphone to finish.

Format fields on each audio event are flat:

{"type":"audio.delta","data":"BASE64_AUDIO_BYTES","item_id":"reply-1","encoding":"pcm16","sample_rate":24000,"channels":1}

BASE64_AUDIO_BYTES is a placeholder. Use real decoded bytes for playback. Raw provider.event messages can describe the same audio; do not play both copies.

​
Client events

EventExample / action
Text input{"type":"text","text":"Hello"}
End a manual audio turn{"type":"commit"}; automatic VAD does not need this.
Cancel output{"type":"cancel"}; OpenAI/xAI only. Clear local playback too.
Return custom tool results{"type":"tool.outputs","outputs":[{"tool_call_id":"CALL_ID","name":"lookup","output":{"answer":"Found it"}}]}
Native provider event{"type":"provider.event","event":{...}}
Finish the session{"type":"stop"}; continue receiving until session.ended or an error.

​
Received events

EventWhat to do
session.beginRead negotiated formats and start sending audio.
audio.deltaDecode data from base64 and play incrementally.
transcript.startedA user transcript is pending.
transcript.delta / transcript.finalRead text, role, and item_id.
transcript.failedA spoken turn could not be transcribed.
tool.callRead name, arguments, and tool_call_id. Execute only when hosted is false.
tool.cancelledCancel client work for the listed tool_call_ids.
tool.completedBackboard finished handling a hosted call. This event alone does not prove success or contain the result.
media.generatedDisplay or download the attachments in generated_media.
response.doneOne response completed; not the end of the session.
interruptedDiscard queued assistant audio so the user can interrupt.
provider.eventInspect the original provider message in event.
session.endedGraceful stop completed. Optional billing reports provider_cost_usd, charged_usd, and reconciliation_required.
errorRead code and message; handle the failure before reconnecting.

Gemini Extended Thinking can produce multiple utterances in one interaction. Do not stop on its first response.done; use provider.event.event.serverContent.interactionStatus === "IDLE" when you need to detect the end of that interaction.

​
Custom tool results

Run only tool.call events with hosted: false. Validate the function and its arguments, then return tool.outputs on this socket. Each result must match a pending tool_call_id and its exact name. Return one result per call; a batch can contain up to 32. Do not return hosted, cancelled, duplicate, or already completed calls. Client-run tools do not get a tool.completed acknowledgement.

This is not the REST tool-output protocol. See the complete tool round trip and SDK handlers.

​
Graceful stop

stop does not commit buffered input or wait for every tool. It allows a bounded wait for late transcripts and usage before finalization. Keep receiving until session.ended or failure; handle history_incomplete and billing_pending errors. Paid image/video work can continue and save results after disconnect.

​
Change settings during a session

Use provider.event for updates supported by the provider. For example, update OpenAI instructions without reconnecting:

{
  "type": "provider.event",
  "event": {
    "type": "session.update",
    "session": {"instructions": "Keep answers to one sentence."}
  }
}

Not every setting is mutable after connection. Reconnect to change the provider, model, or Backboard tool selection. Provider errors identify invalid settings.

​
Limits and reconnecting

  • Each client frame may be at most 256 KiB. Stream small audio chunks.
  • Send the initial configuration within 30 seconds of opening the connection.
  • Sessions last up to 30 minutes and accept up to 100 MiB of client input.
  • A connection with no client audio or events for 120 seconds times out. Silence while microphone frames continue arriving is not inactivity.
  • One native realtime session may write to a thread at a time. Finish it before reconnecting.
  • History is limited to 200 messages after any saved summary and 200,000 characters of serialized history plus assistant instructions. Exceeding these limits rejects setup; it does not silently truncate the conversation.

On a disconnect, reconnect with the same thread_id to continue from saved history. There is no automatic reconnect or replay of unsaved microphone audio. Increasing an SDK connection timeout does not change these session limits.

​
Browser connections

Do not expose a long-lived API key in browser code. Obtain a single-use ticket through a trusted application endpoint that authenticates and authorizes the user:

curl -X POST https://app.backboard.io/api/threads/realtime/tickets \
  -H "X-API-Key: $BACKBOARD_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{}'

Use {} to auto-create a conversation, {"assistant_id":"YOUR_ASSISTANT_ID"} for a new thread under an existing assistant, or {"thread_id":"YOUR_THREAD_ID"} to continue a conversation. The response includes ticket, expires_in (60 seconds), websocket_path, thread_id, and assistant_id. Connect the browser to wss://app.backboard.io/api/threads/realtime?ticket=URL_ENCODED_TICKET, then send the same setup frame. Each ticket can be used once. Browser clients supply their own microphone capture and audio playback. The socket may omit thread_id when using a ticket: it uses the ticket’s resolved thread. A ticket cannot create or switch to a different conversation. The Chat dashboard may instead supply chat_thread_id when requesting a ticket; do not combine it with the public thread or assistant identifiers. The ticket is bound to the thread and, when present, the Origin header on the ticket request. A backend issuing tickets should deliberately choose the intended browser origin. websocket_path excludes the deployment’s /api prefix.