One Stack Replaces Your Entire Vendor Chain | SignalWire
Voice AI Infrastructure
One Stack Replaces Your Vendor Chain
Five vendors for one phone call means five failure domains, five invoices, and zero unified logs. Ship voice AI agents on a platform that owns every layer from PSTN to AI.
Weeks of glue code to connect five APIs, handle format mismatches, and manage WebSocket lifecycle. Every vendor API change, deprecation, or rate limit adjustment requires engineering attention.
Cross-provider debugging at 2am
An alert fires. Callers hear silence. Each vendor says their service is healthy. Four hours of log correlation across three time zones before you discover the TTS provider ran out of characters three days ago.
Double-billing and race conditions
Mixing telephony and orchestration vendors creates overlapping charges and timing conflicts. Multiple providers meter the same minutes from different angles.
Five contracts, five SLAs, zero accountability
When something breaks in the gap between vendors, nobody is responsible. Each vendor points at the others. Your team absorbs the incident.
Five vendors vs. one platform
Typical Voice AI Stack
Telephony from one provider
STT from another provider
TTS from a third provider
LLM from a fourth provider
Orchestration from a fifth provider
Five invoices, five failure domains, zero unified logs
SignalWire
Telephony, STT, TTS, and LLM orchestration in one media engine
One invoice, one set of logs, one support channel
No WebSocket piping between vendors
Sub-second AI response latency (800-1200ms typical)
Built by the team that wrote 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();}
Real numbers
Metric
Five-Vendor Stack
SignalWire
Per-minute cost
$0.20-$0.33 all-in
$0.16/min all AI components
Invoices
5
1
Typical AI response latency
950ms-3,000ms
800-1200ms
Vendor hops per turn
6+
0
Time to production
Months
Days
2am incident resolution
Hours (cross-provider)
Minutes (single log)
The migration path
1
Start with one agent
Define a voice AI agent in YAML or Python. Point a phone number at it. Test against your existing stack.
2
Compare side by side
Measure latency, reliability, and cost. SignalWire delivers 800-1200ms typical response latency because there are no vendor hops.
3
Expand at your pace
Move additional call flows as confidence grows. Bring your own LLM, STT, or TTS providers, or use the integrated defaults.
4
Consolidate
Replace five invoices with one. Replace five support channels with one. Replace five failure domains with one.
Who gets the 2am ticket? In a five-vendor stack, each provider reports healthy while callers hear silence. The root cause hides in the gap between vendors. In a single stack, one set of logs covers the entire call lifecycle from PSTN to AI and back.
FAQ
Can I bring my own AI providers?
Yes. Use your preferred LLM, STT, or TTS provider alongside the integrated defaults. The platform handles codec conversion, streaming, and orchestration regardless of which providers you choose.
How does pricing work?
AI processing (STT, LLM inference, TTS, and orchestration) at $0.16 per minute. Transport (SIP, PSTN) billed separately at carrier rates. No hidden markup chain from separate providers. No minimum commitment. One invoice covers everything.
What about existing phone numbers?
Port your existing numbers or provision new ones. Global coverage with inbound and outbound, SIP and PSTN native.
Who built this platform?
The team that wrote FreeSWITCH, the open-source telephony engine processing trillions of minutes across the industry. Over 2,000 companies run production workloads on SignalWire.
Trusted by 2,000+ companies
Stop stitching. Start shipping.
One platform from PSTN to AI. One invoice. One set of logs. Built by the FreeSWITCH team.