Voice AI That Speaks Carrier-Grade SIP | SignalWire
Enterprise Telephony for Voice AI
Voice AI That Speaks Carrier-Grade SIP
Session Timers, Re-INVITEs, QoS Preconditions. The SIP features every carrier network depends on, built by the team that wrote the SIP stack the industry runs on.
Periodic SIP re-INVITE or UPDATE messages keep a call session alive. Without them, long-running calls die silently when a network element times out. Room-based media servers have no concept of session timers.
QoS Preconditions guarantee voice quality
IMS networks negotiate quality-of-service parameters before the media session starts. A platform built for WebRTC rooms cannot participate in this negotiation because the protocol has no room equivalent.
Re-INVITE handling is basic telephony
Hold, resume, codec renegotiation, adding or removing media streams, and session refresh all happen through Re-INVITEs. A SIP stack that does not handle Re-INVITE cannot perform basic telephony operations.
SIP dialog state gets lost in translation
When a SIP call becomes a participant in a room, connection-level features disappear. Headers, session parameters, and authentication context get reduced to a room participant object.
Room-based architecture vs. telephony-native
Room-Based Platform
SIP features must map to room concepts (most have no equivalent)
SIP is a bridge feature; carrier edge cases get secondary attention
Requires a separate CPaaS provider for actual phone calls
Two platforms, two bills, latency from bridging between them
20+ years of carrier-grade SIP engineering via FreeSWITCH
Build a Voice AI Agent
fromsignalwire_agentsimportAgentBasefromsignalwire_agents.core.function_resultimportSwaigFunctionResultclassSupportAgent(AgentBase):def__init__(self):super().__init__(name="Support Agent",route="/support")self.prompt_add_section("Instructions",body="You are a customer support agent. ""Greet the caller and resolve their issue.")self.add_language("English","en-US","rime.spore:mistv2")@AgentBase.tool(name="check_order")defcheck_order(self,order_id:str):"""Check the status of a customer order. Args: order_id: The order ID to look up """returnSwaigFunctionResult(f"Order {order_id}: shipped, ETA April 2nd")agent=SupportAgent()agent.run()
import{AgentBase,FunctionResult}from'@signalwire/sdk';constagent=newAgentBase({name:'Support Agent',route:'/support',});agent.promptAddSection('Instructions','You are a customer support agent. Greet the caller and resolve their issue.');agent.addLanguage({name:'English',code:'en-US',voice:'rime.spore:mistv2'});agent.defineTool({name:'check_order',description:'Check the status of a customer order',parameters:{type:'object',properties:{order_id:{type:'string',description:'The order ID to look up'},},required:['order_id'],},handler:(args)=>{returnnewFunctionResult(`Order ${args.order_id}: shipped, ETA April 2nd`);},});agent.run();
packagemainimport("fmt""github.com/signalwire/signalwire-go/pkg/agent""github.com/signalwire/signalwire-go/pkg/swaig")funcmain(){a:=agent.NewAgentBase(agent.WithName("Support Agent"),agent.WithRoute("/support"),)a.PromptAddSection("Instructions","You are a customer support agent. Greet the caller and resolve their issue.")a.AddLanguage(map[string]any{"name":"English","code":"en-US","voice":"rime.spore:mistv2",})a.DefineTool(agent.ToolDefinition{Name:"check_order",Description:"Check the status of a customer order",Parameters:map[string]any{"type":"object","properties":map[string]any{"order_id":map[string]any{"type":"string","description":"The order ID to look up",},},"required":[]string{"order_id"},},Handler:func(argsmap[string]any,rawDatamap[string]any)*swaig.FunctionResult{orderID:=args["order_id"]returnswaig.NewFunctionResult(fmt.Sprintf("Order %v: shipped, ETA April 2nd",orderID),)},})a.Run()}
importcom.signalwire.sdk.agent.AgentBase;importcom.signalwire.sdk.swaig.FunctionResult;importjava.util.List;importjava.util.Map;publicclassSupportAgent{publicstaticvoidmain(String[]args)throwsException{varagent=AgentBase.builder().name("Support Agent").route("/support").build();agent.promptAddSection("Instructions","You are a customer support agent. "+"Greet the caller and resolve their issue.");agent.addLanguage("English","en-US","rime.spore:mistv2");agent.defineTool("check_order","Check the status of a customer order",Map.of("type","object","properties",Map.of("order_id",Map.of("type","string","description","The order ID to look up")),"required",List.of("order_id")),(toolArgs,rawData)->{varorderId=toolArgs.get("order_id");returnnewFunctionResult("Order "+orderId+": shipped, ETA April 2nd");});agent.run();}}
# frozen_string_literal: truerequire'signalwire'agent=SignalWire::AgentBase.new(name:'Support Agent',route:'/support')agent.prompt_add_section('Instructions','You are a customer support agent. Greet the caller and resolve their issue.')agent.add_language(name:'English',code:'en-US',voice:'rime.spore:mistv2')agent.define_tool(name:'check_order',description:'Check the status of a customer order',parameters:{'order_id'=>{'type'=>'string','description'=>'The order ID to look up'}})do|args,_raw|SignalWire::Swaig::FunctionResult.new("Order #{args['order_id']}: shipped, ETA April 2nd")endagent.run
<?phprequire'vendor/autoload.php';useSignalWire\Agent\AgentBase;useSignalWire\SWAIG\FunctionResult;$agent=newAgentBase(['name'=>'Support Agent','route'=>'/support']);$agent->promptAddSection('Instructions','You are a customer support agent. Greet the caller and resolve their issue.');$agent->addLanguage('English','en-US','rime.spore:mistv2');$agent->defineTool(name:'check_order',description:'Check the status of a customer order',parameters:['order_id'=>['type'=>'string','description'=>'The order ID to look up'],],handler:function(array$args):FunctionResult{returnnewFunctionResult("Order {$args['order_id']}: shipped, ETA April 2nd");});$agent->run();
#!/usr/bin/env perlusestrict;usewarnings;uselib'lib';useSignalWire::Agent::AgentBase;useSignalWire::SWAIG::FunctionResult;my$agent=SignalWire::Agent::AgentBase->new(name=>'Support Agent',route=>'/support',);$agent->prompt_add_section('Instructions','You are a customer support agent. Greet the caller and resolve their issue.');$agent->add_language(name=>'English',code=>'en-US',voice=>'rime.spore:mistv2');$agent->define_tool(name=>'check_order',description=>'Check the status of a customer order',parameters=>{order_id=>{type=>'string',description=>'The order ID to look up'},},handler=>sub{my($args,$raw)=@_;returnSignalWire::SWAIG::FunctionResult->new(response=>"Order $args->{order_id}: shipped, ETA April 2nd");},);$agent->run;
#include<signalwire/agent/agent_base.hpp>usingnamespacesignalwire;usingjson=nlohmann::json;classSupportAgent:publicagent::AgentBase{public:SupportAgent():AgentBase("Support Agent","/support"){prompt_add_section("Instructions","You are a customer support agent. ""Greet the caller and resolve their issue.");add_language({"English","en-US","rime.spore:mistv2"});define_tool({.name="check_order",.description="Check the status of a customer order",.parameters={{"order_id",{{"type","string"},{"description","The order ID to look up"}}}},.handler=[](constjson&args,constjson&){autoorder_id=args.value("order_id","unknown");returnswaig::FunctionResult("Order "+order_id+": shipped, ETA April 2nd");}});}};intmain(){SupportAgent().run();}
usingSignalWire.Agent;usingSignalWire.SWAIG;varagent=newAgentBase(newAgentOptions{Name="Support Agent",Route="/support"});agent.PromptAddSection("Instructions","You are a customer support agent. Greet the caller and resolve their issue.");agent.AddLanguage("English","en-US","rime.spore:mistv2");agent.DefineTool("check_order","Check the status of a customer order",new{type="object",properties=new{order_id=new{type="string",description="The order ID to look up"}},required=new[]{"order_id"}},(args,rawData)=>{varorderId=args.TryGetValue("order_id",outvarid)?id:"unknown";returnnewFunctionResult($"Order {orderId}: shipped, ETA April 2nd");});agent.Run();
usesignalwire::agent::AgentBase;usesignalwire::swaig::FunctionResult;useserde_json::json;fnmain(){letmutagent=AgentBase::builder().name("Support Agent").route("/support").build();agent.prompt_add_section("Instructions","You are a customer support agent. Greet the caller and resolve their issue.",&[]).add_language("English","en-US","rime.spore:mistv2");agent.define_tool("check_order","Check the status of a customer order",json!({"type":"object","properties":{"order_id":{"type":"string","description":"The order ID to look up"}},"required":["order_id"]}),Box::new(|args,_raw|{letorder_id=args.get("order_id").and_then(|v|v.as_str()).unwrap_or("unknown");FunctionResult::with_response(&format!("Order {order_id}: shipped, ETA April 2nd"))}),);agent.run();}
SIP features voice AI agents need
Feature
What it does
Why voice AI needs it
Session Timers
Periodic session refresh
Long-running AI calls die without them
QoS Preconditions
Pre-call quality negotiation
IMS carriers require it before media flows
Re-INVITE
Mid-call session modification
Hold, resume, codec renegotiation
SIP REFER
Call transfer
AI-to-human handoff
SIP SUBSCRIBE/NOTIFY
Presence and events
Contact center agent availability
SIP INFO
Mid-call signaling
DTMF, IVR navigation, authentication
SRTP/TLS
Encrypted media and signaling
HIPAA, PCI, regulatory compliance
Codec negotiation
SDP offer/answer
Interoperability with any endpoint
Deploy voice AI on carrier infrastructure
1
Define your agent
Write a YAML document or Python class. The same definition works whether the call arrives from an IMS carrier, a SIP trunk, or a PSTN line.
2
Connect your SIP infrastructure
Point your SIP trunks at SignalWire. Session Timers, QoS Preconditions, and Re-INVITEs are handled transparently by the FreeSWITCH-based stack.
3
Test with real carrier traffic
Route test calls through your IMS or enterprise telephony environment. Verify SIP compliance end-to-end.
4
Scale to production
Same platform, same SIP stack, same behavior at carrier scale. No surprises when traffic increases.
SignalWire was built by the team that created FreeSWITCH, the open-source telephony engine that powers major carriers, enterprise contact centers, and unified communications systems worldwide. Production SIP engineering is the foundation, not an add-on.
FAQ
Does SignalWire support IMS carrier deployments?
Yes. The FreeSWITCH-based SIP stack handles Session Timers (RFC 4028), QoS Preconditions (RFC 3312), and the full range of carrier-grade SIP features that IMS networks require.
Can I integrate with existing PBX infrastructure?
Yes. Native SIP trunking, registration, digest authentication, and protocol-level compatibility with session border controllers and enterprise telephony environments.
What about encrypted media and signaling?
SRTP for encrypted media and TLS for encrypted signaling are built into the platform. Required for HIPAA, PCI, and regulatory compliance.
How does transfer work for AI-to-human handoff?
Native SIP REFER for call transfer, with full conversation context (AI summary, session variables, conversation history) carried through to the receiving agent. No webhook gymnastics.
Trusted by 2,000+ companies
Built by the team that wrote the SIP stack.
Deploy voice AI on real carrier infrastructure with full SIP compatibility from day one.