How can I programatically end a gpt-realtime SIP call?

Problem and Question

After experimenting with OpenAI’s new GPT Realtime SIP feature (GA as of a day or two ago), I ran into a situation where I wanted to allow the agent to end the call after it said goodbye. I added a function call tool for hanging up, and while that gets invoked, I haven’t found a way to actually terminate the call.

I found some older posts about ending calls programmatically, but they focused on detecting when to end the call or vendor-specific solutions for ending the call, rather than terminating SIP calls handled directly by OpenAI’s new SIP feature.

Is there some way of programmatically ending SIP calls that were answered by OpenAI? If not, it seems like this would be a reasonable feature request.

My Setup

  • My incoming calls are routed to OpenAI by Twilio Elastic SIP Trunking (not Programmable Voice).

  • My OpenAI webhook is configured to accept calls immediately in response to realtime.call.incoming events.

  • My agent is configured with an end_call function tool that the agent can choose to invoke when appropriate.

Attempted Solutions

1. Twilio REST API

I tried using Twilio’s REST API to mark calls as completed (as suggested here), but calls don’t seem to exist within the REST API until after they’ve ended. I assume this is a limitation of using Elastic SIP Trunking instead of Programmable Voice, but I’d prefer to stay on Elastic SIP Trunking since it has lower per-minute rates, doesn’t charge for SIP REFERs, and seems to be simpler to integrate overall.

2. OpenAI Realtime Reject Endpoint

I attempted to use the v1/realtime/calls/{CallId}/reject endpoint, but couldn’t figure that out.

I’m unclear on whether it wasn’t working due to the call already being accepted, or whether I was sending a malformed request or using the incorrect HTTP method. (Documentation is super sparse on this endpoint.)

3. WebSocket Closure

Closing the WebSocket connection doesn’t terminate the SIP call.

Potential Workaround

As a workaround, I could potentially SIP REFER the call to an endpoint that immediately answers and sends a BYE, but this feels like an unnecessary hack when there should be a cleaner solution for basic call termination. (And admittedly, I’m not that great with SIP and have struggled getting a basic Asterisk server running.)

2 Likes

hi, thanks for trying the API! You can use v1/realtime/calls/{CallId}/hangup to programmatically end the call.

4 Likes

Thanks for this. I tried it and I get a 404. I cannot find the documentation for that endpoint anywhere. Here is the code I have:

resp = requests.post( “apiopenaicom/v1/realtime/calls/” + call_id + “/hangup”, headers={**AUTH_HEADER, “Content-Type”: “application/json”}, )

Could you please point to the API documentation?

Thanks!

I tried the endpoint and it works fine for me. Is it possible you’re using the wrong call_id?

how did you pass the tool to the model?When I add “tools” to call_accept, server rejects.

call_accept = {
    "type": "realtime",
    "tools":[{
    "type": "function",
    "name": "end_call",
    "description": "if user asks you to end the call.Call this tool.",
    "parameters": {
        "type": "object",
        "properties": {
            "reason": {
                "type": "string",
                "description": "Reason why the call is ending, e.g. 'User declined appointment', 'Already has a provider', etc."
            }
        },
        "required": ["reason"],
        "additionalProperties": False,
    },
    "strict": True,
},

],
    "instructions": f"""MY-LONG-LONG-PROMPT """,
    "model": "gpt-realtime",
}

I use openai’s SIP example too.

Error:

WebSocket error: server rejected WebSocket connection: HTTP 404

When I remove the tools, it works.

Thanks Ryan, you solved my problem

You can either:
1.) add a hangup funciton.
2.) add a situational analysis loop.
3.) button.

I think this key is wrong. We’ll improve the debugging info here.

2 Likes