Skip to content

SignalWire AI

For AI agents: a documentation index is available at the root level at /llms.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.

SignalWire AI is built for unlimited programmability and scale. Integrate AI and deploy a MVP with low-code/no-code drag-and-drop tools, then scale your application on SignalWire’s cloud platform.

Quickstart

Deploy a serverless AI Agent and call it over the PSTN in under 5 minutes.

1

Create a free account

Register your SignalWire account.

2

Import SWML script

Open the RELAY / SWML tab in your SignalWire Dashboard, paste the following script, and hit Save.

Fun fact

This simple YAML/JSON document is a complete calling application!

swml.yaml

version: 1.0.0
sections:
  main:
    - ai:
        prompt:
          text: You are a knowledgeable developer. Have an open-ended discussion with the caller about SignalWire and programmable communications.

3

Assign a phone number

Buy a phone number using your $5 promotional credit.

4

Give it a call

Dial your newly configured AI Agent over the PSTN from your cell phone or a VoIP dialer.

SWML

SWML (SignalWire Markup Language) is the most powerful and flexible way to use AI on the SignalWire platform.

SWML is a structured language for configuring and orchestrating real-time communication applications using lightweight and readable JSON or YAML files. These SWML Scripts can be deployed serverlessly in SignalWire’s cloud, or from your server.

SWML’s ai method integrates advanced AI Agents, which can interact with external APIs.

Technical reference\ \ SWML AI method

AI Agents

Configure AI Agents right in your SignalWire Space with a streamlined, no-code user interface.

AI Agents in the Dashboard\ \ Getting started guide

Call Flow Builder

Add AI Agents built in your SignalWire Space directly to drag-and-drop call flows.

Call Flow Builder\ \ Guide to the AI Agent node

Agents SDK

Build powerful custom voice AI agents with Python. The SignalWire Agents SDK provides complete programmatic control for sophisticated voice applications.

Quick Start\ \ Build your first agent in 5 minutes Examples\ \ Progressive examples from simple to advanced Prefab Agents\ \ Ready-to-use agent templates

Use cases

Simple AI Phone Call

A basic AI-powered phone agent that can hold an open-ended conversation.

Agents SDK
SWML
Call Flow Builder
from signalwire import AgentBase

# Create an agent and assign a route
<Badge type="tip" text="Fresh" />
agent = AgentBase("My Assistant", route="/assistant")

# Add some basic capabilities
agent.add_skill("datetime")     # Current date/time info
agent.add_skill("math")         # Mathematical calculations

# Start the agent
if __name__ == "__main__":
    agent.run()

Agents SDK docs | Quickstart guide

FAQ Bot

An AI agent that answers frequently asked questions about your business.

Agents SDK
SWML
from signalwire.prefabs import FAQBotAgent

agent = FAQBotAgent(
    faqs=[\
        {\
            "question": "What are your hours?",\
            "answer": "We're open 9 AM to 5 PM, Monday to Friday."\
        },\
        {\
            "question": "Where are you located?",\
            "answer": "123 Main Street, Downtown."\
        }\
    ]
)

if __name__ == "__main__":
    agent.run()

Agents SDK docs | FAQ Bot prefab

Customer Service Agent

An agent that looks up customer accounts and transfers calls to human support when needed.

Agents SDK
SWML
from signalwire import AgentBase, FunctionResult

agent = AgentBase(name="support")
agent.prompt_add_section("Role", "You are a helpful customer service agent.")

@agent.tool(description="Look up customer account")
def lookup_account(account_id: str) -> FunctionResult:
    # Simulate database lookup
    customer = {"name": "John Doe", "status": "active"}
    return FunctionResult(f"Account: {customer['name']}, Status: {customer['status']}")

@agent.tool(description="Transfer to support")
def transfer_support() -> FunctionResult:
    return FunctionResult("Connecting you to support.").connect("+15551234567")

if __name__ == "__main__":
    agent.run()

Agents SDK docs | Custom functions guide

Hotel Concierge

A virtual concierge that helps guests with amenity information and service bookings.

Agents SDK
SWML
from signalwire.prefabs import ConciergeAgent

agent = ConciergeAgent(
    venue_name="Grand Hotel",
    services=["room service", "spa bookings", "restaurant reservations"],
    amenities={
        "pool": {"hours": "7 AM - 10 PM", "location": "2nd Floor"},
        "gym": {"hours": "24 hours", "location": "3rd Floor"}
    }
)

if __name__ == "__main__":
    agent.run()

Agents SDK docs | Concierge prefab

Appointment Scheduling

An agent that checks availability, books appointments, and sends SMS confirmations.

Agents SDK
SWML
from signalwire import AgentBase, FunctionResult
from datetime import datetime

appointments = []

agent = AgentBase(name="scheduler", route="/scheduler")
agent.prompt_add_section("Role", "You help customers schedule appointments.")
agent.prompt_add_section("Guidelines", """
- Collect customer name, date, and preferred time
- Confirm all details before booking
- Send SMS confirmation when booking is complete
""")
agent.add_language("English", "en-US", "rime.spore")

@agent.tool(description="Check if a time slot is available")
def check_availability(date: str, time: str) -> FunctionResult:
    for apt in appointments:
        if apt["date"] == date and apt["time"] == time:
            return FunctionResult(f"Sorry, {date} at {time} is not available.")
    return FunctionResult(f"{date} at {time} is available.")

@agent.tool(description="Book an appointment")
def book_appointment(
    name: str,
    phone: str,
    date: str,
    time: str
) -> FunctionResult:
    appointments.append({
        "name": name,
        "phone": phone,
        "date": date,
        "time": time,
        "booked_at": datetime.now().isoformat()
    })
    return (
        FunctionResult(f"Appointment booked for {name} on {date} at {time}.")
        .send_sms(
            to_number=phone,
            from_number="+15559876543",
            body=f"Your appointment is confirmed for {date} at {time}."
        )
    )

if __name__ == "__main__":
    agent.run()

Agents SDK docs | InfoGatherer prefab

Survey

An agent that conducts customer satisfaction surveys with different question types.

Agents SDK
SWML
from signalwire.prefabs import SurveyAgent

agent = SurveyAgent(
    survey_name="Customer Satisfaction Survey",
    questions=[\
        {\
            "id": "satisfaction",\
            "text": "How satisfied were you with our service?",\
            "type": "rating",\
            "scale": 5\
        },\
        {\
            "id": "recommend",\
            "text": "Would you recommend us to others?",\
            "type": "yes_no"\
        },\
        {\
            "id": "comments",\
            "text": "Any additional comments?",\
            "type": "open_ended",\
            "required": False\
        }\
    ]
)

if __name__ == "__main__":
    agent.run()

Agents SDK docs | Survey prefab

Receptionist

A virtual receptionist that greets callers and routes them to the right department.

Agents SDK
SWML
from signalwire.prefabs import ReceptionistAgent

agent = ReceptionistAgent(
    departments=[\
        {\
            "name": "sales",\
            "description": "Product inquiries, pricing, and purchasing",\
            "number": "+15551234567"\
        },\
        {\
            "name": "support",\
            "description": "Technical help and troubleshooting",\
            "number": "+15551234568"\
        },\
        {\
            "name": "billing",\
            "description": "Payment questions and account issues",\
            "number": "+15551234569"\
        }\
    ]
)

if __name__ == "__main__":
    agent.run()

Agents SDK docs | Receptionist prefab

Lead Qualification

An agent that collects information from potential customers and qualifies them for the sales team.

Agents SDK
SWML
from signalwire.prefabs import InfoGathererAgent

agent = InfoGathererAgent(
    questions=[\
        {"key_name": "name", "question_text": "What is your name?"},\
        {"key_name": "company", "question_text": "What company are you with?"},\
        {"key_name": "phone", "question_text": "What is your phone number?", "confirm": True},\
        {"key_name": "budget", "question_text": "What is your budget range for this project?"},\
        {"key_name": "timeline", "question_text": "What is your timeline for making a decision?"}\
    ],
    name="lead-qualifier"
)

agent.prompt_add_section(
    "Role",
    "You are qualifying leads for the sales team. Be friendly and professional."
)

if __name__ == "__main__":
    agent.run()

Agents SDK docs | InfoGatherer prefab

Real-Time Transcription

An agent that records calls and provides real-time transcription.

Agents SDK
SWML
from signalwire import AgentBase, FunctionResult

agent = AgentBase(name="transcription-agent")
agent.add_language("English", "en-US", "rime.spore")
agent.prompt_add_section("Role", "You are a helpful assistant. The call is being recorded for transcription.")
agent.set_params({"save_conversation": True})

@agent.tool(description="Start recording the call for transcription")
def start_recording() -> FunctionResult:
    return (
        FunctionResult("Recording has started.")
        .record_call(
            control_id="transcription",
            stereo=True,
            format="wav"
        )
    )

if __name__ == "__main__":
    agent.run()

Agents SDK docs | Call recording guide

View All Examples\ \ From beginner to expert level SDK Documentation\ \ Complete reference guide


How does it work?

Under the hood, the SignalWire AI Gateway (SWAIG) orchestrates the many supporting services that make integrated realtime voice AI possible.

  • AI Agent
  • Prompt
  • LLM
  • SWAIG Functions
  • TTS (Text-To-Speech) Providers

AI Agent diagram.

AI Agent diagram.


Best practices for creating a SignalWire AI agent

For AI agents: a documentation index is available at the root level at /llms.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.

Overview

When designing an AI Agent with SignalWire, it’s crucial to achieve a harmonious balance between clarity, efficiency, and adaptability. The following guide offers a detailed overview of best practices to make sure your SignalWire Agent operates effectively and offers a user-friendly experience.


”End-Pointing” and “Turnaround”

When using SignalWire products to design interaction between AI systems and humans, you’ll likely encounter the important concepts of “end-pointing” and “turnaround.”

  • End-pointing, or “end-of-utterance detection”: this is the AI’s ability to detect when a human speaker has finished speaking.
  • Turnaround, or “turn-taking”: This refers to the time it takes for the AI to process the human’s input and generate a response.

While it might seem ideal for AI to optimize for instant end-pointing and turnaround, this expectation is unrealistic for several reasons:

  • Natural language understanding and processing are complex tasks that require the AI to analyze syntax, semantics, and context of human speech. This analysis takes time, even if only a fraction of a second.
  • Real-world communication is often filled with nuances, such as pauses, overlapping speech, and non-verbal cues. These features make it challenging for AI to confidently pinpoint the moment a speaker has finished.
  • Generating coherent, contextually appropriate, and nuanced responses takes computational time.

A sharp increase in interest in AI products has led to a number of new products claiming to offer instantaneous end-pointing and turnaround. If an AI agent appears to respond perfectly and immediately in a recorded demo, it may be too good to be true.

SignalWire AI products include a number of tools designed to help you increase the apparent responsiveness of your AI agents. For example:

  • Filler words provide text which the AI can say while processing is taking place.
  • Background audio such as typing noises or office noises can offer immediate feedback to the user.

Crafting the Initial Prompt for the AI

The initial prompt sets the tone and context for your AI Agent. It’s essential to be concise, clear, and relevant.

  • Avoid Over-Prompting: Overloading the AI with excessive information can muddle its understanding. Instead, furnish it with a brief yet comprehensive overview that defines its role and boundaries.
  • Stick to Necessities: Clearly outline the AI’s identity and primary responsibilities. This guarantees the AI comprehends its mission and can respond appropriately.
  • Use Markdown for Structuring the Prompt: Structuring prompts in Markdown is highly recommended. It ensures content is organized and legible, both boosting readability and narrowing the AI’s interpretation.

Delving into Prompt Configuration

Understanding the prompt’s configuration parameters is key to fine-tuning the AI’s responses:

  • Temperature (temperature): Influences the randomness of the AI’s output. A value closer to 0 makes the AI’s responses more deterministic and focused, while higher values introduce more variety.
  • Top P (top_p): Another parameter influencing randomness. It dictates how diverse the AI’s responses can be. A lower value narrows down the potential responses.
  • Confidence (confidence): Determines the threshold for speech-detection events. A lower value reduces the pause after user interaction but may lead to false positives.
  • Presence Penalty (presence_penalty): Dictates the AI’s propensity to introduce new topics. A positive value makes the AI more likely to diversify its responses.
  • Frequency Penalty (frequency_penalty): Influences the AI’s tendency to repeat itself. Positive values discourage repetition.
YAML
JSON
sections:
  main:
    - ai:
        prompt:
          text: |
            Your name is David. You are a virtual assistant that is helping with tree planting
            and their environmental benefits.

            ## Information on Tree Planting
            Tree planting is a vital activity that significantly contributes to the environment.
            Trees absorb CO2, prevent soil erosion, provide habitat for wildlife, and offer many
            other benefits.

            ## David's Personality and Job Duties
            Your duties are to help assist users with information related to tree planting.
            You have a friendly and eco-conscious personality.

            ## Greeting Rules
            Greet the user and thank them for showing interest in tree planting. Introduce yourself as David.
            Prefix the greeting with a 'good morning', 'good afternoon', or a 'good evening' depending on the time of day.

          temperature: 0.89
          top_p: 0.64
          confidence: 0.5

Dynamic data

For best results, we recommend including dynamic data, such as data returned by SWAIG functions, at the bottom of your prompt. This improves the speed and consistency of LLM results due to the way that responses are cached.

For more information, consult OpenAI’s documentation on prompt caching.


Exploring Functions in SignalWire AI

SignalWire’s AI Agent uses functions to neatly store and organize information. This way, the AI can easily handle diverse questions without needing long and complicated prompts.

Employ data_map and webhook_url for Storing Prompts

Utilizing data_map to store specific prompts or text segments is a practical approach. It allows you to retrieve them when necessary, promoting a fluid and logical flow of dialogue.

Moreover, SignalWire’s AI Agent offers the flexibility to incorporate external logic via the webhook_url. By pointing the AI to your own webhook, you can harness backend logic to further customize and refine the AI’s responses based on real-time data or specific conditions.

YAML
JSON
SWAIG:
  functions:
    - function: tree_benefits
      purpose: To share the benefits of planting trees.
      argument:
        type: object
        properties:
          benefit_type:
            type: string
      data_map:
        expressions:
          - string: %{lc:args.benefit_type}
            pattern: carbon
            output:
              response: "Trees play a crucial role in absorbing carbon dioxide, thereby helping combat climate change."
    - function: lookup_tree
      web_hook_url: https://example.com/webhook_endpoint
      purpose: To lookup a type of tree.
      argument:
        type: object
        properties:
          tree_type:
            type: string

Optimize Token Usage

By invoking functions to offer specific guidelines when necessary, you utilize tokens more efficiently, ensuring both optimal AI performance and cost-effectiveness.

Elaboration on the Function’s Efficacy

  • Dynamic Response Generation: The tree_benefits function is designed to provide tailored responses based on user queries. This is evident from the way the data_map is structured. Depending on whether a user asks about the benefits of trees in relation to “carbon”, “soil”, or “wildlife”, the AI will furnish a specific, relevant answer.
  • Pattern Recognition: By using the pattern keyword within the data_map, the function can identify specific keywords or patterns in the user’s inquiry. This ensures that the AI’s response is not just generic but directly corresponds to the user’s query.
  • Token Efficiency: Instead of having a lengthy prompt containing all the possible benefits of trees, the function offers a modular approach. It only provides detailed information about a specific benefit when asked, ensuring that tokens (which represent chunks of information the AI can process in a single go) are used judiciously.
  • Scalability: With the current structure, adding more benefits or details becomes straightforward. For instance, if in the future there’s a need to include benefits related to “air quality” or “shade”, it can be seamlessly integrated into the function without overhauling the existing setup.
  • Enhanced User Engagement: By furnishing precise, on-demand information, the AI elevates user experience, ensuring interactions are concise and meaningful.

In essence, the tree_benefits function exemplifies the power of modular design in AI prompts. It showcases how, by intelligently structuring functions, one can create an AI Agent that’s both responsive and resource-efficient.

Utilizing Perl Compatible Regular Expressions (PCRE)

The PCRE is a powerful library that provides a set of functions to match patterns using regular expressions. In the context of a SignalWire AI Agent, PCRE can be used to match specific patterns or keywords in a user’s response and dictate the AI’s subsequent actions.

Benefits of Using PCRE in SignalWire AI

  • Flexibility: PCRE allows for complex pattern matching, enabling the AI to recognize a wide range of user inputs.
  • Precision: PCRE ensures that the AI’s responses or actions are tailored to the user’s specific queries or statements.
  • Efficiency: By using regular expressions, developers can write concise patterns that capture a variety of user inputs, reducing the need for long lists of possible phrases or keywords.
  • Scalability: As the system grows or changes, patterns can easily be updated or expanded to accommodate new functionalities without overhauling the entire system.

Example: Using PCRE to Share Benefits of Planting Trees

Consider the following SignalWire AI configuration that employs PCRE for sharing benefits of planting trees:

YAML
JSON
SWAIG:
  functions:
    - function: tree_benefits
      purpose: To share the benefits of planting trees.
      argument:
        type: object
        properties:
          benefit_type:
            type: string
      data_map:
        expressions:
          - string: %{lc:args.benefit_type}
            pattern: /carbon/i
            output:
              response: "Trees play a crucial role in absorbing carbon dioxide, thereby helping combat climate change."
          - string: %{lc:args.benefit_type}
            pattern: /soil/i
            output:
              response: "Trees help prevent soil erosion and improve soil quality, making the land more fertile."
          - string: %{lc:args.benefit_type}
            pattern: /wildlife/i
            output:
              response: "Trees help wildlife flourish.Many animals also use trees for resting, nesting and for places from which to hunt or capture prey. When the trees mature, animals are able to enjoy delicious fruits and foraging opportunities."
Example Overview:
  • PCRE patterns like /carbon/i, /soil/i, and /wildlife/i are used to match specific benefit types provided as input.
  • Depending on the matched pattern, the AI provides a relevant response about the benefits of tree planting related to carbon absorption, soil quality, or wildlife support.
  • The /i modifier in the patterns makes the regex match case-insensitive, adding flexibility to user input.

Harnessing the Power of Hints

Hints serve as beacons, directing the AI’s comprehension and making sure it stays relevant to the given context.

  • Keyword Guidance: Introducing specific keywords as hints can channel the AI’s attention. This ensures that the AI resonates with the intended theme.
  • Example: For a tree planting and environmental benefits AI, hints like “sapling”, “soil”, “watering”, “benefits”, and “environment” are pivotal.
YAML
JSON
hints:
  - wildlife
  - carbon
  - sapling
  - soil
  - watering
  - benefits
  - environment

Staying In Regulation with FCC Guidelines

The Federal Communications Commission (FCC) has explicitly criminalized unsolicited robocalls that use voices made with artificial intelligence. The proposal would outlaw such robocalls under the Telephone Consumer Protection Act, or TCPA, a 1991 law that regulates automated political and marketing calls made without the receivers’ consent.

This means that any AI Agent that interacts with users must be transparent about its nature and purpose. This does not mean that AI Agents are illegal, but rather that they must be used responsibly and in compliance with the law.

Key Considerations for FCC Compliance

  • Transparency: Clearly state that the user is interacting with an AI Agent.
  • Opt-Out Mechanism: Provide a simple and straightforward method for users to opt out of the AI interaction.
  • User Consent: Ensure that users are aware of the AI’s capabilities and have consented to interact with it.

Other General Best Practices

  • Regularly Review and Update: AI, like any other tool, benefits from regular reviews. Periodically assess its performance and make necessary adjustments.
  • Test with Real Users: Before deploying, conduct beta testing with real users to gather feedback and identify areas of improvement.
  • Stay Updated with SignalWire Changes: AI and associated platforms evolve. Stay updated with SignalWire’s documentation and update your AI accordingly.
  • Monitor Usage Metrics: Keep an eye on token consumption, user interaction times, and other relevant metrics to optimize performance and manage costs.

Tree Planting AI Example

This example illustrates a comprehensive AI virtual assistant configuration, named David, designed to guide users on tree planting and its myriad environmental advantages. By harnessing structured YAML configurations, the AI Agent functions effectively, ensuring users receive accurate and pertinent information.

YAML
JSON
sections:
  main:
    - ai:
        prompt:
          text: |
            Your name is David. You are a virtual assistant that is helping with tree planting
            and their environmental benefits.

            ## Information on Tree Planting
            Tree planting is a vital activity that significantly contributes to the environment.
            Trees absorb CO2, prevent soil erosion, provide habitat for wildlife, and offer many
            other benefits.

            ## David's Personality and Job Duties
            Your duties are to help assist users with information related to tree planting.
            You have a friendly and eco-conscious personality.

            ## Greeting Rules
            Greet the user and thank them for showing interest in tree planting. Introduce yourself as David.
            Prefix the greeting with a 'good morning', 'good afternoon', or a 'good evening' depending on the time of day.
          temperature: 0.89
          top_p: 0.64
          confidence: 0.5
        post_prompt:
          text: '## Post Prompt Actions\n\nSummarize the call and provide the summary in a JSON format.'
          temperature: 0
          top_p: 1.0
        post_prompt_url: https://example.site/webhook_url
        params:
          direction: inbound
          swaig_allow_swml: true
        SWAIG:
          functions:
            - function: tree_benefits
              purpose: To share the benefits of planting trees.
              argument:
                type: object
                properties:
                  benefit_type:
                    type: string
              data_map:
                expressions:
                  - string: %{lc:args.benefit_type}
                    pattern: /carbon/i
                    output:
                      response: "Trees play a crucial role in absorbing carbon dioxide, thereby helping combat climate change."
                  - string: %{lc:args.benefit_type}
                    pattern: /soil/i
                    output:
                      response: "Trees help prevent soil erosion and improve soil quality, making the land more fertile."
                  - string: %{lc:args.benefit_type}
                    pattern: /wildlife/i
                    output:
                      response: "Trees help wildlife flourish.Many animals also use trees for resting, nesting and for places from which to hunt or capture prey. When the trees mature, animals are able to enjoy delicious fruits and foraging opportunities."
            - function: region_specific_trees
              purpose: To recommend trees suitable for specific regions or climate zones.
              argument:
                type: object
                properties:
                  region:
                    type: string
              data_map:
                expressions:
                  - string: %{lc:args.region}
                    pattern: /tropical/i
                    output:
                      response: "For tropical regions, consider planting trees like Mango, Coconut, and Banana."
                  - string: %{lc:args.region}
                    pattern: /temperate/i
                    output:
                      response: "For temperate zones, Oak, Maple, and Birch trees are great choices."
            - function: tree_planting_guide
              purpose: To guide users on the tree planting process.
              argument:
                type: object
                properties:
                  step:
                    type: string
              data_map:
                expressions:
                  - string: %{lc:args.step}
                    pattern: /digging/i
                    output:
                      response: "Dig a hole that is twice as wide as the tree’s root ball and just as deep. Place the tree in the hole and fill it with soil."
                  - string: %{lc:args.step}
                    pattern: /watering/i
                    output:
                      response: "Water the tree immediately after planting. Regularly water it, especially during dry periods."
        hints:
          - sapling
          - soil
          - watering
          - benefits
          - environment

Creating an effective SignalWire AI Agent is a blend of clarity, strategic function utilization, and continuous assessment. By adhering to these best practices, you’ll ensure that your AI Agent is both efficient and user-friendly.


AI platform

For AI agents: a documentation index is available at the root level at /llms.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.

Introduction

SignalWire’s AI platform is a unified system for building and deploying conversational AI solutions. The platform delivers a comprehensive suite of capabilities that work together seamlessly. At its core, it provides a single platform for orchestrating voice, video, and messaging channels, complemented by native integrations with leading LLM, Text-to-Speech, and Speech-to-Text providers. The system is built on serverless functions that execute with minimal latency during live conversations, supported by a multi-threaded architecture for parallel, asynchronous function execution. With a global edge network featuring points of presence in every major region and enterprise-grade security, compliance, logging and analytics, the platform ensures reliable and secure operations worldwide.


Core capabilities

Voice technology

SignalWire’s voice technology provides comprehensive control over how your AI agents sound and understand speech. The platform enables you to select from multiple Text-to-Speech providers and fine-tune voice parameters to perfectly match your brand identity. Natural speech fillers maintain smooth conversation flow during processing pauses, while real-time audio processing handles noise filtering and accent variations with precision.

Conversation intelligence

SignalWire AI revolutionizes how agents handle complex conversations. Unlike traditional IVR systems that follow rigid decision trees, our AI agents operate with natural fluidity. They excel at maintaining their assigned role while juggling multiple conversation threads, seamlessly interfacing with backend systems without breaking natural dialogue flow. Perhaps most importantly, they can handle unexpected topic changes without losing context, ensuring a more human-like interaction.

The below diagrams illustrate how a customer might schedule a medical appointment using a conventional IVR (“interactive voice response”, left), compared to using a SignalWire AI Agent (right).

Traditional IVR Flow
AI IVR Flow

For example, when a caller asks “What about the premium version?”, the AI understands this refers to a product discussed earlier in the conversation. This context awareness extends across different topics and requests within the same interaction, allowing for natural conversation flows like:

“I’d like to schedule an appointment” → “What time works for you?” → “Actually, before we do that, what’s your cancellation policy?”

The AI handles these context switches seamlessly while maintaining the original intent to schedule an appointment.

Dynamic context switching

One powerful way to structure conversations is through contexts. Instead of transferring callers between departments like a traditional system, your AI agent can switch context internally to handle different topics & requests within the same conversation.

Each context operates as an independent entity with its own specialized prompt, fresh conversation memory, and focused expertise in areas such as technical support, billing, or sales. This independence is maintained through strict information boundaries that ensure clear separation between different roles.

This sophisticated approach enables several key benefits. The system can intelligently route each task to the most appropriate specialized context while controlling information flow between contexts. It maintains natural conversation flow during role transitions and implements robust security boundaries for sensitive operations. The result is a system that delivers specialized knowledge within appropriate contexts, prevents information bleed between different roles, and maintains clear compliance and security boundaries while delivering purpose-built responses for each domain.

For example, when a customer moves from technical support to billing questions, the AI swaps context to focus solely on financial matters, leaving technical details in the previous context. This isolation maintains security while ensuring each interaction benefits from specialized expertise.

Below is an example of a context switch in a customer support scenario for both a traditional IVR and a SignalWire AI Agent.

Traditional Support Flow
SignalWire AI Flow

Real-time analytics and monitoring

The platform provides comprehensive analytics to understand and optimize your AI agents’ performance. It continuously captures vital metrics including conversation flow and role adherence, speech recognition accuracy, response timing and latency, voice quality metrics, and integration performance. This wealth of data flows through a robust webhook system that enables real-time conversation monitoring, performance metric tracking, human supervision when needed, and ongoing agent behavior optimization.

Here’s how this works in a customer support scenario:

Webhook data and metrics

Here’s an example of the data you receive during an AI interaction:

{
  "call_info": {
    "project_id": "b08dacad...",
    "content_type": "text/json",
    "call_id": "b3f4e4e1..."
  },
  "conversation_add": {
    "role": "assistant",
    "content": "...",
    "lang": "en-US",
    "tokens": 53,
    "latency": 836,
    "utterance_latency": 934,
    "audio_latency": 1106
  },
  "webhook_reply": {
    "status": "OK",
    "request_id": "341de258...",
    "parameters": {
      "query": "...",
    },
    "data": {...}
  }
}

Management tools

The real-time data enables powerful management capabilities across three key areas:

  • Live Monitoring and Supervision: The platform provides comprehensive real-time monitoring of high-value interactions, with intelligent alerting for critical situations and seamless intervention capabilities when human assistance is required.

  • Performance Optimization: Continuous performance improvement is achieved through AI behavior adjustments based on metrics, dynamic routing rule updates, and refined response pattern optimization.

  • Quality Assurance: The system maintains high service standards by quickly identifying and resolving issues, ensuring compliance requirements are met, and maintaining consistent service quality metrics.


Integration & architecture

External service integration

SignalWire AI connects with your business systems through its function framework. When your agent needs to perform an action - like checking inventory or booking an appointment - it can call functions that interact with your databases and services while keeping the conversation natural.

Here’s an example of scheduling a meeting:

The process works like this:

  1. Your agent recognizes when a request needs external data or actions
  2. It calls the appropriate function
  3. The function handles the technical work with your systems
  4. Your agent incorporates the results naturally into the conversation

This lets you automate complex processes without exposing the technical details to your users.

SignalWire’s RAG stack integration - Datasphere

Datasphere serves as SignalWire’s built-in knowledge integration system, providing AI agents with seamless access to your organization’s information. The system excels at finding and utilizing relevant information during conversations, ensuring responses remain accurate and current by drawing from your latest documentation. Every answer is backed by official documentation, providing confidence and reliability in every interaction.

Here’s an example of how it works in practice:

The system offers several key advantages:

  • Always Current: Your agents automatically use the latest information as you update your documentation

  • Smart Information Use:

    • Combines conversation context with document searches
    • References specific sources
    • Maintains natural dialogue while using detailed info
  • Flexible Organization:

    • Tag documents for easy finding
    • Choose how to break up information
    • Search using natural language
  • High Accuracy:

    • Grounds responses in your actual documents
    • Provides sources for information
    • Keeps responses consistent

Real-world applications

Customer service

SignalWire AI transforms the customer service experience by creating intelligent agents that deliver comprehensive support capabilities. These agents are designed to handle complex, multi-step inquiries while maintaining contextual awareness throughout the conversation. They seamlessly integrate with your knowledge base to provide accurate, consistent answers and can connect to your backend systems for real-time problem resolution. When situations require human expertise, the system smoothly facilitates transfers to human agents, ensuring no context is lost in the process.

Process automation

The platform excels at automating multi-step processes while maintaining natural, fluid interactions. In appointment scheduling scenarios, for example, the AI demonstrates sophisticated capabilities in understanding complex time and date requests, managing multiple calendar systems simultaneously, and handling schedule conflicts with grace. The system proactively sends confirmations and can accommodate changes when needed, all while maintaining a natural conversation flow that feels effortless to the user.


Security and compliance

SignalWire’s AI platform incorporates a comprehensive security framework that includes encrypted communications, sophisticated PII detection and protection mechanisms, and dedicated compliance tools for HIPAA and GDPR requirements. The system maintains detailed audit logging capabilities and granular access controls and permissions, enabling you to automate sensitive communications while maintaining strict regulatory compliance.


Route inbound calls to LiveKit

For AI agents: a documentation index is available at the root level at /llms.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.

In this guide, we will deploy a SWML script that routes inbound calls from SignalWire to the LiveKit platform. The script uses the SWML connect method to dial a LiveKit SIP address.

Prerequisites

Before getting started, you’ll need the following:

  • a SignalWire Space
  • a LiveKit account
  • a SignalWire phone number

Setup

1

Create a SWML Script

To create a SWML script, navigate to the Resources tab in your SignalWire Dashboard, click + Add New, and select SWML Script.

  • Log in to your SignalWire Dashboard and navigate to the Resources tab on the left-hand sidebar.
  • Click Add, select Script, and then choose SWML Script.
  • Paste the following SWML code snippet into the editor:
version: 1.0.0
sections:
   main:
      - connect:
           to: sip:%{call.to}@your-unique-SIP-domain-from-Livekit.com;transport=tcp

Be sure to replace your-unique-SIP-domain-from-Livekit.com with the SIP domain from your LiveKit settings (for example, 241ozqza.sip.livekit.cloud). Find this domain under LiveKit Settings labeled as SIP URI.

  • Save the SWML script once the modifications are complete.

2

Assign a phone number

When your SignalWire phone number receives an inbound call, it needs to know how to handle it. In this step, we will assign the intended SignalWire phone number to the new SWML script Resource as an Address.

On the SignalWire platform, Resources, including SWML scripts, are powerful building blocks that can orchestrate any kind of communications application. Each Resource can have multiple Addresses, such as phone numbers, SIP addresses, and aliases.

  • Open the Phone Numbers tab of your SignalWire Dashboard.
  • Select the Edit Settings option for the phone number you want to use for inbound calls.
  • Click Assign Resource and choose the SWML script you just created.

This ensures that incoming calls to the designated SignalWire phone number follow the routing path defined in the SWML script.

3

Configure LiveKit

Next, we will configure a SIP trunk in LiveKit to handle calls routed from SignalWire. Follow the official LiveKit SIP trunk inbound guide for further information.

4

Add a LiveKit SIP Trunk

  • Create a new SIP trunk using the following configuration:
{
    "trunk": {
      "name": "My trunk",
      "numbers": ["+1XXXXXXXXXX"]
    }
}

Be sure to replace +1XXXXXXXXXX with the SignalWire phone number you assigned previously. Ensure the number is formatted in E.164 format.

  • Submit your configuration.

After completing this setup, you can use LiveKit’s dispatch rules to determine how incoming calls should be handled. Consult LiveKit’s Dispatch Rules Guide for guidance on managing call routing.

You’re all set to start handling inbound calls with LiveKit and SignalWire. If you need further assistance, consult the LiveKit documentation or reach out to SignalWire support.

Next steps

Troubleshooting

  • If calls are not reaching LiveKit:
    • Verify that the SIP domain in your SWML script matches your LiveKit settings.
    • Ensure your phone number is correctly formatted in the trunk configuration.

Record calls

To record inbound calls, add the record_call method to your existing inbound SWML script:

version: 1.0.0
sections:
  main:
  - record_call:
      format: mp3
  - connect:
      to: sip:%{call.to}@your-unique-SIP-domain-from-Livekit-goes-here.com

These recordings can be accessed in the Dashboard in Storage > Recordings, or using the Recordings List API endpoint.

View logs

Access call logs in the Logs tab of your SignalWire Dashboard.


Send outbound calls from LiveKit

For AI agents: a documentation index is available at the root level at /llms.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.

This guide will help you set up outbound SIP calls using LiveKit and SignalWire. Follow these steps to configure your SIP domain, SWML script, and LiveKit settings efficiently.

Prerequisites

Before getting started, you’ll need the following:

  • a SignalWire Space
  • a LiveKit account
  • a SignalWire phone number

Setup

1

Create a SWML Script

To create a SWML script, navigate to the Resources tab in your SignalWire Dashboard, click + Add New, and select SWML Script.

  • Log in to your SignalWire Dashboard and navigate to the Resources tab on the left-hand sidebar.
  • Click Add, select Script, and then choose SWML Script.
  • Paste the following SWML code snippet into the editor:

SWML

version: 1.0.0
sections:
  main:
    - connect:
        answer_on_bridge: true
        from: "+1XXXXXXXXXX"
        to: "%{call.to.replace(/^sip:/i, '').replace(/@.*/, '')}"

Be sure to replace "+1XXXXXXXXXX" with a phone number from your SignalWire account.

2

Add SIP address

  • Save the SWML script and navigate to the Addresses & Phone Numbers section within the script.
  • Click Add and select SIP Address to add your SIP domain application.
  • Configure this SIP address based on your requirements, and save it.
  • After configuration, note down your unique SIP domain.

Example SIP domain: test-space-live-kit.dapp.signalwire.com.

Now, let’s configure LiveKit for outbound SIP calling. Follow along with LiveKit’s documentation for outbound SIP trunk setup.

1

Create an outbound trunk

Use the following JSON configuration for creating an outbound SIP trunk, ensuring you update the given fields:

{
   "trunk": {
      "name": "My Outbound SIP Trunk",
      "address": "test-space-livekit.dapp.signalwire.com",
      "numbers": ["+15105550100"],
      "auth_username": "<username>",
      "auth_password": "<password>",
      "transport": 3
   }
}

Update placeholders in the above JSON with the following:

PlaceholderReplace with
"address"The SIP domain you created previously (e.g., test-space-live-kit.dapp.signalwire.com).
numbersA SignalWire phone number.
<username> and <password>The credentials provided by SignalWire Support. Contact Support if needed.

Submit this request and save the generated Trunk ID. If you forget to save the Trunk ID, use LiveKit’s CLI tool to retrieve the trunk configurations.

2

Create SIP participant

To initiate outbound calls through your configured trunk, you’ll need to create a SIP participant in LiveKit. This process establishes the connection and manages the call flow. For detailed instructions on creating SIP participants and handling outbound calls, refer to LiveKit’s comprehensive guide to Creating a SIP Participant.

If you’re working with LiveKit AI agents for outbound calls, please see the LiveKit AI Agent Telephony Guide.

3

Final checks

  • Ensure the trunk address matches exactly with the one created previously.
  • Phone numbers must be in E.164 format (e.g., “+15105550100”) to ensure proper routing and connectivity.

You’re now ready to make your first outbound SIP call using LiveKit and SignalWire. If you encounter any issues, verify the configurations for both SignalWire and LiveKit.


Next steps

Record calls

Record calls by creating a SWML script with recording logic and slightly modifying your outbound SWML script.

1

Create a second script

In your new script, paste the following SWML:

record.yaml

version: 1.0.0
sections:
  main:
  - record_call:
      format: mp3

2

Update the outbound SWML script

Then, modify your existing outbound SWML script by adding the confirm parameter under the connect method, and setting its value to the URL for the new recording script.

The result should look like this:

outbound.yaml

version: 1.0.0
sections:
  main:
    - connect:
        answer_on_bridge: true
        confirm: "your-recording-script-url"
        from: "+1XXXXXXXXXX"
        to: "%{call.to.replace(/^sip:/i, '').replace(/@.*/, '')}"

These recordings can be accessed in the Dashboard in Storage > Recordings, or using the Recordings List API endpoint.

View logs

Access call logs in the Logs tab of your SignalWire Dashboard.


No-code agent

For AI agents: a documentation index is available at the root level at /llms.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.

A new SignalWire AI Agent.

A new SignalWire AI Agent.

SignalWire AI Agents are powerful, programmable, and infinitely customizable. Initialize your agent in the Dashboard without code, assign a phone number, and SignalWire’s platform takes care of the rest.

1

Sign up for a new SignalWire account

To begin, sign up for a SignalWire account. If you already have an account, log in.

Once logged in, create a Space or select an existing Space.

Create account

2

Create an AI Agent Resource

  • Open the Resources tab in your SignalWire Space.
  • Click + Add New to create a new Resource.
  • Select AI Agent from the menu.

If prompted, choose Custom AI Agent.

What's a Resource?

Resources are the building blocks of every SignalWire communication application. Resources include AI Agents, Subscribers, RELAY applications, FreeSWITCH connectors, and more.

Resources selection.

3

Configure the agent

For this simple demo, add the below Prompt text and leave the other settings at their default.

You are a knowledgeable developer. Have an open-ended discussion with the caller about SignalWire and programmable communications.

To see live debug logs, set up a webhook from a service like Webhook.site. Paste your webhook URL in the Debug Webhook URL field in the Params tab. Ensure that Debug Webhook Level is set to 1.

4

Fund your account

Add funds to your SignalWire Space in order to purchase a phone number and initialize your AI Agent.

  • Click on the name of your Space to open the drop-down menu in the top-left corner
  • Click Usage & Billing
  • Click Add a Payment Method
  • Add a new payment method
  • From the Billing page, click Top Up Your Balance
  • Add funds

The left drop-down menu for your SignalWire Space.

5

Assign a phone number

  • Click on the Addresses tab of your AI Agent.
  • Click + Add

Add a new Address to your AI Agent.

  • In the Add an Address menu, select Phone Number
  • If you have an unassigned phone number you’d like to use, select it
  • Otherwise, select Buy a Phone Number
  • Choose a Local phone number and click Buy

Your new phone number is now ready to use!

Buying a phone number\ \ In-depth guide to purchasing a phone number on the SignalWire platform

6

Give it a call

Dial your newly configured AI Agent over the PSTN from your cell phone or a VoIP dialer.


Next steps

Congratulations, you’ve created and tested your first SignalWire AI Agent!

Next, dive into our guide to prompting and other best practices, or learn about using AI Agents in SWML and Call Flow Builder.

Best practices\ \ Optimize your SignalWire AI Agent Use AI with SWML\ \ Build advanced AI applications using SignalWire Markup Language Use AI with Call Flow Builder\ \ Deploy your AI Agent within our drag-and-drop calling application builder


VAPI inbound calling

For AI agents: a documentation index is available at the root level at /llms.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.

VAPI provides powerful AI voice assistants, but these assistants need phone numbers to receive calls. SignalWire’s phone network can route incoming calls directly to your VAPI assistants using SIP trunking. This guide shows you how to connect them.

When you’re finished, callers will dial your SignalWire phone number and immediately connect to your VAPI AI assistant - no additional routing or servers needed.

Setup overview

1

Configure VAPI for SignalWire

Set up a SIP trunk with SignalWire’s IP addresses and register your phone number.

2

Create call routing in SignalWire

Build a SWML script that forwards incoming calls to your VAPI assistant.

3

Connect and test

Assign the routing script to your phone number and verify calls reach your AI assistant.

What you’ll need

  • A SignalWire account with at least one phone number ( sign up here)
  • A VAPI account with API access
  • Your VAPI private API key (found in your VAPI dashboard)

Setting up VAPI to receive SignalWire calls

VAPI needs to know that calls will be coming from SignalWire’s network. We’ll create a SIP trunk that includes all of SignalWire’s IP addresses, then register your phone number with that trunk.

This follows VAPI’s official SIP trunk setup guide, but with SignalWire-specific configuration.

Create the SIP trunk

Run the API call below to create the trunk, making sure to replace YOUR_VAPI_PRIVATE_KEY with your actual API key.

Save the id from the response - you’ll need this credential ID for the next step.

These IP addresses are current as of this guide’s publication, but SignalWire IPs can change and should be programmatically monitored to avoid any impact on calls. You can gather SignalWire’s latest IPs by performing a DIG or nslookup of sip.signalwire.com.

See our guide on allowing SignalWire IPs through firewalls for more details.

curl -X POST "https://api.vapi.ai/credential" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_VAPI_PRIVATE_KEY" \
  -d '{
    "provider": "byo-sip-trunk",
    "name": "SignalWire Inbound Trunk",
    "gateways": [\
      { "ip": "170.64.128.96", "inboundEnabled": true },\
      { "ip": "198.13.56.186", "inboundEnabled": true },\
      { "ip": "104.248.176.184", "inboundEnabled": true },\
      { "ip": "152.42.144.114", "inboundEnabled": true },\
      { "ip": "104.248.150.114", "inboundEnabled": true },\
      { "ip": "138.68.125.160", "inboundEnabled": true },\
      { "ip": "159.65.244.171", "inboundEnabled": true },\
      { "ip": "167.99.198.84", "inboundEnabled": true },\
      { "ip": "13.245.35.235", "inboundEnabled": true },\
      { "ip": "108.61.169.31", "inboundEnabled": true },\
      { "ip": "137.184.4.155", "inboundEnabled": true },\
      { "ip": "188.166.126.7", "inboundEnabled": true },\
      { "ip": "139.59.34.94", "inboundEnabled": true },\
      { "ip": "165.232.186.228", "inboundEnabled": true },\
      { "ip": "157.175.131.128", "inboundEnabled": true }\
    ]
  }'

Register your SignalWire phone number

Now register your SignalWire phone number with VAPI using the credential ID from above:

curl -X POST "https://api.vapi.ai/phone-number" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_VAPI_PRIVATE_KEY" \
  -d '{
    "provider": "byo-phone-number",
    "name": "SignalWire Inbound Number",
    "number": "+15551234567",
    "numberE164CheckEnabled": true,
    "credentialId": "YOUR_CREDENTIAL_ID"
  }'

Make sure to replace:

  • YOUR_VAPI_PRIVATE_KEY with your actual API key
  • +15551234567 with your SignalWire phone number in E.164 format (including the + and country code)
  • YOUR_CREDENTIAL_ID with the credential ID from the previous step

Assign your AI assistant

In your VAPI dashboard, find the phone number you just registered and assign it to one of your AI assistants. You’ll only need to configure the inbound settings - we’re not using this number for outbound calls.


Configuring SignalWire to route calls

Now we need to tell SignalWire where to send incoming calls. We’ll create a simple SWML script that forwards calls to your VAPI assistant.

Create the routing script

In your SignalWire dashboard, go to ResourcesAddScriptSWML Script. This script will handle all incoming calls by immediately connecting them to VAPI:

version: 1.0.0
sections:
  main:
    - connect:
        to: 'sip:%{call.to}@YOUR_CREDENTIAL_ID.sip.vapi.ai'

Replace YOUR_CREDENTIAL_ID with the credential ID from the VAPI trunk setup above. The %{call.to} variable ensures VAPI receives the original dialed number, which helps with call routing and analytics.

This SWML script uses the connect method to bridge the incoming call directly to VAPI’s SIP endpoint. The call happens in real time with no delays. Learn more about SWML in our complete guide.

Connect the script to your phone number

Go to Phone Numbers in your SignalWire dashboard, find your number, and click Edit Settings. Under the voice settings, assign your new SWML script to handle incoming calls.

That’s it - your phone number is now connected to your VAPI assistant.


Testing and troubleshooting

Call your SignalWire phone number and you should hear your VAPI assistant answer within a few seconds.

If something isn’t working, here are the most common issues:

Calls aren’t reaching VAPI: Check that your SWML script has the correct credential ID and is assigned to your phone number. Also, verify that your phone number is set to accept voice calls.

VAPI can’t connect: Make sure all SignalWire IP addresses are in your VAPI trunk. If SignalWire has added new IP addresses since you created the trunk, you’ll need to update it.

Wrong number format errors: Phone numbers must be in E.164 format (+1234567890) with no spaces or special characters.

You can monitor call logs in both platforms - SignalWire shows the initial call routing, while VAPI shows the assistant interaction details.


What’s next

Now that you have basic inbound routing working, you might want to explore:

Outbound Calling\ \ Let your VAPI assistant make outbound calls through SignalWire Advanced Call Flows\ \ Add IVR menus, call screening, or business hours logic before connecting to VAPI Assistant Optimization\ \ Best practices for creating effective VAPI assistants


Outbound calling

For AI agents: a documentation index is available at the root level at /llms.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.

While VAPI provides powerful AI voice assistants, they need a way to make outbound calls to your customers or contacts. SignalWire’s phone network can handle outbound calls from your VAPI assistants using SIP trunking. This guide shows you how to connect them for outbound calling.

When you’re finished, your VAPI assistants will be able to initiate calls using your SignalWire phone numbers, giving you complete control over both inbound and outbound AI-powered communications.

Setup overview

1

Configure SignalWire for outbound routing

Create a SWML script and SIP domain to handle outbound calls from VAPI.

2

Set up VAPI outbound trunk

Configure VAPI with your SignalWire SIP domain and authentication details.

3

Connect and test

Register your phone number with VAPI and verify outbound calling works.

What you’ll need

  • A SignalWire account with at least one phone number ( sign up here)
  • A VAPI account with API access
  • Your VAPI private API key (found in your VAPI dashboard)
  • Access to SignalWire support for SIP domain app password generation

Setting up SignalWire for outbound calls

SignalWire needs to be configured to receive and route outbound call requests from VAPI. This involves creating a SWML script that handles the call routing and setting up a SIP address.

Create the outbound routing script

In your SignalWire dashboard, go to ResourcesAddScriptSWML Script. This script will handle outbound calls by connecting them through the PSTN:

version: 1.0.0
sections:
  main:
    - connect:
        answer_on_bridge: true
        from: +1A-Number-From-Your-Space-here
        to: '%{call.to.replace(/^sip:/i, '''').replace(/@.*/, '''')}'

Replace "+1A-Number-From-Your-Space-here" with an actual phone number from your SignalWire account. This will be the caller ID shown to people who receive calls from your VAPI assistant.

This SWML script uses the connect method with answer_on_bridge: true to ensure calls connect properly. The to field uses a regular expression to extract the phone number from VAPI’s SIP format and route it through the PSTN.

Add a SIP address to your script

After saving your SWML script, you’ll need to create a SIP address that VAPI can connect to:

  1. In your saved SWML script, navigate to the Addresses & Phone Numbers section
  2. Click Add and select SIP Address
  3. Configure the SIP address settings and save

After configuration, note down your unique SIP domain app. It will look something like: test-space-vapi.dapp.signalwire.com

Learn more about addresses in our Call Fabric Addresses documentation.

Important: To complete this setup, you must contact SignalWire Support to generate a password for your SIP domain app. VAPI needs this password for authentication.

Contact support by:

Provide your SIP domain app and let them know you need a password for VAPI integration.


Configuring VAPI for outbound calls

Now we’ll set up VAPI to make outbound calls through your SignalWire SIP domain app. This follows VAPI’s official SIP trunk setup guide, but with SignalWire-specific configuration.

Create the outbound SIP trunk

Run this API call to create the outbound trunk, making sure to replace the placeholder values with your actual configuration:

curl -X POST "https://api.vapi.ai/credential" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_VAPI_PRIVATE_KEY" \
  -d '{
    "provider": "byo-sip-trunk",
    "name": "SignalWire Outbound Trunk",
    "gateways": [{\
      "ip": "YOUR_SIGNALWIRE_SIP_DOMAIN",\
      "inboundEnabled": false\
    }],
    "outboundLeadingPlusEnabled": true,
    "outboundAuthenticationPlan": {
      "authUsername": "YOUR_SIGNALWIRE_PHONE_NUMBER",
      "authPassword": "YOUR_SIGNALWIRE_PASSWORD"
    }
  }'

Make sure to replace:

  • YOUR_VAPI_PRIVATE_KEY - Your VAPI API key
  • YOUR_SIGNALWIRE_SIP_DOMAIN - Your SIP domain app from the previous step (e.g., test-space-vapi.dapp.signalwire.com)
  • YOUR_SIGNALWIRE_PHONE_NUMBER - Your SignalWire phone number in E.164 format (e.g., +15551234567)
  • YOUR_SIGNALWIRE_PASSWORD - The password provided by SignalWire Support

Save the id from the response - you’ll need this credential ID for the next step.

Register your SignalWire phone number for outbound

Register your SignalWire phone number with VAPI for outbound calling using the credential ID from above:

curl -X POST "https://api.vapi.ai/phone-number" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_VAPI_PRIVATE_KEY" \
  -d '{
    "provider": "byo-phone-number",
    "name": "SignalWire Outbound Number",
    "number": "+15551234567",
    "numberE164CheckEnabled": true,
    "credentialId": "YOUR_CREDENTIAL_ID"
  }'

Replace:

  • YOUR_VAPI_PRIVATE_KEY - Your VAPI API key
  • +15551234567 - Your actual SignalWire phone number in E.164 format
  • YOUR_CREDENTIAL_ID - The credential ID from the trunk creation step

Assign your AI assistant for outbound calls

In your VAPI dashboard, find the phone number you just registered and assign it to one of your AI assistants. Configure the outbound settings to specify which assistant should handle outbound calls.

If you’ve already set up inbound calling with the same number, VAPI will indicate this is a duplicate number. This is completely normal and expected - you’re using the same phone number for both inbound and outbound calling with different configurations.


Testing your outbound setup

Your VAPI assistant can now make outbound calls through SignalWire. The calls will show your SignalWire phone number as the caller ID.

To test your setup, refer to VAPI’s official documentation on testing your SIP trunk for specific instructions on initiating outbound calls.


Troubleshooting

Authentication failures: Double-check that you’re using the correct SIP domain app password from SignalWire Support. The authentication username should be your phone number in E.164 format.

Calls not connecting: Verify your SWML script has the correct caller ID number and that it’s a valid number from your SignalWire account.

Domain app issues: Ensure your SIP domain app is properly configured in SignalWire and that VAPI can resolve the domain name.


What’s next

Now that you have outbound calling configured, you might want to explore:

Inbound Calling\ \ Complete your integration by setting up inbound calls from SignalWire to VAPI Advanced Call Flows\ \ Add call screening, business hours logic, or complex routing before outbound calls Assistant Optimization\ \ Best practices for creating effective VAPI assistants for outbound campaigns

SignalWire Developer Documentation