OpenAI Realtime API SIP REFER Endpoint Returns 500 Internal Server Error
Issue Summary
I’m implementing call screening using OpenAI’s Realtime API with SIP integration. The call acceptance, WebSocket monitoring, AI conversation, and tool calling all work perfectly. However, when attempting to transfer an approved call using the /v1/realtime/calls/{call_id}/refer
endpoint, I consistently receive a 500 Internal Server Error
.
Architecture Overview
- SIP Provider: SignalWire (example-domain.signalwire.com)
- Proxy: Kamailio (creates SIP B-leg to OpenAI)
- Monitoring: Voice API server monitors via WebSocket
- Flow: Caller → Kamailio → OpenAI SIP → AI Screening → REFER transfer to user’s phone
Working Components 
- Call acceptance via
POST /v1/realtime/calls/{call_id}/accept
- Works - WebSocket connection to
wss://api.openai.com/v1/realtime?model=gpt-realtime&call_id={call_id}
- Works - AI conversation with caller - Works
- Tool calling with
make_screening_decision
function - Works perfectly (AI decides ALLOW/REJECT)
The Problem 
When the AI decides to ALLOW the call, we attempt to transfer it using REFER, but OpenAI returns 500 Internal Server Error.
Accept Endpoint Configuration
const response = await axios.post(
`https://api.openai.com/v1/realtime/calls/${callId}/accept`,
{
type: 'realtime',
model: 'gpt-realtime',
instructions: 'You are a friendly call screening assistant...',
tools: [
{
type: 'function',
name: 'make_screening_decision',
description: 'Make final screening decision after gathering information from caller',
parameters: {
type: 'object',
properties: {
decision: { type: 'string', enum: ['ALLOW', 'REJECT', 'VOICEMAIL'] },
reason: { type: 'string' }
},
required: ['decision', 'reason']
}
}
],
tool_choice: 'auto'
}
);
REFER Request (Currently Failing)
const referPayload = {
target_uri: "sip:+14155551234@example-domain.signalwire.com"
};
const referResponse = await axios.post(
`https://api.openai.com/v1/realtime/calls/${callId}/refer`,
referPayload,
{
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json',
'OpenAI-Project': 'proj_XXXXXXXXXXXXX'
},
timeout: 10000
}
);
Error Response
Status: 500 Internal Server Error
Response: "Internal Server Error"
x-envoy-upstream-service-time: 367ms
The request reaches OpenAI’s servers (processes for ~367-390ms) but fails with a generic 500 error.
What We’ve Tried
1. Different URI Formats
tel:+14155551234
→ 500 errorsip:+14155551234@example-domain.signalwire.com
→ 500 error
2. WebSocket Timing
Closing WebSocket before REFER → 500 error
Keeping WebSocket open during REFER → 500 error
3. Request Validation
Request structure matches documentation
Headers are correct (Authorization, Content-Type, OpenAI-Project)
Call ID is valid (same ID used successfully for accept/WebSocket)
Payload is valid JSON
Request Details from Logs
POST /v1/realtime/calls/rtc_XXXXXXXXXXXXXXXXXXXX/refer HTTP/1.1
Accept: application/json, text/plain, */*
Content-Type: application/json
Authorization: Bearer sk-proj-[REDACTED]
OpenAI-Project: proj_XXXXXXXXXXXXX
Content-Length: 59
Host: api.openai.com
{"target_uri":"sip:+14155551234@example-domain.signalwire.com"}
Questions
-
Is REFER supported for SIP calls accepted through the REST API? The documentation mentions REFER for transferring calls, but all examples show browser-based WebRTC.
-
What URI format should
target_uri
use for PSTN numbers? Should it be:tel:+14155551234
sip:+14155551234@domain.com
sip:14155551234@domain.com
(without +)- Something else?
-
Are there any state requirements? Does the call need to be in a specific state before REFER? Should we:
- Close the WebSocket first?
- Wait for a specific event?
- Send a session.update before REFER?
-
Is there any logging available? The 500 error is generic - is there a way to get more detailed error information about why the REFER is being rejected?
Additional Context
- Call ID format:
rtc_XXXXXXXXXXXXXXXXXXXX
- WebSocket events show successful tool calling:
response.function_call_arguments.done Screening decision: ALLOW - [example reason]
- After REFER fails, we successfully call
/hangup
endpoint (works fine)
Expected Behavior
REFER request should succeed and transfer the call to the specified target_uri
, keeping the PSTN call leg alive.
Actual Behavior
REFER request consistently returns 500 Internal Server Error
with no additional error details.
Any insights on what might be causing this or what we should try next would be greatly appreciated! Is REFER even supported for SIP calls in the current implementation?