Realtime API over SIP: calls always terminated at ~30.16s, sideband WebSocket never receives a single event

Project: proj_sVhrExIViP1giTNZfiRfOKYT
Setup: FreeSWITCH SIP trunk (via a European VoIP provider) bridging inbound calls to sip:proj_sVhrExIViP1giTNZfiRfOKYT@sip.api.openai.com``;transport=tls. Webhook realtime.call.incoming → our backend, which calls accept and opens the sideband WebSocket at wss://api.openai.com/v1/realtime?call_id={call_id}.

Symptom: Every inbound call is cut off after exactly the same duration, regardless of what we change. Caller hears one ring tone, then silence, then the call is torn down.

Reproduced across 5 consecutive real test calls, isolating one variable at a time:

Test Webhook delivered? Sideband WS Proactive response.create sent? Caller spoke? Call duration (Answer → Hangup)
#2 Yes (200 OK) ConnectionClosedError No No ~30s
#3 No (webhook never arrived) N/A No No 30.0s (clean NORMAL_CLEARING)
#4 Yes (200 OK) ConnectionClosedError No No 30.16s
#5 Yes (200 OK) ConnectionClosedError Yes Yes, actively 30.16s — identical

The call duration is essentially invariant (30.0–30.16s) no matter whether the webhook arrives, whether the sideband WS is attempted, whether we proactively call response.create, or whether the caller speaks. This rules out “AI never greets, so nobody talks” and any client-side inactivity timeout as the cause.

Precise timeline for test #5 (all timestamps UTC, from docker logs -t):

  • 12:04:36.55 — webhook realtime.call.incoming received, we return 200 OK
  • 12:04:37.15 — FreeSWITCH: call answered, RINGING → ACTIVE
  • 12:05:07.31 — FreeSWITCH: Hangup, cause NORMAL_CLEARING (30.16s after answer)
  • 12:05:09.92 — our backend logs websockets.exceptions.ConnectionClosedError: no close frame received or sent on the sideband WS — 2.6 seconds after the SIP call was already torn down

So the sideband ConnectionClosedError is a downstream symptom of the SIP teardown, not its cause — FreeSWITCH/OpenAI’s SIP leg ends first, and our WS read loop only notices the dead connection ~2.6s later.

Sideband WebSocket receives zero events, ever. We instrumented every branch of our event-dispatch loop (transcript events, tool-call events, error events — each logged distinctly). Across the entire ~30s lifetime of the sideband connection in every test, we logged not a single incoming event — no session.updated acknowledging our session.update, no error event, nothing. The only traffic on that connection is the session.update we send outbound. websockets.connect() itself succeeds without error (so auth/TLS/URL are fine — we’re using the documented wss://api.openai.com/v1/realtime?call_id=... pattern with a valid Authorization: Bearer header), but the connection is then completely silent until it’s killed.

Question: Is there a known ~30-second server-side timeout for the SIP call setup handshake (accept → sideband connect → session configuration) that fires when the session isn’t considered “ready” in time? If so, what determines readiness, and why would our sideband connection never receive any event at all — not even a rejection or error — if something about our session setup were wrong?

This matches reports in the “Realtime API unreliable over SIP” thread (including “model stopping responses after 30 seconds over SIP”), but we wanted to share a fully instrumented, reproducible timeline in case it helps narrow down the root cause. Happy to share full logs or call IDs on request.

Call IDs available on request (format rtc_...), captured for all 5 tests above.