Connection Lifecycle

Connect → configure → stream audio → receive events → close/reconnect.

The full lifecycle of a realtime WebSocket connection.

Stages

1. Connect → 2. session.created → 3. Configure (optional) → 4. Stream audio
                                                           ↓
6. Close/Reconnect ← 5. Receive events ←

1. Connect

WebSocket handshake:

  • Server-side: Authorization: Bearer sk-... header
  • Browser: ?access_token=rt_... query parameter

Conditions checked on connect:

  • WebSocket upgrade required (else 426)
  • Gateway enabled (else 503 gateway_disabled)
  • Circuit breaker closed (else 503 upstream_unavailable + Retry-After)
  • Connection quota passes (concurrent + rate)

2. session.created

Received immediately on connect:

{
  "type": "session.created",
  "session_id": "sess_...",
  "limits": {
    "max_concurrent_utterances": 2,
    "max_session_seconds": 900,
    "idle_timeout_seconds": 60,
    "remaining_audio_seconds": 3600
  }
}

3. Configure (optional)

Send session.update to set parameters:

{ "type": "session.update", "language": "zh" }

Receive session.updated confirmation.

4. Stream audio

Continuously send PCM16LE audio frames:

  • Text frames: input_audio_buffer.append (base64)
  • Binary frames: raw PCM data
  • End of speech segment: input_audio_buffer.flush

5. Receive events

input_audio_buffer.speech_started
  → input_audio_buffer.speech_stopped
  → conversation.item.input_audio_transcription.completed

This cycle repeats for each speech segment.

6. Close / Reconnect

Normal close

Client calls ws.close(). Server flushes final meter data.

Timeout close

Close codeCause / close reasonTrigger
4408idle_timeoutNo audio received within idle_timeout_seconds
1008session_duration_limitExceeded max_session_seconds
1008session_audio_limitExceeded max_audio_seconds_per_session
1008audio_quota_exhaustedBilling-window audio budget exhausted
1009frame_too_largeSingle frame exceeds 1 MiB
1011client_error / internal errorClient socket error or unexpected gateway failure
1013upstream_unavailableCircuit breaker open
1013upstream_backpressureUpstream is not draining fast enough
1013client_backpressureClient is not reading events fast enough

Idle timeout

To avoid idle timeout, either:

  • Send silent frames to keep the connection alive
  • Or close explicitly and reconnect when needed
  1. Listen for close events, decide reconnect based on close code
  2. 4408 (idle) and 1008 (duration limit): reconnect directly
  3. 1013 (upstream): exponential backoff before reconnect
  4. 1000 (normal): do not reconnect
  5. After reconnect, re-send session.update to restore configuration

See Reconnect a Live Session for a detailed guide.