25 25
26Use a [sideband connection](https://developers.openai.com/api/docs/guides/voice-server-controls?api=live) when your backend needs to receive session events or send commands. It attaches to the existing conversation while SIP carries the audio. Assign one handler to each action so that duplicate webhook deliveries or events observed on multiple connections don't execute tools twice.26Use a [sideband connection](https://developers.openai.com/api/docs/guides/voice-server-controls?api=live) when your backend needs to receive session events or send commands. It attaches to the existing conversation while SIP carries the audio. Assign one handler to each action so that duplicate webhook deliveries or events observed on multiple connections don't execute tools twice.
27 27
28### Handle the call lifecycle28### Handle an inbound call
29 29
30Confirm that GPT-Live SIP support is enabled for your project and that your30Confirm that GPT-Live SIP support is enabled for your project and that your
31 provider's SIP trunk is routed to that project before using this flow.31 provider's SIP trunk is routed to that project before using this flow.
76 76
77Keep the sideband open until `session.closed` supplies final usage, then release application resources. If the connection drops first, record finalization as incomplete. See [Usage and graceful close](https://developers.openai.com/api/docs/guides/live-conversations#usage-and-graceful-close) for finalization and close reasons.77Keep the sideband open until `session.closed` supplies final usage, then release application resources. If the connection drops first, record finalization as incomplete. See [Usage and graceful close](https://developers.openai.com/api/docs/guides/live-conversations#usage-and-graceful-close) for finalization and close reasons.
78 78
79This flow accepts inbound calls. Creating an outbound SIP call through `POST /v1/live/sessions` is not supported; use the relevant [partner integration](https://developers.openai.com/api/docs/guides/live-partner-integrations) for provider-owned outbound calling.79### Place an outbound call
80
81Call a phone number through your SIP provider with [Create session](https://developers.openai.com/api/reference/resources/live/methods/create). Your provider handles the phone network connection while GPT-Live carries the conversation.
82
83Outbound SIP calling must be enabled for your organization. It is available
84 through the Live API, not the Realtime API call-creation endpoint.
85
86#### Configure your trunk
87
88Use a trunk that supports TLS signaling, Opus audio, and SDES-SRTP media. Enable Opus and SRTP in your provider's settings before placing a call.
89
90Supply the trunk configuration with each request:
91
92| Field | Value |
93| ------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
94| `transport.destination` | The phone number to call, in E.164 format, such as `+14155550123`. SIP URI destinations aren't supported. |
95| `transport.trunk.provider_url` | A provider endpoint such as `sips:sip.example.com:5061`. The default port is `5061`; `;transport=tcp` is optional. |
96| `transport.trunk.auth.type` | `digest` for SIP Digest authentication. |
97| `transport.trunk.auth.username` | Your provider's SIP username. |
98| `transport.trunk.auth.password` | Your provider's SIP password. |
99| `transport.trunk.caller_number` | The caller phone number to send to your provider, in E.164 format. |
100
101The provider endpoint must use `sips:` for TLS signaling. Don't include credentials, paths, URI headers, or other URI parameters in the URL. Local hostnames and literal private or local IP addresses are rejected. Keep your OpenAI API key and SIP credentials on your server.
102
103#### Create the session
104
105Send `POST /v1/live/sessions` with your session configuration and `transport.type: "sip"`. Choose the voice and delegation mode when creating the session. Omit `audio.format` because SIP negotiates the audio format.
106
107This example uses `curl` and `jq`. Set `OPENAI_API_KEY`, `SIP_USERNAME`, and `SIP_PASSWORD` in your server environment, and replace the example provider endpoint and phone numbers with your own values. The example selects client delegation; your backend must handle [delegated work](https://developers.openai.com/api/docs/guides/live-delegation).
108
109```bash
110jq -n \
111 --arg username "$SIP_USERNAME" \
112 --arg password "$SIP_PASSWORD" \
113 '{
114 "session": {
115 "model": "gpt-live-1",
116 "instructions": "Help the user schedule an appointment.",
117 "audio": { "output": { "voice": "marin" } },
118 "delegation": { "type": "client" }
119 },
120 "transport": {
121 "type": "sip",
122 "destination": "+14155550123",
123 "trunk": {
124 "provider_url": "sips:sip.example.com:5061",
125 "auth": {
126 "type": "digest",
127 "username": $username,
128 "password": $password
129 },
130 "caller_number": "+14155550100"
131 }
132 }
133 }' | curl https://api.openai.com/v1/live/sessions \
134 -H "Authorization: Bearer $OPENAI_API_KEY" \
135 -H "Content-Type: application/json" \
136 --data-binary @-
137```
138
139The request returns `200 OK` after the session initializes:
140
141```json
142{
143 "session": { "id": "live_123" },
144 "transport": { "type": "sip" }
145}
146```
147
148This response doesn't mean the call has been answered. It contains no SDP or trunk credentials. Preserve `session.id` unchanged for the sideband connection and call controls. You don't need an incoming-call webhook or an accept request for an outbound call.
149
150#### Monitor and end the call
151
152Attach your backend to `wss://api.openai.com/v1/live/sessions/{session_id}/attach` using your OpenAI API key. Don't send `session.start` again. The [sideband connection](https://developers.openai.com/api/docs/guides/voice-server-controls?api=live) carries conversation events, delegated work, and call progress while SIP carries the audio.
153
154| Event | Meaning |
155| -------------------- | ----------------------------------------------------------------------------------------- |
156| `transport.ringing` | The provider reports ringing or early media. |
157| `transport.answered` | The call has been answered and media is established. |
158| `transport.failed` | Call setup failed after session initialization. Inspect `error.code` and `error.message`. |
159
160Each call-progress event includes `event_id` and `session_id`. Attach immediately after creation: the sideband only replays events from the preceding 3 seconds, so a later attachment can miss earlier call progress. Replayed events retain their original event IDs. Deduplicate events by `event_id`.
161
162Use the same [transfer](#transfer-or-end-the-call) and [hangup](https://developers.openai.com/api/reference/resources/live/subresources/sessions/methods/hangup) actions as for inbound calls. Keep the sideband open for `session.closed` and final usage as described in [Usage and graceful close](https://developers.openai.com/api/docs/guides/live-conversations#usage-and-graceful-close).
163
164#### Handle limits and errors
165
166Outbound SIP requests have a 1 MiB body limit. Ringing is limited to 3 minutes, and a connected call is limited to 2 hours. These limits aren't configurable in the creation request.
167
168A `403` response with `outbound_sip_not_enabled` means outbound calling isn't enabled for your organization. Invalid session configuration is returned on the creation request. Transport setup failures can return `502`, and initialization timeouts return `504`. After creation succeeds, monitor `transport.failed` for asynchronous setup failures.
169
170Each creation request places a new call. `X-Client-Request-Id` doesn't
171 deduplicate requests. Don't automatically retry after an ambiguous timeout or
172 connection failure: a retry can place another call.
80 173
81### Server audio bridges174### Server audio bridges
82 175