SignalWire Markup Language (SWML) lets you define call control and AI behavior in JSON or YAML, and SignalWire AI Gateway (SWAIG) lets your AI agent trigger backend functions during a live call. This tutorial shows how to let a SWAIG function execute SWML outside the model, so the agent can do real telephony actions reliably, such as sending Short Message Service (SMS) messages, recording a call, and transferring the caller, while keeping the conversational layer focused on intent and data collection.
Understanding SWML and SWAIG
SignalWire Markup Language (SWML) is a powerful markup language expressed in YAML or JSON for managing call flows and AI Agents. SignalWire AI Gateway (SWAIG) enables functions that allow an AI voice agent to perform actions or connect with backend systems.
SWAIG allows you to execute SWML blocks that exist outside of the AI language model. This capability enhances control over AI conversational flows, enabling more precise actions and responses after a function is triggered, and allowing you to build a highly customizable AI assistant.
Incorporated into SignalWire's broader ecosystem, these underlying technologies support SignalWire’s Programmable Unified Communications (PUC) network. PUC brings together a programmable interface with a unified communications platform, providing easy-to-use, customizable communication solutions.
SWML is an essential tool within the network for customizing communication pathways, collecting data, or invoking AI agents, pushing the boundaries of what conversational AI can achieve. For building a custom AI agent beyond the capabilities of pre-made examples, you’ll have to learn to execute SWML from within a SWAIG function.
How to leverage SWML from within a function
In this post, we'll take a closer look at the requirements for successfully executing a SWML block from within a function. By crafting a SWML script, we’ll create an example AI agent that helps callers with information about the U.S. National Park Service.
In this scenario, the virtual agent not only answers questions, but also sends text messages with information, and transfers calls to specific departments. This demonstrates the seamless integration of SWAIG functions within AI interactions.
The video above guides you through setting up an AI agent using SWML, detailing the configuration of key functions that are designed to enhance user assistance.
In this example, we will be making a GET request to the National Park Service API in one of the functions, but this is only for demonstration purposes. You can create an AI agent that is an expert in anything you can imagine.
Breaking down the execution: Params and functions
To begin, set up the prompt instructions for the agent. It's essential to configure the AI assistant to support SWML execution in its functions. This is done by setting the swaig_allow_swml parameter to true within the AI's parameters section.
copy
01
02
03
04
05
06
07
08
09
10
11
12
params:
swaig_allow_swml: true
copy
01
02
03
04
05
06
07
08
09
10
11
12
params:
swaig_allow_swml: true
copy
01
02
03
04
05
06
07
08
09
10
11
12
params:
swaig_allow_swml: true
copy
01
02
03
04
05
06
07
08
09
10
11
12
params:
swaig_allow_swml: true
park_alert_lookup function:
The park_alert_lookup function allows the AI agent, Laura, to access real-time alerts from the National Park Service API based on the caller’s query. In this function we use the data_map parameter, enabling AI agents to process user inputs, perform actions based on these inputs, or interact with external APIs seamlessly.
copy
01
02
03
04
05
06
07
08
09
10
11
12
data_map:
webhooks:
- require_args: query
error_keys: error
url: https://developer.nps.gov/api/v1/alerts?q=${lc:enc:args.query}
method: GET
headers:
X-Api-Key: "Your Rapid API Token Here" foreach:
input_key: data
output_key: alert_summary
max: 1 append: 'title: ${this.title} ${this.description}'
copy
01
02
03
04
05
06
07
08
09
10
11
12
data_map:
webhooks:
- require_args: query
error_keys: error
url: https://developer.nps.gov/api/v1/alerts?q=${lc:enc:args.query}
method: GET
headers:
X-Api-Key: "Your Rapid API Token Here" foreach:
input_key: data
output_key: alert_summary
max: 1 append: 'title: ${this.title} ${this.description}'
copy
01
02
03
04
05
06
07
08
09
10
11
12
data_map:
webhooks:
- require_args: query
error_keys: error
url: https://developer.nps.gov/api/v1/alerts?q=${lc:enc:args.query}
method: GET
headers:
X-Api-Key: "Your Rapid API Token Here" foreach:
input_key: data
output_key: alert_summary
max: 1 append: 'title: ${this.title} ${this.description}'
copy
01
02
03
04
05
06
07
08
09
10
11
12
data_map:
webhooks:
- require_args: query
error_keys: error
url: https://developer.nps.gov/api/v1/alerts?q=${lc:enc:args.query}
method: GET
headers:
X-Api-Key: "Your Rapid API Token Here" foreach:
input_key: data
output_key: alert_summary
max: 1 append: 'title: ${this.title} ${this.description}'
Output in park_alert_lookup:
After fetching and processing alerts, the function generates a response for our agent to disclose the top alert's title and description. It then asks the caller if they wish to receive this information via SMS.
copy
01
02
03
04
05
06
07
08
09
10
11
12
output:
response: |
If the alert summary is not empty, say the title and brief description of the top 1 alert to the user. Then, ask if they want to be texted with this info. ### Alerts Summary: ${alerts_summary} action:
- toggle_functions:
- active: true function
copy
01
02
03
04
05
06
07
08
09
10
11
12
output:
response: |
If the alert summary is not empty, say the title and brief description of the top 1 alert to the user. Then, ask if they want to be texted with this info. ### Alerts Summary: ${alerts_summary} action:
- toggle_functions:
- active: true function
copy
01
02
03
04
05
06
07
08
09
10
11
12
output:
response: |
If the alert summary is not empty, say the title and brief description of the top 1 alert to the user. Then, ask if they want to be texted with this info. ### Alerts Summary: ${alerts_summary} action:
- toggle_functions:
- active: true function
copy
01
02
03
04
05
06
07
08
09
10
11
12
output:
response: |
If the alert summary is not empty, say the title and brief description of the top 1 alert to the user. Then, ask if they want to be texted with this info. ### Alerts Summary: ${alerts_summary} action:
- toggle_functions:
- active: true function
The action parameter within the output is where a list of actions can be performed upon matching. In this case, we are enabling the send_sms function, which allows the AI agent to send an SMS to the caller.
The send_sms function
The send_sms function is tasked with sending text messages to the caller containing park alerts. Unlike the park_alert_lookup function, which uses webhooks to retrieve data from an external source, send_sms leverages data_map.expressions for handling data internally and preparing it for action based on the AI's inputs.
Using data_map.expressions in send_sms:
copy
01
02
03
04
05
06
07
08
09
10
11
12
data_map:
expressions:
- pattern: ".*" string: ".*" output:
response: "Sending alert to the user." action:
- SWML:
sections:
main:
- send_sms:
to_number: "${caller_id_num}" from_number: "+XXXXXXXXXX" body
copy
01
02
03
04
05
06
07
08
09
10
11
12
data_map:
expressions:
- pattern: ".*" string: ".*" output:
response: "Sending alert to the user." action:
- SWML:
sections:
main:
- send_sms:
to_number: "${caller_id_num}" from_number: "+XXXXXXXXXX" body
copy
01
02
03
04
05
06
07
08
09
10
11
12
data_map:
expressions:
- pattern: ".*" string: ".*" output:
response: "Sending alert to the user." action:
- SWML:
sections:
main:
- send_sms:
to_number: "${caller_id_num}" from_number: "+XXXXXXXXXX" body
copy
01
02
03
04
05
06
07
08
09
10
11
12
data_map:
expressions:
- pattern: ".*" string: ".*" output:
response: "Sending alert to the user." action:
- SWML:
sections:
main:
- send_sms:
to_number: "${caller_id_num}" from_number: "+XXXXXXXXXX" body
Here, data_map.expressions processes the alerts_summary data to generate the SMS content. The configuration ensures any provided alert summary is processed, enabling a versatile approach to data handling within the AI's workflow.
Implementing the SWML block in the transfer function
The transfer function demonstrates the use of a SWML block to carry out a series of actions, such as notifying a department of an incoming call, playing a message, recording the call, and transferring the call.
copy
01
02
03
04
05
06
07
08
09
10
11
12
- function: transfer
...
output:
response: "Initiating call transfer." action:
- SWML:
sections:
main:
- send_sms:
to_number: "+1XXXXXXXXXX" from_number: "+1XXXXXXXXXX" body: |-
Incoming call from ${caller_id_num}
- play: "This call will be recorded for training purposes."
- record_call:
beep: true format: mp3
- connect:
to: "+1XXXXXXXXXX"
- stop: true
copy
01
02
03
04
05
06
07
08
09
10
11
12
- function: transfer
...
output:
response: "Initiating call transfer." action:
- SWML:
sections:
main:
- send_sms:
to_number: "+1XXXXXXXXXX" from_number: "+1XXXXXXXXXX" body: |-
Incoming call from ${caller_id_num}
- play: "This call will be recorded for training purposes."
- record_call:
beep: true format: mp3
- connect:
to: "+1XXXXXXXXXX"
- stop: true
copy
01
02
03
04
05
06
07
08
09
10
11
12
- function: transfer
...
output:
response: "Initiating call transfer." action:
- SWML:
sections:
main:
- send_sms:
to_number: "+1XXXXXXXXXX" from_number: "+1XXXXXXXXXX" body: |-
Incoming call from ${caller_id_num}
- play: "This call will be recorded for training purposes."
- record_call:
beep: true format: mp3
- connect:
to: "+1XXXXXXXXXX"
- stop: true
copy
01
02
03
04
05
06
07
08
09
10
11
12
- function: transfer
...
output:
response: "Initiating call transfer." action:
- SWML:
sections:
main:
- send_sms:
to_number: "+1XXXXXXXXXX" from_number: "+1XXXXXXXXXX" body: |-
Incoming call from ${caller_id_num}
- play: "This call will be recorded for training purposes."
- record_call:
beep: true format: mp3
- connect:
to: "+1XXXXXXXXXX"
- stop: true
This exploration into the advanced features of SWML and SWAIG functions highlights the potential for creating dynamic, responsive, and intelligent AI agents that can meet a wide array of user needs. Whether it's providing detailed information, facilitating communications, or executing specific actions based on user input, the power of SWML from functions is a game-changer in the realm of conversational AI.
Full example
copy
01
02
03
04
05
06
07
08
09
10
11
12
version: 1.0.0sections:
main:
- ai:
prompt:
text: |-
Your name is Laura. You help the user learn more about the US's National Park Services. # Conversation Flow## Step 1 Introduce yourself in an enthusiastic way and ask if the caller has any
questions.
## Step 2 Answer all the questions the caller might have about the parks.## Step 3 If the caller asks about alerts in effect or closures, provide that info.## Step 4 Ask if the caller wants the alert to be sent to them as SMS. If yes, use the send_sms function to
send a message to their phone number with the alerts.
## Step 5 If the caller asks about reservations, use the 'transfer' function to connect
them to the reservations department.
post_prompt_url: https://webhook.site/yourWebhookHere
params:
swaig_allow_swml: true languages:
- name: English
code: en-US
voice: elevenlabs.dorothy
engine: elevenlabs
fillers:
- one moment please,
- let's see, SWAIG:
functions:
- function: park_alert_lookup
purpose: To look up alerts for a national park using a search term.
argument:
type: object
properties:
query:
type: string
description: the name or partial name of the national park to look up alerts for.
data_map:
webhooks:
- require_args: query
error_keys: error
url: https://developer.nps.gov/api/v1/alerts?q=${lc:enc:args.query}
method: GET
headers:
X-Api-Key: "Your Rapid API Token Here" foreach:
input_key: data
output_key: alert_summary
max: 1 append: 'title: ${this.title} ${this.description}' output:
response: |
If the alert summary is not empty, say the title and brief description of the top 1 alert to the user. Then, ask if they want to be texted with this info. ### Alerts Summary: ${alerts_summary} action:
- toggle_functions:
- active: true function: send_sms
- function: send_sms
active: "false" purpose: To send an SMS with the park alert to the caller.
argument:
type: object
properties:
alerts_summary:
type: string
description: The alert of the park requested by the user.
data_map:
expressions:
- pattern: ".*" string: ".*" output:
response: Send the alert to the user.
action:
- SWML:
sections:
main:
- send_sms:
to_number: "${caller_id_num}" from_number: "+1XXXXXXXXXX" body: |-
Hello, here is the National Park Service Alert you requested
today:${args.alerts_summary}
- function: transfer
purpose: Transfer to the reservations department
argument:
type: object
properties:
destination:
type: string
description: The destination to transfer to
data_map:
expressions:
- string: ${args.destination}
pattern: .*
output:
response: Transfer call.
action:
- SWML:
sections:
main:
- send_sms:
to_number: "+1XXXXXXXXXX" from_number: "+1XXXXXXXXXX" body: |-
Incoming call from ${caller_id_num}
- play: "say:This call will be recorded for training purposes!"
- record_call:
beep: true format: mp3
- connect:
to: "+1XXXXXXXXXX"
- stop
copy
01
02
03
04
05
06
07
08
09
10
11
12
version: 1.0.0sections:
main:
- ai:
prompt:
text: |-
Your name is Laura. You help the user learn more about the US's National Park Services. # Conversation Flow## Step 1 Introduce yourself in an enthusiastic way and ask if the caller has any
questions.
## Step 2 Answer all the questions the caller might have about the parks.## Step 3 If the caller asks about alerts in effect or closures, provide that info.## Step 4 Ask if the caller wants the alert to be sent to them as SMS. If yes, use the send_sms function to
send a message to their phone number with the alerts.
## Step 5 If the caller asks about reservations, use the 'transfer' function to connect
them to the reservations department.
post_prompt_url: https://webhook.site/yourWebhookHere
params:
swaig_allow_swml: true languages:
- name: English
code: en-US
voice: elevenlabs.dorothy
engine: elevenlabs
fillers:
- one moment please,
- let's see, SWAIG:
functions:
- function: park_alert_lookup
purpose: To look up alerts for a national park using a search term.
argument:
type: object
properties:
query:
type: string
description: the name or partial name of the national park to look up alerts for.
data_map:
webhooks:
- require_args: query
error_keys: error
url: https://developer.nps.gov/api/v1/alerts?q=${lc:enc:args.query}
method: GET
headers:
X-Api-Key: "Your Rapid API Token Here" foreach:
input_key: data
output_key: alert_summary
max: 1 append: 'title: ${this.title} ${this.description}' output:
response: |
If the alert summary is not empty, say the title and brief description of the top 1 alert to the user. Then, ask if they want to be texted with this info. ### Alerts Summary: ${alerts_summary} action:
- toggle_functions:
- active: true function: send_sms
- function: send_sms
active: "false" purpose: To send an SMS with the park alert to the caller.
argument:
type: object
properties:
alerts_summary:
type: string
description: The alert of the park requested by the user.
data_map:
expressions:
- pattern: ".*" string: ".*" output:
response: Send the alert to the user.
action:
- SWML:
sections:
main:
- send_sms:
to_number: "${caller_id_num}" from_number: "+1XXXXXXXXXX" body: |-
Hello, here is the National Park Service Alert you requested
today:${args.alerts_summary}
- function: transfer
purpose: Transfer to the reservations department
argument:
type: object
properties:
destination:
type: string
description: The destination to transfer to
data_map:
expressions:
- string: ${args.destination}
pattern: .*
output:
response: Transfer call.
action:
- SWML:
sections:
main:
- send_sms:
to_number: "+1XXXXXXXXXX" from_number: "+1XXXXXXXXXX" body: |-
Incoming call from ${caller_id_num}
- play: "say:This call will be recorded for training purposes!"
- record_call:
beep: true format: mp3
- connect:
to: "+1XXXXXXXXXX"
- stop
copy
01
02
03
04
05
06
07
08
09
10
11
12
version: 1.0.0sections:
main:
- ai:
prompt:
text: |-
Your name is Laura. You help the user learn more about the US's National Park Services. # Conversation Flow## Step 1 Introduce yourself in an enthusiastic way and ask if the caller has any
questions.
## Step 2 Answer all the questions the caller might have about the parks.## Step 3 If the caller asks about alerts in effect or closures, provide that info.## Step 4 Ask if the caller wants the alert to be sent to them as SMS. If yes, use the send_sms function to
send a message to their phone number with the alerts.
## Step 5 If the caller asks about reservations, use the 'transfer' function to connect
them to the reservations department.
post_prompt_url: https://webhook.site/yourWebhookHere
params:
swaig_allow_swml: true languages:
- name: English
code: en-US
voice: elevenlabs.dorothy
engine: elevenlabs
fillers:
- one moment please,
- let's see, SWAIG:
functions:
- function: park_alert_lookup
purpose: To look up alerts for a national park using a search term.
argument:
type: object
properties:
query:
type: string
description: the name or partial name of the national park to look up alerts for.
data_map:
webhooks:
- require_args: query
error_keys: error
url: https://developer.nps.gov/api/v1/alerts?q=${lc:enc:args.query}
method: GET
headers:
X-Api-Key: "Your Rapid API Token Here" foreach:
input_key: data
output_key: alert_summary
max: 1 append: 'title: ${this.title} ${this.description}' output:
response: |
If the alert summary is not empty, say the title and brief description of the top 1 alert to the user. Then, ask if they want to be texted with this info. ### Alerts Summary: ${alerts_summary} action:
- toggle_functions:
- active: true function: send_sms
- function: send_sms
active: "false" purpose: To send an SMS with the park alert to the caller.
argument:
type: object
properties:
alerts_summary:
type: string
description: The alert of the park requested by the user.
data_map:
expressions:
- pattern: ".*" string: ".*" output:
response: Send the alert to the user.
action:
- SWML:
sections:
main:
- send_sms:
to_number: "${caller_id_num}" from_number: "+1XXXXXXXXXX" body: |-
Hello, here is the National Park Service Alert you requested
today:${args.alerts_summary}
- function: transfer
purpose: Transfer to the reservations department
argument:
type: object
properties:
destination:
type: string
description: The destination to transfer to
data_map:
expressions:
- string: ${args.destination}
pattern: .*
output:
response: Transfer call.
action:
- SWML:
sections:
main:
- send_sms:
to_number: "+1XXXXXXXXXX" from_number: "+1XXXXXXXXXX" body: |-
Incoming call from ${caller_id_num}
- play: "say:This call will be recorded for training purposes!"
- record_call:
beep: true format: mp3
- connect:
to: "+1XXXXXXXXXX"
- stop
copy
01
02
03
04
05
06
07
08
09
10
11
12
version: 1.0.0sections:
main:
- ai:
prompt:
text: |-
Your name is Laura. You help the user learn more about the US's National Park Services. # Conversation Flow## Step 1 Introduce yourself in an enthusiastic way and ask if the caller has any
questions.
## Step 2 Answer all the questions the caller might have about the parks.## Step 3 If the caller asks about alerts in effect or closures, provide that info.## Step 4 Ask if the caller wants the alert to be sent to them as SMS. If yes, use the send_sms function to
send a message to their phone number with the alerts.
## Step 5 If the caller asks about reservations, use the 'transfer' function to connect
them to the reservations department.
post_prompt_url: https://webhook.site/yourWebhookHere
params:
swaig_allow_swml: true languages:
- name: English
code: en-US
voice: elevenlabs.dorothy
engine: elevenlabs
fillers:
- one moment please,
- let's see, SWAIG:
functions:
- function: park_alert_lookup
purpose: To look up alerts for a national park using a search term.
argument:
type: object
properties:
query:
type: string
description: the name or partial name of the national park to look up alerts for.
data_map:
webhooks:
- require_args: query
error_keys: error
url: https://developer.nps.gov/api/v1/alerts?q=${lc:enc:args.query}
method: GET
headers:
X-Api-Key: "Your Rapid API Token Here" foreach:
input_key: data
output_key: alert_summary
max: 1 append: 'title: ${this.title} ${this.description}' output:
response: |
If the alert summary is not empty, say the title and brief description of the top 1 alert to the user. Then, ask if they want to be texted with this info. ### Alerts Summary: ${alerts_summary} action:
- toggle_functions:
- active: true function: send_sms
- function: send_sms
active: "false" purpose: To send an SMS with the park alert to the caller.
argument:
type: object
properties:
alerts_summary:
type: string
description: The alert of the park requested by the user.
data_map:
expressions:
- pattern: ".*" string: ".*" output:
response: Send the alert to the user.
action:
- SWML:
sections:
main:
- send_sms:
to_number: "${caller_id_num}" from_number: "+1XXXXXXXXXX" body: |-
Hello, here is the National Park Service Alert you requested
today:${args.alerts_summary}
- function: transfer
purpose: Transfer to the reservations department
argument:
type: object
properties:
destination:
type: string
description: The destination to transfer to
data_map:
expressions:
- string: ${args.destination}
pattern: .*
output:
response: Transfer call.
action:
- SWML:
sections:
main:
- send_sms:
to_number: "+1XXXXXXXXXX" from_number: "+1XXXXXXXXXX" body: |-
Incoming call from ${caller_id_num}
- play: "say:This call will be recorded for training purposes!"
- record_call:
beep: true format: mp3
- connect:
to: "+1XXXXXXXXXX"
- stop
Lastly, don’t forget to configure your chosen phone number to handle a call using your SWML script!
With SWML's flexibility, there's no limit to how you can innovate and enhance the user experience for communications applications. Whether you're building a customer service bot or an informational guide, these tools are here to make your AI assistant smarter, and your life easier.
Start building for free today by signing up for a SignalWire Space, exploring our developer documentation, and bringing your questions to our community on Discord.
Frequently asked questions
What is SignalWire Markup Language (SWML)?
SignalWire Markup Language (SWML) is a markup format expressed in JSON or YAML for defining call flows and AI agent behavior, including telephony actions like prompts, recording, and transfers.
What is SignalWire AI Gateway (SWAIG)?
SignalWire AI Gateway (SWAIG) enables functions that an AI voice agent can call to perform actions or connect with backend systems during a conversation.
Why execute SWML from a SWAIG function instead of handling everything in the model?
Executing SWML from a function keeps telephony actions deterministic and auditable, while letting the AI focus on collecting intent and parameters. It also makes it easier to run sequences like notify, play a message, record, then transfer, without trying to “prompt” the model into perfect call control.
What does swaig_allow_swml do?
swaig_allow_swml is a configuration flag that enables SWML execution from within SWAIG functions, which is required if your function output will include a SWML block to run call control steps.
What is data_map, and why is it used in SWAIG functions?
data_map is used to process inputs and map values for a function so the agent can transform caller data, pass arguments cleanly, and integrate with external APIs, such as retrieving data from a third-party service.
What is a practical pattern for SWML in functions?
Use one function to look up information from an external API, another function to send an SMS follow-up, and a transfer function that executes a SWML block to play a message, start recording, and transfer the call to the right destination.