Appearance
Cxml Voice
FreshVoice Overview
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 cXML is a set of actions defined in an XML document you can use to tell SignalWire what to do when you receive an incoming call or instructions for outbound calls.
When a call is made to one of your SignalWire phone numbers, SignalWire looks up the SignalWire cXML document from the URL you configured and reads the instructions you provided to determine what to do.
SignalWire cXML allows you to dynamically control what happens, responding with specific instructions based on the caller, time of day, incoming call, and much more.
Not making a call? Check out Messaging XML for more details.
Request for XML
SignalWire makes an HTTP request to your configured endpoint just like a regular web form submission (POST) or page load (GET). The request includes contextual information about the call, allowing you to respond dynamically and fluidly to the call to meet the needs of your application.
You can configure the endpoint URL and HTTP Method in your phone number settings panel on your SignalWire Dashboard, or via the REST API.
Request parameters
SignalWire sends the following parameters, as either URL query parameters or POST parameters, to your endpoint when it receives a call:
AccountSid
string
The unique ID of the Account this call is associated with.
ApiVersion
string
The version of the SignalWire API. Incoming calls use the API version placed on the number called. Outgoing calls use the version of the REST API request.
CallSid
string
A unique identifier for the call.
CallStatus
string
The status of the call. Can be one of the following values: ringing, in-progress, queued, failed, busy, no-answer, or completed.
Direction
string
An identifier to describe the direction of the call: outbound-dial: calls launched through the <Dial> verb, outbound-api: calls launched through the REST API, inbound: for inbound calls.
From
string
The phone number that sent this call, in E.164 format.
ParentCallSid
string
A unique identifier for the call that created this call.
To
string
The phone number of the call recipient, in E.164 format.
CallStatus values
The following are the possible CallStatus parameter values. These are also used in <Dial>’s DialCallStatus:
| Value | |
|---|---|
ringing | The call is ringing. |
in-progress | The call was answered and is in progress. |
queued | The call is ready and in line to initiate. |
failed | The call could not be completed. Usually occurs when phone number does not exist. |
busy | The caller encountered a busy signal. |
no-answer | The call ended without an answer. |
completed | The call was answered and ended normally. |
canceled | The REST API canceled the call while it was ringing or queued. |
Responding to SignalWire
An example of a SignalWire cXML document that reads a message to the caller before playing an audio file:
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say>Hello, World!</Say>
<Play>https://your-application.com/audio.mp3</Play>
</Response>When a message comes into one of your SignalWire phone numbers, SignalWire makes an HTTP request to the URL endpoint you configured for that number. Your response to that request instructs SignalWire on what to do next.
Responses to the HTTP request are in SignalWire cXML. SignalWire starts at the top of your Compatibility XML document and executes your XML commands in order, from top to bottom.
SignalWire cXML verbs and their attributes are case-sensitive, so using <play>instead of <Play> will result in an error.
Status callbacks
SignalWire can send your application callbacks at various lifecycle stages of your call. Status callbacks do not allow you to change the application execution directly, so callbacks do not have to respond with SignalWire cXML, but they allow your application to get updates as a call is happening.
You should respond to any callbacks with a 200 OK or 204 No Content, otherwise you will see failures in your application log on SignalWire.
The StatusCallback request contains the Standard Request Parameters plus the following optional parameters:
AudioInMos
string
The mean opinion score that helps to determine audio quality. The scale is from 1-5 with 1 being worst and 5 being best.
CallbackSource
string
The source of the status callback.
CallDuration
integer
The duration, in seconds, of the finished call. Only present on the completed event.
CallerName
string
The name of the caller. Only available if Caller ID lookup is enabled.
ForwardedFrom
string
The number this call was forwarded from.
HangupBy
string
An indicator of which number ended the call.
HangupDirection
string
An indicator of which direction ended the call.
RecordingDuration
integer
The duration, in seconds, of the recording.
RecordingSid
string
The unique identifier for the audio recording.
RecordingUrl
string
The URL of the recorded audio call.
SequenceNumber
integer
The order in which events occur. Starts at 0. Although events are fired in order, they each take time and may not appear in the order you expect.
Timestamp
string
The timestamp, in RFC 2822 format, of when the event occurred.
Instructions
Instructions (verbs and nouns) tell SignalWire what actions to take during a call. They are executed sequentially, so one instruction must complete fully before the next one is executed. Some instructions have optional attributes that can override the flow of execution, allowing you to dynamically change what happens based on events within the call.
All instructions are case-sensitive, so calling <ThisAction> is different from calling <thisaction>.
Call actions
The following instructions cause the specified action to take place during the call:
Connect\ \ Connect a call to another resource like a video room or stream. Denoise\ \ Enable or disable noise reduction. Dial\ \ Initiate a call to another phone number. Echo\ \ Echo audio back to the call. Gather\ \ Collect input from the caller as pressed digits or speech. Pay\ \ Securely collect payment information during a call. Play\ \ Play an audio file in the call. Record\ \ Record and save the audio in the call. Say\ \ Read the supplied text into the call. Sms\ \ Send an SMS message during a call. Stream\ \ Stream a call to a websocket.
Call control
The following instructions control what happens to the call itself:
Enqueue\ \ Place the call into a queue. Hangup\ \ Disconnect the call. Leave\ \ Remove the call from the queue it is currently in. Pause\ \ Wait before continuing to execute further instructions. Redirect\ \ Stop executing the current document and start executing another. Refer\ \ Send SIP REFER to transfer the call from SignalWire control. Reject\ \ Decline an incoming call.
*Twilio and TwiML are trademarks of Twilio, Inc. SignalWire, Inc. and its products are not affiliated with or endorsed by Twilio, Inc.
Conference
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.
<Dial> verb’s <Conference> noun allows the connection to a named conference room. For example:
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial>
<Conference>Room 1234</Conference>
</Dial>
</Response>Noun attributes
beep
stringDefaults to true
Whether or not a sound is played when callers leave or enter a conference. See below for all possible values.
coach
string
Coach accepts a call SID of a call that is currently connected to an in-progress conference. Specifying a call SID that does not exist or is no longer connected to the conference will result in the call failing to the action URL and throwing a 13240 error.
endConferenceOnExit
booleanDefaults to false
If a participant with endConferenceOnExit set to true leaves a conference, the conference terminates and all participants drop out of the call.
eventCallbackUrl
string
The eventCallbackUrl attribute takes a URL as an argument and makes a POST request to it when a conference ends.
maxParticipants
integer
The maximum number of participants allowed in a named conference room.
muted
booleanDefaults to false
Whether or not a caller can speak in a conference.
record
stringDefaults to do-not-record
Can be used to record an entire <Conference>. record-from-start will begin recording the conference call once the first two participants join in on the call. Wait music is not recorded.
recordingStatusCallback
string
The recordingStatusCallback attribute takes in an absolute URL. SignalWire will make a GET or POST request to this URL when recording is accessible. See below for request parameters.
recordingStatusCallbackEvent
stringDefaults to completed failed
Specifies recording status changes. To specify multiple values, separate them by a space. See below for details.
recordingStatusCallbackMethod
stringDefaults to POST
The type of HTTP request to use when requesting a recordingStatusCallback.
startConferenceOnEnter
booleanDefaults to true
The conference begins once a specific caller enters into the conference room, unless it has already started. If a participant joins and startConferenceOnEnter is false, that participant will hear background music and stay muted until a participant with startConferenceOnEnter set to true joins the call.
statusCallback
string
The URL to make requests to for each statusCallbackEvent event. The URL is set by the first participant to enter a conference. All other information provided by other participants will be ignored. See below for request parameters.
statusCallbackEvent
string
Which conference state changes will trigger a webhook to the URL provided in statusCallback. Specifies conference state changes. The first participant to join the named conference is able to manipulate and set events. All other changes made by other participants will be ignored. See below for all possible events. To specify multiple events, separate them with a space.
statusCallbackMethod
stringDefaults to POST
The type of HTTP request to use when requesting a statusCallback.
trim
stringDefaults to trim-silence
Whether or not silence in the beginning and end of recordings are removed.
waitMethod
stringDefaults to POST
Specifies whether the request to waitUrl is a GET or a POST.
waitUrl
string
URL for the music to play in the background while participants are waiting to enter a conference room. Only supports <Play>, <Pause>, and <Redirect>. If no waitUrl is provided, SignalWire will use its hold music.
Values for the beep attribute
The beep attribute has the following values:
| Value | Description |
|---|---|
true | Plays a beep when a caller leaves or enters a conference. The default value for beep. |
false | Disables the beep when callers leave and enter conferences. |
onEnter | Only plays a beep when a caller enters a conference. |
onExit | Only plays a beep when a caller leaves a conference. |
Events for the statusCallbackEvent attribute
The statusCallbackEvent attribute has the following events:
| Event | Description |
|---|---|
start | The conference has started as long as there are at least two people in the conference room and one of the participant’s startConferenceOnEnter is set to true. |
end | The conference ends when the last participant in the call or a participant with endConferenceOnExit set to true leaves the call. |
join | When a participant joins a conference. |
leave | When a participant leaves a conference. |
mute | When a participant has been muted or un-muted. |
hold | When a participant has been put on hold or put out of hold. |
speaker | When a participant has begun or stopped speaking. |
Request parameters for the statusCallback URL
You can expect several parameters to be present in the request associated to the statusCallback URL. First, you have the Standard Request Parameters. Then, you also have the following specific parameters:
AccountSid
string
A unique identifier for the Account this call is associated with.
CallSid
string
A unique identifier for the call.
ConferenceSid
string
A unique identifier for the named Conference.
Duration
integer
The time, in seconds, of the conference call.
EndConferenceOnExit
string
When a participant has this set on true and they leave a call, conference ends.
EventName
string
The name of the event.
FriendlyName
string
Name of the conference.
Hold
string
Whether a participant is on hold or not.
Muted
string
Whether a participant is muted or not.
RecordingFileSize
string
The size of the recorded audio file.
RecordingUrl
string
The URL of the recorded audio file.
StartConferenceOnEnter
string
When a participant has this set on true and they join a call, conference begins.
StatusCallbackEvent
string
Conference state changes. Possible events are: conference-end, conference-start, participant-leave, participant-join, participant-mute, participant-unmute, participant-hold, participant-unhold, participant-speech-start, participant-speech-stop.
Timestamp
string
The timestamp, in RFC 2822 format, of when an event occurred.
Request parameters for the recordingStatusCallback URL
Status values for the recordingStatusCallbackEvent attribute
The recordingStatusCallbackEvent attribute has the following status values:
| Value | Description |
|---|---|
in-progress | The recording has begun. |
completed | The recording has completed and is accessible. |
failed | The recording is not accessible because of a failure. |
Examples
A simple conference call
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial>
<Conference>Room 1234</Conference>
</Dial>
</Response>The first participant would join the conference “Room 1234” and listen to wait music in the background until a second participant joins the conference. Once participants have joined the conference, the wait music comes to an end, a beep is played, and the conference call begins.
A moderated conference call
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial>
<Conference startConferenceOnEnter="false">
moderated-conference-room
</Conference>
</Dial>
</Response>You can set the startConferenceOnEnter to false so that a group of participants can join in the conference room but the conference cannot begin until the moderator has entered the call. As the participants wait for the conference to begin, hold music will be playing in the background.
Start a moderated conference call
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial>
<Conference startConferenceOnEnter="true" endConferenceOnExit="true">
moderated-conference-room
</Conference>
</Dial>
</Response>Now, since the moderator has joined in on the conference call, startConferenceOnEnter is set to true which means the conference can begin. All the participants that were waiting on hold will now be connected to the conference room; the hold music will come to an end and a beep notification will play indicating conference entrance. Once the moderator leaves the call, the conference will come to an end and all participants will be disconnected from the call.
Joining a conference call muted (Monitor)
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial>
<Conference muted="true">ConferenceRoom</Conference>
</Dial>
</Response>Participants who enter a conference call muted can hear the other participants in the call who are unmuted. However, the unmuted participants cannot hear the muted callers. Muting and unmuting can be enabled and disabled in real-time via a REST API.
Coaching a conference call
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial>
<Conference coach="AgentCallSid">
Example-Room
</Conference>
</Dial>
</Response>Recording a conference call
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial>
<Conference record="record-from-start"
recordingStatusCallback="https://www.example.com/recording_update">
ConferenceCall
</Conference>
</Dial>
</Response>The recording of the conference call will begin when at least two participants join the conference room. A recordingStatusCallback will be sent when the recording is accessible.
Notes on usage
- You can freely name the conference room to fit your preference. However, only callers within a project can join in on a named conference room. Callers from separate projects will not be able to connect to that same conference room.
- You can customize the background music as callers are waiting to join a conference call
- Conferences will not begin unless there are 2 or more parties present.
*Twilio and TwiML are trademarks of Twilio, Inc. SignalWire, Inc. and its products are not affiliated with or endorsed by Twilio, Inc.
Connect
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.
The <Connect> verb connects an existing call to another resource.
You can use the <Connect> verb with the following nouns:
| Noun | Description |
|---|---|
<Room> | A video room. |
<Stream> | A bidirectional stream. |
<VirtualAgent> | A Dialogflow virtual agent. |
Examples
A simple connect
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Connect>
<Room>my-room-name</Room>
</Connect>
</Response>Bidirectional media stream
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Connect>
<Stream url="wss://your-application.com/audiostream" />
</Connect>
</Response>Denoise
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.
The <Denoise> verb enables or disables noise reduction for call audio inbound to SignalWire. It reduces noise on calls before dialing into a conference or forwarding to another number.
Verb attributes
This verb does not accept attributes.
Nesting
No other verbs can be nested within <Denoise>.
Examples
Enable noise reduction
This example illustrates enabling noise reduction on an inbound phone call prior to forwarding the call.
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Denoise>on</Denoise>
<Dial><Sip>sip:user@example.com;transport=udp</Sip></Dial>
</Response>Disable noise reduction
This example illustrates disabling noise reduction prior to recording and transcribing.
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Denoise>off</Denoise>
<Record timeout="5" transcribe="true"/>
</Response>Dial
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.
The <Dial> verb connects an existing call to another phone number. <Dial> will end this new call if: the called number does not answer, the number does not exist, or SignalWire receives a busy signal.
You can use the <Dial> verb with the following nouns:
| Noun | |
|---|---|
<Conference> | A conference call between two or more callers. |
<Number> | A phone number with additional attributes. |
<Sip> | A SIP endpoint. |
<Verto> | A Verto client. |
<Queue> | A line for callers to wait in. The current call will be connected to the call at the front of the queue. |
Verb attributes
action
string
The action attribute takes in an absolute URL. SignalWire will make a GET or POST request to this URL after the dialed call ends. If no action is provided, SignalWire will continue to the next verb in the document. SignalWire will end the call if there are no more verbs following the <Dial> verb in the document. See below for request parameters.
answerOnBridge
booleanDefaults to false
If set to true, the inbound call will ring until the number that was dialed answers the call. If the inbound call is a SIP call, SignalWire will send a 180 or 183 to your SIP server as soon as it connects to SignalWire. When the <Dial> call is connected, a 200 will be sent.
callerId
string
The inbound caller’s phone number, which is displayed to the number that was dialed. The caller ID must be a valid E.164 number. Note that the number specified here must either be verified or purchased in the SignalWire Dashboard.
callerName
string
The caller name displayed for Sip calls. This should be an alphanumeric string. Limit is 70 characters.
hangupOnStar
booleanDefaults to false
The initiator of the call can hangup on the dialed number by using the * key.
method
stringDefaults to POST
The method attribute specifies whether the request to action is a GET or a POST. Valid values are GET or POST.
record
stringDefaults to do-not-record
The record attribute allows the ability to record both legs of a call. Recordings are available as mono-channel or dual-channel. See below for a detailed explanation of these channels.
recordingStatusCallback
string
The recordingStatusCallback attribute takes in an absolute or relative URL. SignalWire will make a GET or POST request to this URL when recording is available. See below for request parameters.
recordingStatusCallbackEvent
stringDefaults to completed
The different recording statuses. Possible values are completed, in-progress, and absent. To specify multiple events, separate with a space.
recordingStatusCallbackMethod
stringDefaults to POST
Whether the request to recordingStatusCallback URL is a GET or a POST.
recordingStorageUrl
string
The recordingStorageUrl attribute accepts an absolute URL as the destination to send a recording to, if you prefer to host your own recordings and bypass SignalWire storage. The recording files are in .wav format.
recordingStorageUrlMethod
stringDefaults to POST
Specifies which HTTP verb to use when sending the recording to the recordingStorageUrl. Available values are: POST and PUT.
recordingTrack
stringDefaults to both
Specifies whether to record the inbound audio to SignalWire from the called party or the outbound audio from SignalWire to the called party or both the inbound and outbound audio.
ringTone
string
The ability to change the ringback tone played to the caller when dialing a number. Default value is the ringback tone from the carrier. Available values are the following ISO 3166-1 alpha-2 country codes: at, au, bg, br, be, ch, cl, cn, cz, de, dk, ee, es, fi, fr, gr, hu, il, in, it, lt, jp, mx, my, nl, no, nz, ph, pl, pt, ru, se, sg, th, uk, us, us-old, tw, ve, za.
timeLimit
integerDefaults to 14400
Maximum duration, in seconds, for a <Dial>. Default value is 4 hours (14400 seconds).
timeout
integerDefaults to 30
The time, in seconds, that SignalWire will wait for a call to be answered before setting the status of the call to no-answer. Minimum value is 5 seconds and maximum value is 600 seconds. For some call flows, there may be a 5-second buffer added to the timeout value you provide.
trim
stringDefaults to do-not-trim
Whether silence in the beginning and end of recordings is removed. Use trim-silence to achieve this behavior.
Request parameters for the action URL
You can expect several parameters to be present in the request associated to the action URL. First, you have the Standard Request Parameters. Then, you also have the following specific parameters:
DialCallDuration
integer
The duration, in seconds, of the dialed call.
DialCallSid
string
The unique identifier of the new call leg.
DialCallStatus
string
The status of the dialed call attempt. See below for status values.
RecordingUrl
string
The URL of the recorded audio file. This parameter is only present if record is set on a <Dial>.
Values for DialCallStatus parameter
The DialCallStatus parameter of the action attribute can be one of the following values:
| Value | Description |
|---|---|
completed | The number that was dialed answered the call and was successfully connected to the caller. |
answered | When calling to a conference, the number that was dialed answered the call and was successfully connected to the caller. |
busy | SignalWire received a busy signal when connecting to the dialed number. |
no-answer | The number that was dialed did not answer the call in time. |
failed | SignalWire was unable to connect to the dialed number. This usually occurs when the dialed number does not exist. |
canceled | The call was canceled through a REST API before it was answered. |
Values for record parameter
The record attribute allows for recordings in mono-channel or dual-channel:
mono-channel: both legs of a call are combined into one channel in one recording file
- record-from-answer: starts the recording when the call is answered
- record-from-ringing: starts the recording when ringing begins
dual-channel: both legs of a call use separate channels in one recording file
- record-from-answer-dual: starts the recording when the call is answered
- record-from-ringing-dual: starts the recording when ringing begins
Request parameters for recordingStatusCallback
Examples
A simple dial
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial>123-456-7890</Dial>
</Response>If the dialed number answers the call, the two parties can talk to each other until one of them hangs up the phone.
Dial a number from a SignalWire client
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial callerId="+18007778899">
<Number>+18004445566</Number>
</Dial>
</Response>In order to dial from a SignalWire client, you need to make sure you are inputting a valid phone number. If the number in the callerID is not valid, the call will fail.
Mono-channel recording
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial record="record-from-ringing"
recordingStatusCallback="https://example.com/recording_status">
<Number>+10123456789</Number>
</Dial>
</Response>With mono-channel recording, each participant in the call will be recorded on the same channel. The recording will then be stored in a single recording file. Since we have set record to record-from-ringing, the recording will begin when the phone starts to ring.
Dual-channel recording for a conference call
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial record="record-from-ringing-dual"
recordingStatusCallback="https://example.com/recording_status">
<Conference>teamcall</Conference>
</Dial>
</Response>This example connects the caller to the conference call, teamcall. With dual-channel recording, each participant in the call will be recorded in a separate channel. The recording will then be stored in a single recording file. Since we have set record to record-from-ringing-dual, the recording will begin when the phone starts to ring.
*Twilio and TwiML are trademarks of Twilio, Inc. SignalWire, Inc. and its products are not affiliated with or endorsed by Twilio, Inc.
Echo
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.
The <Echo> verb will echo audio back to the call.
Verb attributes
timeout
integerDefaults to 60
The number of seconds SignalWire will echo, from 5 up to 120 seconds.
Nesting
No other verbs can be nested within <Echo>.
Examples
A simple echo test
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Echo timeout="120"/>
<Hangup/>
</Response>SignalWire answers calls and echoes what it hears for 2 minutes.
Enqueue
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.
The <Enqueue> verb places a call in a specified call queue. If the specified queue does not exist, a new queue will be created and the call will be placed into that new queue. Calls can be dequeued through the <Dial> verb or removed from the queue through the <Leave> verb.
Verb attributes
action
string
The action attribute takes an absolute URL. When a call leaves the queue, a request to this URL is made. If a call is dequeued through the <Leave> verb, the URL is immediately requested. If the call has been bridged to another party via the <Dial> verb, then the HTTP request is made only after both parties have disconnected. If action is not provided, SignalWire will continue reading the next verb in the document. See below for specified request parameters.
method
stringDefaults to POST
Specifies whether the redirect is a GET or a POST.
waitUrl
string
URL of the document to execute while the caller is in the queue. Default points to a playlist with classical music. waitUrl supports the following verbs: <Play>, <Say>, <Pause>, <Hangup>, <Redirect>, <Leave>, and <Gather>. See below for specified request parameters.
waitUrlMethod
stringDefaults to POST
Specifies whether the request to waitUrl is a GET or a POST.
Request parameters for the action URL
The action request contains the Standard Request Parameters as well as:
QueueResult
string
The result of the queued call. See below for all possible values.
QueueSid
string
The unique ID of the queue. Only available if a call is successfully placed into a queue.
QueueTime
string
The time a call was waiting in a queue. Only available if a call is successfully placed into a queue.
Values for parameter QueueResult
The parameter QueueResult has the following values:
| Value | Description |
|---|---|
bridged | The call was bridged and removed from the queue. |
bridging-in-progress | SignalWire is instructed to bridge the call. |
error | An error occurred either through the <Enqueue> verb or through the document retrieved from the waitUrl. |
hangup | The caller hung up while still in the queue. |
leave | The caller left the queue through the <Leave> verb. |
redirected | The call was redirected out of the queue, through a REST API request, while the caller was in the queue. |
redirected-from-bridged | The queued and bridged session was transferred out. |
queue-full | The queue was full, so the placement into the queue was not accepted. |
system-error | SignalWire had a malfunction while placing a call into a queue. |
Request parameters for waitUrl
The waitUrl request contains the Standard Request Parameters as well as:
AvgQueueTime
integer
The average time, in seconds, that callers have been waiting in a queue.
CurrentQueueSize
integer
The current number of callers in a queue.
QueuePosition
integer
The current position in the queue.
QueueSid
string
The unique ID of the queue a caller is in.
QueueTime
integer
The time a call was waiting in a queue.
Nouns
The noun of an XML verb is nested within the verb upon which the verb acts. <Enqueue> has the following nouns:
| Noun | Description |
|---|---|
plain text | The name of a specific queue. |
Nesting
No other verbs can be nested within <Enqueue> and you cannot nest
<Enqueue> within any other verbs.
Examples
A simple enqueue
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Enqueue waitUrl="https://example.com/hold-music.xml">support</Enqueue>
</Response>While a caller is in the queue, SignalWire retrieves the XML document ‘hold-music.xml’ and executes it.
Playing wait music
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Play>http://your-application.com/classical.mp3</Play>
</Response>While callers in a queue are waiting, classical music is played.
*Twilio and TwiML are trademarks of Twilio, Inc. SignalWire, Inc. and its products are not affiliated with or endorsed by Twilio, Inc.
Gather
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.
The <Gather> verb transcribes speech or collects digits during a call.
Verb attributes
action
string
The action attribute takes in an absolute URL. SignalWire will make a GET or POST request to this URL when entering of digits is completed. If there is no URL provided, SignalWire will re-request the URL that was previously used, which can cause an unwanted looping behavior. Be sure to provide the proper URL in order to avoid this outcome. See below for specified request parameters.
actionOnEmptyResult
booleanDefaults to false
Send a webhook to the action URL even if there is no input. By default, if no input is detected, the next XML instruction is executed but by setting actionOnEmptyResult to true, a callback to the action URL will be sent to continue call flow.
enhanced
booleanDefaults to false
This attribute enables enhanced speech recognition, which will incur an added cost. When it is false, speechModel has no effect.
finishOnKey
stringDefaults to #
The set of digits, (0-9, *, #), that can end a recording.
hints
string
A list of words and phrases, each a max of 100 characters, a caller is likely to say during a call.
input
stringDefaults to dtmf
The type of input received from a caller (i.e. speech or DTMF). Values can be dtmf, speech, or dtmf speech.
language
stringDefaults to en-US
The language in which you expect your callers to speak.
method
stringDefaults to POST
The method attribute specifies whether the request to action is a GET or a POST. Valid values are GET or POST.
numDigits
integer
The number of digits you expect to be pressed by a caller.
partialResultCallback
string
The URL to request to during speech recognition. No URL is specified by default.
partialResultCallbackMethod
stringDefaults to POST
The type of HTTP request to use when requesting a partialResultCallback.
profanityFilter
booleanDefaults to true
Tells SignalWire whether or not to filter profane language when transcribing a call.
speechModel
string
The model of enhanced speech recognition you would like to use. This attribute only has an effect if enhanced is true. Valid values are phone_call, video, or default. phone_call optimizes speech recognition for phone calls at a 8khz sample rate. video optimizes speech recognition for video calls at a 16khz sample rate. default will automatically choose the current best option between phone_call and video.
speechTimeout
string
The set time, in seconds, that SignalWire will wait before ending speech recognition. If set to auto, SignalWire will automatically end speech recognition when there is a pause in speech.
timeout
integerDefaults to 5
The number of seconds of silence or inaction that denote the end of caller input.
Supported languages
You can find a list of our supported languages here.
Request parameters for action URL
The action request contains the Standard Request Parameters as well as:
Confidence
string
The score, between 0.0 and 1.0, that determines the accuracy of a transcription.
Digits
string
The buttons pressed by a caller.
SpeechResult
string
The transcribed result of the caller’s speech.
Nesting
The following verbs can be nested within a <Gather>:
<Play>: plays an audio file, that SignalWire fetches from the URL you configured, back to the caller.<Pause>: waits silently for a distinctive number of seconds.<Say>: reads supplied text back to the caller.
Examples
Handle gathered input on your server
This example demonstrates a complete flow: the initial cXML prompts the caller for input, and your server handles the POST request to process Digits or SpeechResult and respond with appropriate cXML.
Request cXML
Server Handler (Node.js)
This cXML is served to SignalWire (e.g., as your webhook response). It prompts the caller for input and specifies your server’s action URL to handle the result.
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Gather input="speech dtmf" action="https://example.com/handle-gather" method="POST"
numDigits="1" hints="sales, support, billing" timeout="5" speechTimeout="auto">
<Say>
Press 1 or say sales for sales.
Press 2 or say support for technical support.
Press 3 or say billing for billing questions.
</Say>
</Gather>
<Say>We did not receive any input. Goodbye!</Say>
</Response>A simple gather
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Gather/>
</Response>SignalWire will collect any speech or digits pressed during a call.
Nesting <Say> within a gather
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Gather action="https://example.com/process_gather.php" method="GET">
<Say>
Please enter your account number,
followed by the pound sign.
</Say>
</Gather>
<Say>We did not receive any input. Goodbye!</Say>
</Response>You can use the <Say> verb to prompt callers to enter the desired input. In this example, when a caller enters their account number, SignalWire will submit the result to the URL provided in the action attribute. If the caller does not enter any digits, SignalWire will prompt the ‘Goodbye’ statement.
Nesting <Play> within a gather
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Gather action="https://example.com/process_gather.php" method="GET">
<Play>https://your-application.com/audio.mp3</Play>
</Gather>
<Say>We did not receive any input. Goodbye!</Say>
</Response>You can use the <Play> verb to prompt callers to enter the desired input. In this example, when a caller enters their account number, SignalWire will submit the result to the URL provided in the action attribute. If the caller does not enter any digits, SignalWire will prompt the ‘Goodbye’ statement.
Gather DTMF or speech
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Gather input="speech dtmf" timeout="5" numDigits="1">
<Say>Please press 3 or say account for account information.</Say>
</Gather>
</Response>A caller can access their account information either through speech recognition or DTMF tones. SignalWire will wait 5 seconds before processing the information and sending the data.
Potential issues
<Gather> doesn’t receive caller input when the caller is using a VoIP phone.
Solution: Some VoIP phones have trouble sending DTMF tones. Phones typically use compressed bandwidth-conserving audio protocols that can interfere with the transmission of the digit’s signal.
The Digits parameter is not sent to the <Gather> URL.
Solution: Verify that your application is not responding to the action URL with an HTTP 3xx redirect. SignalWire will follow this redirect but will not resend the Digits parameter.
*Twilio and TwiML are trademarks of Twilio, Inc. SignalWire, Inc. and its products are not affiliated with or endorsed by Twilio, Inc.
Hangup
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.
The <Hangup> verb ends a call. While <Reject>ed calls are never answered, calls that use the <Hangup> verb for disconnection are still answered, becoming subject to billing.
Verb attributes
The <Hangup> verb does not support any attributes.
Nesting
No other verbs can be nested within <Hangup> and you cannot nest <Hangup> within any other verbs.
Examples
A simple hangup
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Hangup/>
</Response>SignalWire will answer the call then immediately hangup.
*Twilio and TwiML are trademarks of Twilio, Inc. SignalWire, Inc. and its products are not affiliated with or endorsed by Twilio, Inc.
Leave
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.
The <Leave> verb transfers a call out of the queue containing that call. It then returns the flow of execution to verb following the <Enqueue> that placed this call into the queue.
Verb attributes
The <Leave> verb does not support any attributes.
Examples
Leaving a closed queue
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Enqueue waitUrl="https://example.com/wait.xml">support</Enqueue>
<Say>Customer support is now closed. Please call back on the next business day. Thank you.</Say>
</Response>Callers who are waiting in the queue for customer support will automatically be directed out of the queue after closing hours. SignalWire will notify these callers that they have left the queue and will have to try calling back another day.
Playing audio
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Play>http://your-application.com/music.mp3</Play>
</Response>SignalWire will play hold music for the callers in the queue until customer support hours are over.
Leave a call
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Leave />
</Response>wait.xml will dequeue the callers after closing hours and prompt the <Say> statement in the first example.
*Twilio and TwiML are trademarks of Twilio, Inc. SignalWire, Inc. and its products are not affiliated with or endorsed by Twilio, Inc.
Number
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.
<Dial> verb’s <Number> noun specifies what phone number to dial. You can use up to 10 <Number>s within a <Dial> to simultaneously call several people. The first person to answer the call will be connected to the caller and the rest of the called numbers will be hung up.
Noun attributes
method
stringDefaults to POST
The method attribute specifies whether the request to action is a GET or a POST. Valid values are GET or POST.
sendDigits
string
Play DTMF tones when a call is answered. Useful when dialing numbers with extensions. SignalWire will initially dial the main phone number, then send the DTMF tones for the extension when the automated system answers.
statusCallback
string
The URL to make requests to for each statusCallbackEvent event. See below for request parameters.
statusCallbackEvent
string
The current status of the call. The call moves from initiated to ringing when the phone starts ringing. It moves from ringing to answered when the phone call is answered. Finally, it moves from answered to completed when the call is terminated. The status will be set to completed through the following reasons: busy, canceled, completed, failed, or no-answer. To specify multiple events, separate each one with a space. See below for the different call statuses.
statusCallbackMethod
stringDefaults to POST
The type of HTTP request to use when requesting a statusCallback.
url
string
A specified URL for a document that runs on the callee’s end after the dialed number answers but before the call is connected. This allows the caller to provide information to the dialed number, giving them the opportunity to decline the call, before they answer the call.
Status values for the statusCallbackEvent attribute
The statusCallbackEvent attribute has the following call status values:
| Value | Description |
|---|---|
initiated | Dialing of a call has begun. |
ringing | The call has begun ringing. |
answered | The call has been answered. |
completed | The call has been terminated. The status will be set to completed through the following reasons: busy, canceled, completed, failed, or no-answer. |
Request parameters for the statusCallback URL
Examples
Dialing an extension
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial>
<Number sendDigits="www5645">
123-456-7890
</Number>
</Dial>
</Response>After entering the phone number, we want to wait a little before entering in the extension. In order to do this, a w can be placed in front of the extension number. Each w will wait 0.5 seconds before dialing the extension. In this example, SignalWire will wait 1.5 seconds before dialing the extension 5645.
Concurrent phone calls
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial>
<Number>123-456-7890</Number>
<Number>987-654-3210</Number>
<Number>102-938-4750</Number>
</Dial>
</Response>You can simultaneously call up to 10 <Number>s. The first caller to pick up the phone will be connected to the caller and the rest of the called numbers will be hung up.
Notes on usage
- You can have up to 10
<Number>s within a<Dial>. - If you dial an office number or a phone on airplane mode, the call will be picked up within the first ring and all other calls will be hung up.
*Twilio and TwiML are trademarks of Twilio, Inc. SignalWire, Inc. and its products are not affiliated with or endorsed by Twilio, Inc.
Pause
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.
The <Pause> verb waits silently for a distinctive number of seconds.
Verb attributes
length
integerDefaults to 1
The number of seconds SignalWire will pause silently before moving on.
Nesting
No other verbs can be nested within <Pause>. However, <Pause> can be nested within a <Gather>.
Examples
A simple pause
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say>Please wait one moment while I check that for you.</Say>
<Pause length="8"/>
<Say>Yes, we are open Monday through Friday.</Say>
</Response>This illustrates the wait time between two statements.
Delaying a response
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Pause length="3"/>
<Say>Hello, how can I help you?</Say>
</Response>SignalWire waits 3 seconds before answering a call.
*Twilio and TwiML are trademarks of Twilio, Inc. SignalWire, Inc. and its products are not affiliated with or endorsed by Twilio, Inc.
Pay
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
The <Pay> verb enables secure payment processing during voice calls. When implemented in your voice application, it handles the complete payment flow including data collection, validation, and processing through your configured payment gateway.
The <Pay> verb also has two nouns that are embedded within it:
<Parameter>: Pass custom parameters to your payment processor.<Prompt>: Customize the prompts used during payment collection.
Core functionality
- Secure payment information collection
- Real-time payment processing
- Payment method tokenization
- Multi-currency support
- Automated retry handling
- Status tracking via webhooks
Transaction types
The <Pay> verb supports two primary transaction types: immediate charges and tokenization.
Immediate charges
When you need to process a payment right away, use an immediate charge transaction. This collects the payment details and processes the transaction in one step.
To execute an immediate charge:
<Pay chargeAmount="25.00"/>Setting any positive value for chargeAmount initiates an immediate charge transaction.
Tokenization
Tokenization allows you to securely store payment information for future use. Instead of processing a payment, it generates a secure token that represents the payment method. This is particularly useful for:
- Subscription services
- Recurring billing
To tokenize payment information:
<Pay chargeAmount="0"/>You can also omit the chargeAmount attribute entirely:
The actual token is provided & stored by your payment processor, which can be used for future transactions without requiring customers
to re-enter their payment details. This may differ depending on the payment processor you are using.
Attributes
minPostalCodeLength
integerRequired
Minimum required length for postal code input. Used for input validation.
paymentConnectorUrl
stringRequired
The URL to which to POST the encrypted payment data.
securityCode
booleanDefaults to trueRequired
Controls whether CVV/security code collection is required. When false, skips security code collection.
action
string
HTTPS endpoint that receives POST requests after payment completion. Must be HTTPS. Response determines next cXML instructions. For tokenization, receives PaymentToken and ProfileId. For charges, receives PaymentConfirmationCode. Defaults to the current cXML document URL.
chargeAmount
decimal
Amount to charge. Set to 0 or omit for tokenization only. Must be between 0 and 1,000,000.
currency
stringDefaults to usd
Three-letter currency code (e.g., usd, eur, gbp). Must be supported by selected payment connector. Currently only usd is accepted.
description
string
Transaction description passed to payment processor. Appears in transaction records.
input
stringDefaults to dtmf
The only supported input method for payment data collection. All captured digits are automatically redacted in logs.
language
stringDefaults to en-us
Controls prompt language. Supports en-AU, en-CA, en-GB, en-IN, en-US for all payments. Additional es-ES, es-MX, fr-CA, fr-FR, de-DE, it-IT for credit card only. See language list.
maxAttempts
integerDefaults to 1
Maximum number of retry attempts when timeout occurs or invalid data is received. Allowed values are 1, 2, or 3. Payment flow terminates after maxAttempts is reached.
paymentMethod
stringDefaults to credit-card
Determines payment collection flow. Credit card flow captures card number, expiration, security code, and postal code. ACH flow captures routing and account numbers.
postalCode
string | booleanDefaults to true
Controls postal code collection. When false, skips collection for postal code. When true, prompts the user for collection. When a String value, uses provided value without needing to collect the postal code from the user.
statusCallback
string
HTTPS endpoint that receives real-time payment status updates via POST requests. Includes details about current payment stage, errors, and attempt counts. See Status Callback Parameters for more details.
timeout
integerDefaults to 5
Number of seconds to wait for the next digit input before timing out. Must be a positive integer greater than 3 seconds. Applies to all input collection stages.
tokenType
stringDefaults to reusable
Determines token persistence. Allowed values are one-time or reusable. One-time for single use, reusable for recurring use. Payment-method specific to certain processors.
validCardTypes
stringDefaults to visa mastercard amex
Space-separated list of accepted card types. Validates card number against specified types. Allowed values: visa, mastercard, amex, maestro, discover, optima, jcb, diners-club, enroute.
Webhook request parameters
paymentConnectorUrl request parameters
When a transaction is completed, SignalWire will POST to your paymentConnectorUrl URL. Based on the transaction type, the body of the request will contain the below parameters:
Response from paymentConnectorUrl
A valid response from your paymentConnectorUrl must be provided to indicate the success or failure of the transaction. More information can be found in the Webhook Response section.
Standard Credit Card Payment
Tokenized Credit Card Payment
cardnumber
string
Customer’s credit card number.
chargeAmount
decimal
Amount to charge.
currency_code
string
Three-letter currency code.
cvv
string
Card security code.
description
string
Transaction description.
expiry_month
string
Card expiration month (2 digits).
expiry_year
string
Card expiration year (2 digits).
method
string
Payment method (credit-card).
parameters
object
Custom key-value parameters.
postal_code
string
Billing postal code.
transaction_id
string
Unique identifier for the transaction.
Example
{
"transaction_id":"id",
"method":"credit-card",
"cardnumber":"1234123412341234",
"cvv":"123",
"postal_code":"12345",
"description":"renew plan",
"chargeAmount":123.45,
"expiry_month":"01",
"expiry_year":"38",
"currency_code":"USD",
"parameters":{
"custom1":"value1"
}
}action request parameters
When a transaction is completed, SignalWire will POST to your action URL. The body of the request will contain the standard request parameters as well as the following parameters:
Response from action URL
A valid cXML response must be provided if the action URL is provided. More information can be found in the Webhook Response section.
BankAccountNumber
string
Masked bank account number.
BankRoutingNumber
string
Bank routing number.
ConnectorError
string
Raw processor error details.
ExpirationDate
string
Card expiration in MMYY format.
PayErrorCode
string
Numeric error reference.
PaymentCardNumber
string
Masked card number (last 4 digits visible).
PaymentCardPostalCode
string
Postal code provided.
PaymentCardType
string
Card brand (visa, mastercard, etc.).
PaymentConfirmationCode
string
Transaction confirmation code.
PaymentError
string
Detailed error information.
PaymentMethod
string
Type of payment method used.
PaymentToken
string
Tokenized payment method reference.
ProfileId
string
Customer profile identifier from payment processor.
Result
string
Final outcome of the payment attempt. The possible values can be seen in the Result Values table.
SecurityCode
string
Masked security code.
Result values
| Value | Description |
|---|---|
success | Payment processed successfully |
too-many-failed-attempts | Maximum retry attempts reached |
payment-connector-error | Gateway communication failure |
caller-interrupted-with-star | User canceled with * key |
caller-hung-up | Call terminated by user |
validation-error | Invalid parameter provided |
internal-error | System processing error |
statusCallback request parameters
When a status change occurs, the following parameters are sent to your statusCallback URL:
Attempt
integer
Current attempt number.
ErrorType
string
Specifies the nature of the error encountered (if any). Refer to the table below for detailed error type descriptions. The possible values can be seen in the Error Types table.
ExpirationDate
string
Card expiration date.
For
string
Indicates the present phase of the <Pay> request. The table below outlines the potential values. Possible values can be seen in the For Values table.
PaymentCardNumber
string
Masked card number.
PaymentCardPostalCode
string
Postal code provided.
PaymentCardType
string
Type of card provided.
PaymentMethod
string
Type of payment being processed.
SecurityCode
string
Masked security code.
Status callback events
| Event | Description |
|---|---|
payment-card-number | Collecting card number |
expiration-date | Collecting expiration date |
security-code | Collecting CVV/security code |
postal-code | Collecting postal code |
bank-routing-number | Collecting routing number |
bank-account-number | Collecting account number |
payment-processing | Processing transaction |
For values
| Value | Description |
|---|---|
payment-card-number | Requesting the customer’s credit or debit card details |
expiration-date | Requesting the expiration date of the customer’s payment card |
security-code | Requesting the security code (CVV) of the customer’s payment card |
postal-code | Requesting the postal code linked to the customer’s payment card |
payment-processing | Executing the payment transaction |
Error types
| Error | Description |
|---|---|
input-timeout | User input timeout |
invalid-card-number | Failed card validation |
invalid-card-type | Unsupported card type |
invalid-date | Invalid expiration date |
invalid-security-code | Invalid CVV format |
invalid-postal-code | Invalid postal code format |
invalid-bank-routing-number | Invalid routing number |
invalid-bank-account-number | Invalid account number |
session-in-progress | Concurrent session attempt |
Webhook response
paymentConnectorUrl response
The response from your paymentConnectorUrl is used to inform if the transaction was successful or not.
Successful transaction
When a transaction is successful, the webhook should respond with one of the following formats (depending on the transaction type):
Successful Standard Credit Card PaymentSuccessful Tokenized Credit Card Payment
{
"charge_id":"charge_id",
"error_code":null,
"error_message":null
}Unsuccessful transaction
When a transaction is unsuccessful (declined by the payment processor), the webhook should respond with the following format:
Declined Standard Credit Card PaymentDeclined Tokenized Credit Card Payment
{
"charge_id": null,
"error_code": "some error code",
"error_message": "some error message"
}action response
When a transaction is completed, SignalWire will POST to your action URL. The response should return valid cXML for the next step in your application.
Example
<Response>
<Say>Thank you for your payment. Your transaction has been completed.</Say>
<Hangup/>
</Response>Language support
The language attribute controls the language of automated prompts during payment collection.
You can customize prompt messages in any language using the <Prompt> noun, regardless of the selected language attribute.
Credit card payments
All credit card payments support the following languages:
English variants
- en-AU (Australian English)
- en-CA (Canadian English)
- en-GB (British English)
- en-IN (Indian English)
- en-US (American English)
Additional languages
- es-ES (European Spanish)
- es-MX (Mexican Spanish)
- fr-CA (Canadian French)
- fr-FR (European French)
- de-DE (German)
- it-IT (Italian)
Examples
Simple payment collection:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say>Please enter your payment information</Say>
<Pay chargeAmount="20.45"/>
</Response>Payment with status tracking:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say>Please enter your payment information</Say>
<Pay
chargeAmount="20.45"
action="https://your-callback-url.example.com/pay"
statusCallback="https://your-callback-url.example.com/status"
/>
</Response>Basic tokenization:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say>Please enter your card information to save for future use</Say>
<Pay
tokenType="reusable"
chargeAmount="0"
/>
</Response>Tokenization with validation:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say>Please enter your card information</Say>
<Pay
tokenType="reusable"
chargeAmount="0"
validCardTypes="visa mastercard"
securityCode="true"
postalCode="true"
/>
</Response>Custom retry logic:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say>Please enter your payment information</Say>
<Pay
chargeAmount="75.00"
maxAttempts="3"
timeout="10"
/>
</Response>International payment:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say>Por favor, ingrese su información de pago</Say>
<Pay
chargeAmount="100.00"
currency="mxn"
language="es-MX"
description="Mexican peso transaction"
/>
</Response>Example with custom parameters and prompts
<Response>
<Pay chargeAmount="123.45" paymentConnectorUrl="https://example.com/accept-payment" description="renew plan">
<Parameter name="custom1" value="value1"/>
<Prompt name="payment-card-number" attempt="1"><Say>Let's collect your payment information. Please enter your credit card number</Say></Prompt>
<Prompt name="payment-card-number" attempt="2 3"><Say>Please enter your credit card number</Say></Prompt>
<Prompt for="security-code" cardType="amex"><Say>Please enter your credit card’s security code. It's the 4 digits located on the front of your card. </Say></Prompt>
</Pay>
</Pay>
</Response>Security best practices
- Always use HTTPS for callback URLs
- Implement webhook validation
- Monitor payment status callbacks
- Handle errors gracefully
- Store tokens securely
- Use appropriate timeout values
- Implement proper error handling
- Validate all inputs
- Monitor transaction patterns
- Keep payment connector configurations secure
Parameter
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.
The <Parameter> noun within the <Pay> verb enables you to:
- Pass custom parameters to your payment processor when using a Generic Pay Connector
- Include additional ACH payment details not covered by the standard
<Pay>verb attributes
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
namerequired | string | - | The identifier for your custom parameter. |
valuerequired | string | - | The value associated with the parameter name. |
Examples
Adding custom parameters for generic transaction
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Pay chargeAmount="10.00" paymentConnector="https://example/signalwire/parameter/pay" action="https://example/signalwire/parameter/pay/action">
<Parameter name="my_custom_parameter_1" value="my_custom_value_1" />
</Pay>
</Response>Prompt
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.
The <Prompt> noun allows you to customize the default prompts used by <Pay>.
When SignalWire executes <Pay> CXML instructions without <Prompt>, the caller will hear default prompts for each step of the payment process. You can modify what the caller hears for a given payment step by nesting <Prompt> within <Pay>’s opening and closing tags.
You can customize prompts using either:
- Text-to-speech by nesting
<Say>CXML within<Prompt> - Pre-recorded audio by nesting
<Play>CXML within<Prompt>
Payment steps
There are seven payment steps in the <Pay> process where prompts can be customized (see the for attribute section below). Each step that you wish to customize requires its own <Prompt> element.
Attributes
for
stringRequired
Specifies which payment step’s prompt you wish to customize. Allowed values: payment-card-number, expiration-date, security-code, postal-code, bank-routing-number, bank-account-number, payment-processing. See Payment Steps for details.
attempt
integer
Specifies which attempt number this prompt should be used for. Value from 1 to 10. Useful for providing more detailed instructions after failed attempts.
cardType
string
Space-separated list of card types. Allows customization of prompts for specific card types (e.g., different security code lengths). Allowed values: visa, mastercard, amex, maestro, discover, optima, jcb, diners-club, enroute.
errorType
string
Space-separated list of error types. Customize error messages for specific failure scenarios. Allowed values: timeout, invalid-card-number, invalid-card-type, invalid-date, invalid-security-code, invalid-bank-routing-number, invalid-bank-account-number, input-matching-failed.
Payment step
Specifies which payment step’s prompt you wish to customize:
| Payment Step | Description |
|---|---|
payment-card-number | Prompt for credit/debit card number |
expiration-date | Prompt for card expiration date |
security-code | Prompt for card security code (CVV) |
postal-code | Prompt for billing postal code |
bank-routing-number | Prompt for bank routing number |
bank-account-number | Prompt for bank account number |
payment-processing | Message during payment processing |
Examples
Prompt for card number with TTS
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Pay>
<Prompt for="payment-card-number">
<Say>Please enter your 16 digit Visa or Mastercard number.</Say>
</Prompt>
</Pay>
</Response>Prompt for card number with MP3
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Pay>
<Prompt for="payment-card-number">
<Play>https://example.com/signalwire/cxml/audio/card_number.mp3</Play>
</Prompt>
</Pay>
</Response>Full transaction example
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Pay paymentMethod="credit-card" validCardTypes="visa mastercard amex">
<Prompt for="payment-card-number">
<Say>Welcome! To begin, enter the credit card number you'd like to use for payment.</Say>
</Prompt>
<Prompt for="payment-card-number" errorType="timeout">
<Say>I haven't received your card number yet. Please take a moment to enter your credit card number now.</Say>
</Prompt>
<Prompt for="payment-card-number" errorType="invalid-card-number">
<Say>That card number doesn't appear to be valid. Let's try entering it one more time.</Say>
</Prompt>
<Prompt for="payment-card-number" errorType="invalid-card-type">
<Say>We can only accept Visa, MasterCard, or American Express cards. Please enter a card number from one of these providers.</Say>
</Prompt>
<Prompt for="expiration-date">
<Say>Great! Now enter your card's expiration date using two digits for the month followed by two digits for the year.</Say>
</Prompt>
<Prompt for="expiration-date" errorType="timeout">
<Say>I still need your card's expiration date. Please enter two digits for the month, then two digits for the year.</Say>
</Prompt>
<Prompt for="expiration-date" errorType="invalid-date">
<Say>That expiration date isn't valid. Remember to use two digits each for month and year - for example, March 2025 would be 0 3 2 5.</Say>
</Prompt>
<Prompt for="security-code" cardType="visa mastercard">
<Say>Now for the security code - you'll find three digits on the back of your card.</Say>
</Prompt>
<Prompt for="security-code" errorType="timeout" cardType="visa mastercard">
<Say>I'm waiting for your three-digit security code. You can find it on the back of your card.</Say>
</Prompt>
<Prompt for="security-code" errorType="invalid-security-code" cardType="visa mastercard">
<Say>That security code wasn't quite right. Please enter all three digits from the back of your card.</Say>
</Prompt>
<Prompt for="security-code" cardType="amex">
<Say>For American Express, please enter the four-digit security code from the front of your card.</Say>
</Prompt>
<Prompt for="security-code" errorType="timeout" cardType="amex">
<Say>I still need the four-digit security code from the front of your American Express card.</Say>
</Prompt>
<Prompt for="security-code" errorType="invalid-security-code" cardType="amex">
<Say>That security code wasn't valid. Please enter all four digits from the front of your American Express card.</Say>
</Prompt>
<Prompt for="postal-code">
<Say>Almost done! Please enter the five-digit zip code for your billing address.</Say>
</Prompt>
<Prompt for="postal-code" errorType="timeout">
<Say>We still need your billing zip code. Please enter all five digits now.</Say>
</Prompt>
<Prompt for="payment-processing">
<Say>Perfect! Just a moment while we securely process your payment.</Say>
</Prompt>
</Pay>
</Response>Play
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.
The <Play> verb plays an audio file, which SignalWire fetches from the URL you configured, back to the caller.
An example of an audio file set to loop 15 times:
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Play loop="15">https://your-application.com/audio.mp3</Play>
</Response>An example which plays an RTMP stream into the call:
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Play loop="15">rtmp://example.com:1935/my-rtmp-stream</Play>
</Response>Verb attributes
digits
string
The digits attribute allows you to play DTMF tones throughout a call. If pauses are required in between your DTMF tones, the character w can be used. w adds a pause of 0.5 seconds for each occurrence, so www would render a pause of 1.5 seconds. Note that this attribute simply plays tones into a call. To enter an extension when making a call, use the sendDigits attribute for the noun <Number> of the verb <Dial>.
loop
integerDefaults to 1
The loop attribute determines how many times an audio file is played. If loop is set to 0, <Play> will continue looping until the call has ended.
Nouns
The noun of an XML verb is nested within the verb upon which the verb acts. <Play> has the following noun:
| Noun | Description |
|---|---|
plain text | The URL of the audio file that will be played to the caller. Supported protocols are HTTP and RTMP. |
MIME types
The following are the MIME types supported by SignalWire:
| Type | Description |
|---|---|
audio/mpeg | mpeg layer 3 audio |
audio/wav | wav format audio |
audio/wave | wav format audio |
audio/x-wav | wav format audio |
audio/aiff | audio interchange file format |
audio/x-aifc | audio interchange file format |
audio/x-aiff | audio interchange file format |
audio/x-gsm | GSM audio format |
audio/gsm | GSM audio format |
audio/ulaw | μ-law audio format |
Nesting
No other verbs can be nested within <Play>. However, <Play> can be nested within <Gather>. In this case, the verb attribute digits is not supported.
Examples
Play a simple audio file
Node.jsC#PythonRuby
const { RestClient } = require("@signalwire/compatibility-api");
const response = new RestClient.LaML.VoiceResponse();
response.play("https://your-application.com/audio.mp3");
console.log(response.toString());The simplest case for <Play>: SignalWire downloads the specified audio file and plays it to the caller.
Use DTMF tones in calls
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Play digits="wwwww9"></Play>
</Response>As described in the attributes section, the character w produces a 0.5 second pause. In this example, SignalWire will wait 2.5 seconds before playing the digit ‘9’.
Notes on usage
- Audio files that are longer than 40 minutes should be split into smaller files, as it may result in a dropped call.
- Since it takes some time to download and cache files from your server, slight delays may occur the first time an audio file is played. In this case, SignalWire may play a tone during download.
- SignalWire attempts to cache files only when allowed by HTTP headers (ETag and Last-Modified). Always check for a new version of the file with a response of
Cache-Control: no-cache. This enables your server to respond with a new version, or with a ‘304 Not Modified’, which tells SignalWire to use the cached version. - The degradation that occurs when transcoding high bitrate, lossy encoded files, such as 128kbps MP3 files, can take a long time, resulting in audio that sounds worse than those in lossless 8kbps formats.
- SignalWire transcodes all audio files into a format that is identifiable by the telephone network. Telephones typically do not support high bitrate audio, so playback results in lower-quality audio.
*Twilio and TwiML are trademarks of Twilio, Inc. SignalWire, Inc. and its products are not affiliated with or endorsed by Twilio, Inc.
Queue
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.
<Dial> verb’s <Queue> noun specifies what queue to dial.
Noun attributes
method
stringDefaults to POST
The method attribute specifies whether the request to action is a GET or a POST. Valid values are GET or POST.
url
string
A specified URL for a document that runs on the caller’s end before the call is connected. This allows the caller to inform the dialed number that the call will be connected to an agent or that the call may be monitored or recorded. See below for request parameters.
Request parameters for url
The url request contains the Standard Request Parameters as well as:
CallSid
string
The unique identifier for the dequeued call.
DequeingCallSid
string
The unique identifier for the call dequeueing the caller.
QueueSid
string
The unique identifier for the Queue.
QueueTime
string
The time, in seconds, spent waiting in a queue.
Examples
Dialing a queue
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial>
<Queue url="https://example.com/about_to_connect.xml">support</Queue>
</Dial>
</Response>This is an example of a caller in the ‘support’ queue waiting to be dequeued.
Bridging out of a queue
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say>You will now be connected to an agent.</Say>
</Response>Once a caller is first in line in the queue and ready to be bridged, they will be informed of the connection to an agent.
*Twilio and TwiML are trademarks of Twilio, Inc. SignalWire, Inc. and its products are not affiliated with or endorsed by Twilio, Inc.
Record
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.
The <Record> verb creates an audio file with the caller’s voice and returns the URL to you. Text transcriptions of these recorded calls can also be produced.
Recordings remain stored indefinitely. To delete a recording, use the appropriate API call from the Compatibility API.
Any instructions placed after the <Record> verb will not be executed. To ensure additional instructions are processed, use the action attribute to specify a URL that SignalWire will request once the recording is complete.
Verb attributes
action
string
The action attribute takes in an absolute or relative URL. SignalWire will make a GET or POST request to this URL when recording is completed. The current document’s URL will be requested if no action is provided which can lead to unwanted looping behavior if you’re not careful. See below for specified request parameters.
finishOnKey
string
The set of digits, (0-9, *, #), that can end a recording.
maxLength
integer
The maximum length, in seconds, of the recording. A value of zero means 3600 seconds.
method
stringDefaults to POST
The method attribute specifies whether the request to action is a GET or a POST. Valid values are GET or POST.
playBeep
booleanDefaults to true
Whether or not a sound is played before the start of a recording.
recordingStatusCallback
string
The recordingStatusCallback attribute takes in an absolute or relative URL. SignalWire will make a GET or POST request to this URL when recording is accessible. See below for specified request parameters.
recordingStatusCallbackEvent
stringDefaults to completed
The different recording statuses. Possible values are completed, in-progress, and absent. To specify multiple events, separate with a space.
recordingStatusCallbackMethod
stringDefaults to POST
The type of HTTP request to use when requesting a recordingStatusCallback.
storageUrl
string
The storageUrl attribute accepts an absolute URL as the destination to send a recording to, if you prefer to host your own recordings and bypass SignalWire storage.
storageUrlMethod
stringDefaults to POST
Specifies which HTTP verb to use when sending the recording to the storageUrl. Available values are: POST and PUT.
timeout
integer
The timeout attribute specifies the number of seconds of silence that ends a recording.
transcribe
booleanDefaults to false
The transcribe attribute identifies whether to produce a text transcription of the recording. There is an additional charge for this service, so is turned off by default.
transcribeCallback
string
The ability to define a URL to which SignalWire will make a POST request to once the transcription is complete. See below for specified request parameters.
trim
stringDefaults to trim-silence
Whether or not silence in the beginning and end of recordings are removed. Allowed values are trim-silence and do-not-trim.
the sound of silence
If no audio data is received, including when a caller is silent and trim-silence is enabled, SignalWire will not save a recording. If you wish to save silence, be sure to set trim="do-not-trim".
Note also that SignalWire will trim leading and trailing silence from your audio files, causing the duration of calls to be less than the time spent recording.
avoid looping
When recording finishes, including when no audio data is received, <Record> will always request its action URL and process the cXML instructions that are returned. If no action URL is set, SignalWire will re-request the current cXML document’s URL by default. This can lead to unwanted looping behavior, so make sure to end the call using action as seen in the Recording a Voicemail example.
Request parameters for action URL
The action request contains the Standard Request Parameters as well as:
Digits
string
The buttons pressed to end a recording.
RecordingDuration
integer
The duration, in seconds, of the audio recording.
RecordingUrl
string
The URL of the recorded audio file.
Request parameters for recordingStatusCallback
Request parameters for transcribeCallback
Nesting
No other verbs can be nested within <Record> and you cannot nest <Record> within any other verbs.
Examples
Recording a voicemail
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say>
Please leave a message at the beep.
Press the pound key when finished.
</Say>
<Record
action="http://your-application.com/handleRecording.php"
method="GET"
maxLength="15"
finishOnKey="#"
/>
</Response>This prompt will play before the ‘beep’, asking the caller to leave a message. The caller can only leave a message that is 15s long.
Transcribing a recording
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Record
transcribe="true"
transcribeCallback="http://your-application.com/handle_transcribe.php" />
</Response>SignalWire will record the caller and transcribe the recording once it is complete. Then, SignalWire will make a POST request to the transcribeCallback URL with the transcription as a parameter.
*Twilio and TwiML are trademarks of Twilio, Inc. SignalWire, Inc. and its products are not affiliated with or endorsed by Twilio, Inc.
Redirect
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.
An example that redirects the next XML instruction to another call:
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Redirect>https://www.your-application.com/next-instructions</Redirect>
</Response>The <Redirect> verb transfers control from the current call to another. It is effectively an exit statement from the current call, as there is no way to return to any instructions listed after the <Redirect> verb.
Verb attributes
The following attribute is available for the verb <Redirect>:
method
stringDefaults to POST
Specifies whether the redirect is a GET or a POST.
Nouns
The following item is accepted as a noun for the <Redirect> verb:
| Noun | Description |
|---|---|
plain text | The URL, in plain text, of the call to execute. |
Nesting
No other verbs can be nested within <Redirect> and you cannot nest <Redirect> within any other verbs.
Examples
Redirect to absolute URL
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial>310-123-0000</Dial>
<Redirect>http://www.your-application.com/next-instructions</Redirect>
</Response>SignalWire makes a request after the number has been dialed and transfers the call to the XML received through the request.
*Twilio and TwiML are trademarks of Twilio, Inc. SignalWire, Inc. and its products are not affiliated with or endorsed by Twilio, Inc.
Refer
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.
The <Refer> verb transfers a SIP call in SignalWire to a transfer target using the SIP REFER method. This verb returns upon completion of transfer, on failure of transfer, on hangup, or on time out while waiting for NOTIFY. SignalWire will not hang up after <Refer> until all verbs have been processed.
Verb attributes
action
string
The action attribute takes an absolute or relative URL. On completion of the transfer, a request to this URL is made. If action is not provided, SignalWire will continue reading the next verb in the document. See below for specified request parameters.
method
stringDefaults to POST
Specifies whether the action is a GET or a POST.
Request parameters for the action URL
The action request contains the Standard Request Parameters as well as:
NotifySipResponseCode
string
The last response code reported by the SIP NOTIFY events. This is the code sent by the transfer target in response to the SIP INVITE method. This parameter will not reported if no SIP NOTIFY events are received.
ReferCallStatus
string
The result of the transfer based on the reply to the SIP REFER method and the SIP NOTIFY events received afterwards. This parameter will not be reported if no SIP NOTIFY events are received. See below for all possible values.
ReferSipResponseCode
string
The code received in response to the SIP REFER method. 202 when accepted.
Values for the ReferCallStatus parameter
The parameter ReferCallStatus has the following values:
| Value | Description |
|---|---|
in-progress | SIP REFER accepted and SignalWire received 200 via SIP NOTIFY. |
busy | SIP REFER accepted and SignalWire received 486 or 600 via SIP NOTIFY. |
no-answer | SIP REFER accepted and SignalWire received 487 via SIP NOTIFY. |
canceled | SIP REFER accepted, however the call ended before the transfer completed. |
failed | An error occurred through the <Refer> verb, an error received in response to SIP REFER, or a 4xx/5xx/6xx error was received via SIP NOTIFY. |
Nouns
The noun of a cXML verb is nested within the verb upon which the verb acts. <Refer> has the following nouns:
| Noun | Description |
|---|---|
<Sip> | The SIP URI to which to transfer this call. |
Nesting
No other verbs can be nested within <Refer> and you cannot nest <Refer> within any other verbs.
Examples
Transfer to SIP URI
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Refer action="https://example.com/refer-completed.xml" method="GET"><Sip>sip:transfer-target@example.com</Sip></Refer>
</Response>*Twilio and TwiML are trademarks of Twilio, Inc. SignalWire, Inc. and its products are not affiliated with or endorsed by Twilio, Inc.
Reject
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.
The <Reject> verb rejects a call to your SignalWire number. It is effectively an exit statement from the current document, as there is no way to return to any instructions listed after the <Reject> verb.
Verb attributes
reason
stringDefaults to rejected
The reason attribute takes in the following values: busy and rejected. These values specify what message is to be played when SignalWire rejects a call. If this value is set to busy, the caller receives a busy signal and the call is terminated with the status busy. If this value is set to rejected, the call is terminated with the status no answer.
Nesting
No other verbs can be nested within <Reject> and you cannot nest <Reject> within any other verbs.
Examples
A simple rejection of a call
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Reject />
</Response>SignalWire will reject the call and the caller will receive a standard “This number is not in service” response.
Busy signal rejection
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Reject reason="busy" />
</Response>SignalWire will reject the call and the caller will receive a busy signal.
*Twilio and TwiML are trademarks of Twilio, Inc. SignalWire, Inc. and its products are not affiliated with or endorsed by Twilio, Inc.
Room
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.
<Connect> verb’s <Room> noun allows the connection to a video room. For example:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Connect>
<Room>my-room-name</Room>
</Connect>
</Response>Examples
Joining a video room by dialing a number
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Connect>
<Room>my-room-name</Room>
</Connect>
</Response>Notes on usage
- Make sure to use the name of the room. This is generally different from the display name. A display name may look like “My Office”, while a room name looks like “my-office”.
Say
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.
The <Say> verb reads the supplied text back to the caller. It is useful for text that is difficult to pre-record. The gender and language in which the text will be read is customizable.
Verb attributes
language
string
The attribute language allows you to specify the dialect (language and locale) of voice. See below for all language specifications.
loop
integerDefaults to 1
The attribute loop specifies the number of times a text is to be repeated. If loop is set to 0, the text will be continuously repeated until the call is terminated.
voice
stringDefaults to woman
The attribute voice supports: man, woman, alice, Amazon Polly voices by prefixing them with Polly., Amazon Polly Neural voices by prefixing them with Polly. and ending them with -Neural, Google Cloud voices by prefixing them with gcloud.. Polly Neural and Google Wavenet voices are charged a premium price compared to Polly Standard and Google Standard voices. alice is deprecated and provided for backward compatibility. See below for language specifications on each of these voices.
Supported voices and languages
The supported voices and languages can be found here.
Nouns
The noun of a cXML verb is nested within the verb upon which the verb acts. <Say> has the following noun:
| Noun | Description |
|---|---|
plain text | The text that will be read to the caller. Limit: 4,096 unicode characters. |
Speech synthesis markup language (SSML)
Speech Synthesis Markup Language (SSML) is an XML-based markup language that provides a standard way to mark up text for synthesized speech.
SSML is usually wrapped within <speak> tags. But, when using SSML with the <Say> verb, you can ignore those <speak> tags. The rest of the SSML tags will be placed inside the <Say> verb.
Below are the supported SSML tags. When using an Amazon Polly voice, please refer to Amazon Polly SSML Documentation instead.
| Tag | Description |
|---|---|
<break> | A pause in speech. Set the length of the pause with the time attribute. Maximum pause time is 10s. Include the unit s or ms when setting a time. The strength attribute can also be used for pauses. See below for possible values. |
<emphasis> | Emphasize words or phrases. This tag changes the rate and volume of speech. More emphasis generates louder and slower speech while less emphasis generates quieter and faster speech. Emphasis can be modified with the level attribute. See below for possible values. |
<lang> | Specify another language for specific words or phrases. Set the language with the xml:lang attribute. Possible languages are: en-US, en-GB, en-IN, en-AU, en-CA, de-DE, es-ES, it-IT, ja-JP, fr-FR (English, German, Spanish, Italian, Japanese, French). |
<p> | Add a pause between paragraphs. |
<phoneme> | Phonetic pronunciation for specified words or phrases. Set the phonetic alphabet to use with the alphabet attribute. See below for possible values. In addition, you can use the ph attribute to set the phonetic pronunciation to speak. See here for a list of supported symbols. |
<prosody> | Modify the volume, pitch, and rate of the tagged speech. |
<s> | Add a pause between sentences. |
<say-as> | Describe how text should be interpreted. See below for all the possible values of the interpret-as attribute of the <say-as> tag. |
<sub> | Pronounce the specified word or phrase as a different word or phrase. Specify the pronunciation to substitute with the alias attribute. |
strength attribute
The strength attribute has the following values. Default is medium.
| Value | Description |
|---|---|
none | No pause. Can be used to remove a pause that would normally occur. |
x-weak | No pause. |
weak | Treat adjacent words as if separated by a single comma. |
medium | Treat adjacent words as if separated by a single comma. |
strong | Sentence break. |
x-strong | Paragraph break. |
level attribute
The level attribute has the following values. Default is moderate.
| Value | Description |
|---|---|
strong | Increase the volume and slow down the speaking rate. Speech is louder and slower. |
moderate | Increase the volume and slow down the speaking rate, but not as much as strong. |
reduced | Decrease the volume and speed up the speaking rate. Speech is softer and faster. |
alphabet attribute
The alphabet attribute has the following values.
| Value | Description |
|---|---|
ipa | The International Phonetic Alphabet (IPA). |
x-sampa | The Extended Speech Assessment Methods Phonetic Alphabet (X-SAMPA). |
volume attribute
The volume attribute has the following values. Set the volume with one of the values below. Then, you can specify a percentage to increase or decrease the volume of the speech. See here for more information.
| Value | Description |
|---|---|
silent | No volume. |
x-soft | Lowest volume. |
soft | Lower volume. |
medium | Normal volume. |
loud | Louder volume. |
x-loud | Loudest volume. |
pitch attribute
The pitch attribute has the following values. Set the pitch with one of the values below. Then, you can specify a percentage to increase or decrease the pitch of the speech. See here for more information.
| Value | Description |
|---|---|
x-low | Lowest pitch. |
low | Lower pitch. |
medium | Normal pitch. |
high | Higher pitch. |
x-high | Highest pitch. |
rate attribute
The rate attribute has the following values. Set the rate with one of the values below. Then, you can specify a percentage to increase or decrease the speed of the speech. See here for more information.
| Value | Description |
|---|---|
x-slow | Slowest rate. |
slow | Slower rate. |
medium | Normal rate. |
fast | Faster rate. |
x-fast | Fastest rate. |
interpret-as attribute
The interpret-as attribute has the following values.
| Value | Description |
|---|---|
characters | Spell out each letter. |
spell-out | Spell out each letter. |
cardinal | Interpret value as cardinal number. |
number | Interpret value as cardinal number. |
ordinal | Interpret value as ordinal number. |
digits | Spell each digit separately. |
fraction | Interpret value as fraction. |
unit | Interpret value as measurement. |
date | Interpret value as a date. Use format attribute to indicate format of date: mdy, dmy, ymd, md, dm, ym, my, d, m, y. |
time | Interpret as a duration of minutes and seconds. |
telephone | Interpret as telephone number. |
address | Interpret as part of a street address. |
interjection | Interpret as an interjection. |
expletive | ”Bleep” out content in tag. |
Example
<Response>
<Say>
Welcome to SignalWire
<break strength="x-weak" time="100ms"/>
<emphasis level="moderate">Emphasized words</emphasis>
<p>Words in a paragraph</p>
<phoneme alphabet="x-sampa" ph="pɪˈkÉ‘Ën">Phonetic pronunciation</phoneme>
<prosody pitch="-10%" rate="85%" volume="-6dB">Words to speak</prosody>
<s>Words in a sentence.</s>
<say-as interpret-as="spell-out">Words</say-as>
<sub alias="alias">Words to be substituted</sub>
</Say>
</Response>Here is an example of how to use some of the SSML tags within the Say verb.
Nesting
No other verbs can be nested within <Say>. However, <Say> can be nested within <Gather>.
Examples
A simple message to be read
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say>Hello World.</Say>
</Response>‘Hello World’ will be read once in a male voice.
A simple message to be read using Amazon Polly voice
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say voice="Polly.Joanna">Hello World.</Say>
</Response>‘Hello World’ will be read once using the Amazon Polly “Joanna” voice.
A simple message to be read using Amazon Polly Neural voice
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say voice="Polly.Joanna-Neural">Hello World.</Say>
</Response>‘Hello World’ will be read once using the Amazon Polly “Joanna” Neural voice. Amazon Polly Neural voices are charged a premium price compared to Amazon Polly Standard voices.
A simple message to be read using Google Cloud text-to-speech voice
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say voice="gcloud.en-US-Standard-A">Hello World.</Say>
</Response>‘Hello World’ will be read once using the Google Cloud text-to-speech en-US-Standard-A voice.
Repetition of a message in a foreign language
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say voice="alice" language="fr-CA" loop="5">Bonjour.</Say>
</Response>‘Hello’ will be repeated 5 times in Canadian French.
Notes on usage
- There is a 4,096 Unicode character limit on the text
- Numbers are spoken, or read, based on context. For example, ‘234’ is read as “two hundred thirty-four”, whereas ‘2 3 4’ is read as “two three four”.
- Short pauses in spoken text are accomplished by inserting punctuations, i.e. commas and periods, in the written text. For longer pauses, place text in a separate
<Say>verbs and place a<Pause>verb in between them. - Dates, times, money amounts, and abbreviations may not follow intuitive pronunciations. Test these situations to ensure they are pronounced to your liking.
*Twilio and TwiML are trademarks of Twilio, Inc. SignalWire, Inc. and its products are not affiliated with or endorsed by Twilio, Inc.
Sip
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.
<Dial> verb’s <Sip> noun permits the set up of VoIP sessions using SIP (Session Initiation Protocol). You can send a call to any SIP endpoint.
When dialing an SIP endpoint, the transport defaults to TLS. If the SIP destination does not support TLS, you can set the transport to UDP or TCP by setting the transport manually. For example: sip:alice@example.com;transport=udp.
The <Sip> noun supports all of the <Dial> verb’s attributes with one exception: callerId is supported but not limited to a valid E.164 number. When using the <Sip> noun, the callerId attribute can be any alphanumeric string and include the following characters: +-_., but no whitespace.
For example, one can dial to a SIP destination with:
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial>
<Sip>sip:alice@example.com</Sip>
</Dial>
</Response>Noun attributes
codecs
stringDefaults to PCMU,PCMA
A comma separated list of codecs to offer to the SIP user agent. Select from PCMU, PCMA, G722, G729, and OPUS. Codecs are offered in the order specified.
method
stringDefaults to POST
The method attribute specifies whether the request to action is a GET or a POST. Valid values are GET or POST.
password
string
Password for SIP authentication.
sessionTimeout
integer
Non-negative value, in seconds, to use for the SIP Session-Expires header. If 0 or unset, SignalWire will pick the default (typically 600).
statusCallback
string
The URL to make requests to for each statusCallbackEvent event. See below for request parameters.
statusCallbackEvent
string
The current status of the call. The call moves from initiated to ringing when the phone starts ringing. It moves from ringing to answered when the phone call is answered. Finally, it moves from answered to completed when the call is terminated. The status will be set to completed through the following reasons: busy, canceled, completed, failed, or no-answer. To specify multiple events, separate each one with a space. See below for the different call statuses.
statusCallbackMethod
stringDefaults to POST
The type of HTTP request to use when requesting a statusCallback.
url
string
A specified URL for a document that runs on the callee’s end after the dialed number answers but before the call is connected. This allows the caller to provide information to the dialed number, giving them the opportunity to decline the call, before they answer the call. See below for request parameters.
username
string
Username for SIP authentication.
After a Dial attempt is made, SignalWire can make a request to the <Dial> verb’s action attribute. In addition to the Standard Request Parameters, the following are parameters passed back to your application when SignalWire makes the request.
DialSipCallId
string
The SIP call ID header of the request made to the remote SIP infrastructure.
DialSipHeader_
string
The name or value of any X-headers returned in the 200 response to the SIP INVITE request.
DialSipResponseCode
string
The SIP response code to the INVITE attempt.
Request parameters for sip_url
In addition to the Standard Request Parameters, the following are parameters passed back to your application when SignalWire makes a request to the <Sip> noun’s url attribute.
SipCallId
string
The SIP call ID header of the request made to the remote SIP infrastructure.
SipHeader
string
The name or value of any X-headers returned in the 200 response to the SIP INVITE request.
Status values for statusCallbackEvent
The statusCallbackEvent attribute has the following call status values:
| Value | Description |
|---|---|
initiated | Dialing of a call has begun. |
ringing | The call has begun ringing. |
answered | The call has been answered. |
completed | The call has been terminated. The status will be set to completed through the following reasons: busy, canceled, completed, failed, or no-answer. |
Request parameters for the statusCallback URL
Examples
Dialing to a SIP endpoint
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial>
<Sip>sip:alice@example.com</Sip>
</Dial>
</Response>In this example, in order to connect to alice@example.com we have to nest a <Sip> within a <Dial>.
Dialing to a SIP endpoint with authentication
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial>
<Sip username="admin" password="1234">sip:bob@example.com</Sip>
</Dial>
</Response>Now, in order to connect to bob@example.com, you have to have the proper authentication credentials.
Passing custom headers
Pass custom headers to the SIP endpoint.
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial>
<Sip>sip:charlie@example.com?customheader=foo&othercustomheader=bar</Sip>
</Dial>
</Response>Dialing a SIP endpoint with Dial attributes
The Sip Noun supports of <Dial> attributes and can be used together.
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial
record="record-from-answer"
callerId="alice"
method="GET"
action="https://www.example.com/after_dial">
<Sip
url="https://www.example.com/whisper_audio"
statusCallbackEvent='ringing answered'
statusCallback='https://www.example.com/dial_events'>
sip:dan@example.com?customheader=foo
</Sip>
</Dial>
</Response>Notes on usage
- SIP INVITE message includes CallSid, AccountSid, and the API version; can also pass custom SIP headers in the INVITE message.
- You can have up to 10
<Sip>s within a<Dial>. - You cannot add other nouns in a
<Dial>that contains a<Sip>.
*Twilio and TwiML are trademarks of Twilio, Inc. SignalWire, Inc. and its products are not affiliated with or endorsed by Twilio, Inc.
Sms
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.
The <Sms> verb sends an SMS message to a phone number during a phone call.
Verb attributes
action
string
The action attribute takes a URL as an argument. After processing the <Sms> verb, SignalWire will make a GET or POST request to this URL with the form parameters SmsStatus and SmsSid. Using an action URL, your application can receive synchronous notification that the message was successfully enqueued. If you provide an action URL, SignalWire will use the cXML received in your response to the action URL request to continue the current call. Any cXML verbs occurring after an <Sms> which specifies an action attribute are unreachable. If no action is provided, <Sms> will finish and SignalWire will move on to the next cXML verb in the document. If there is no next verb, SignalWire will end the phone call. Note that this is different from the behavior of <Record> and <Gather>. <Sms> does not make a request to the current document’s URL by default if no action URL is provided. See below for request parameters.
from
string
The from attribute takes a valid phone number as an argument. This number must be a phone number that you’ve purchased from or ported to SignalWire. When sending an SMS during an incoming call, from defaults to the called party. When sending an SMS during an outgoing call, from defaults to the calling party. This number must be an SMS-enabled phone number assigned to your account. If the phone number isn’t SMS-enabled, then the <Sms> verb will not send an SMS message.
method
stringDefaults to POST
The method attribute specifies whether the request to action is a GET or a POST. Valid values are GET or POST.
statusCallback
string
The URL to make requests to for each statusCallbackEvent event. See below for request parameters. The statusCallback attribute takes a URL as an argument. When the SMS message is actually sent, or if sending fails, SignalWire will make an asynchronous POST request to this URL with the parameters SmsStatus and SmsSid. Note, statusCallback always uses HTTP POST to request the given url.
to
string
The to attribute takes a valid phone number as a value. SignalWire will send an SMS message to this number. When sending an SMS during an incoming call, to defaults to the caller. When sending an SMS during an outgoing call, to defaults to the called party. The value of to must be a valid phone number. NOTE: sending to short codes is not currently supported. Phone numbers should be formatted with a + and country code e.g., +17275551212 (E.164 format).
Request parameters for the action URL
The action URL request contains the Standard Request Parameters as well as:
SmsSid
string
The SID for the Sms message.
SmsStatus
string
The current status of the Sms message. This is usually sending. But if you provide an invalid number, this is invalid.
Request parameters for statusCallback
The statusCallback request contains the Standard Request Parameters as well as:
SmsSid
string
The SID for the Sms message.
SmsStatus
string
The current status of the Sms message. Either sent or failed.
Nouns
The noun of a cXML verb is nested within the verb upon which the verb acts. <Sms> has the following nouns:
| Noun | Description |
|---|---|
plain text | The text of the SMS message you want to send. Must be less than 1600 characters. |
Nesting
No other verbs can be nested within <Sms> and you cannot nest <Sms> within any other verbs.
Examples
Simple SMS sending
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say>Our store is located at 123 Easy St.</Say>
<Sms>Store Location: 123 Easy St.</Sms>
</Response>This is the simplest case for <Sms>. SignalWire first tells the caller where the store is located, and then sends the caller an SMS with the location as the message.
SmsStatus reporting
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say>Our store is located at 123 Easy St.</Say>
<Sms action="/smsHandler.php" method="POST">
Store Location: 123 Easy St.
</Sms>
</Response>In this use case, we provide action URL and method attributes. Now when the message is queued for delivery, SignalWire will make a request to the action URL passing the parameter SmsStatus. If the message is queued and waiting to be sent, SmsStatus will have the value sending. If an invalid attribute was provided, then SmsStatus will be invalid.
Your web application can look at the SmsStatus parameter and decide what to do next.
If an action URL is provided for <Sms>, flow of your application will continue with the XML received in response to the action request. All verbs remaining in the document are unreachable and ignored.
statusCallback reporting
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say>Our store is located at 123 Easy St.</Say>
<Sms statusCallback="/smsHandler.php">Store Location: 123 Easy St.</Sms>
</Response>In this example we provide a statusCallback URL. When the message is finished sending (not just enqueued), SignalWire will asynchronously request the statusCallback URL with the parameter SmsStatus. If the messages was successfully sent, SmsStatus will be sent. If the message failed to send, SmsStatus will be failed.
*Twilio and TwiML are trademarks of Twilio, Inc. SignalWire, Inc. and its products are not affiliated with or endorsed by Twilio, Inc.
Stream
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.
The <Stream> instruction makes it possible to send raw audio streams from a running phone call over WebSockets in near real time, to a specified URL. The audio frames themselves are base64 encoded, embedded in a json string, together with other information like sequence number and timestamp. The feature can be used with Speech-To-Text systems and others.
Attributes
An example on how to use Stream:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Start>
<Stream url="wss://your-application.com/audiostream" />
</Start>
</Response>This cXML will instruct Signalwire to make a copy of the audio frames of the current call and send them in near real-time over WebSocket to wss://your-application.com/audiostream.
<Stream> will start the audio stream in an asynchronous manner; it will continue with the next cXML instruction at once. In case there is no instruction, Signalwire will disconnect the call.
Node.jsC#PythonRuby
const { RestClient } = require("@signalwire/compatibility-api");
const response = new RestClient.LaML.VoiceResponse();
const start = response.start();
start.stream({
name: "Example Audio Stream",
url: "wss://your-application.com/audiostream",
});
console.log(response.toString());Stream
Conference Stream
url
stringRequired
Absolute or relative URL. A WebSocket connection to the url will be established and audio will start flowing towards the Websocket server. The only supported protocol is wss. For security reasons ws is NOT supported.
authBearerToken
string
An authentication Bearer token that can be supplied when starting a stream. The remote server can then authenticate the websocket connection request from the supplied token. More information can be found in the WebSocket connection section.
codec
stringDefaults to PCMU@8000h
Specifies the audio codec for the stream. See Supported Codecs for full list.
name
string
Unique name for the Stream, per Call. It is used to stop a Stream by name.
realtime
booleanDefaults to false
If true, and the stream is bidirectional, the stream offers a realtime experience to the call parties by managing packet delays and bursts. If false, the user benefits from buffered audio, which can be played out with delay.
statusCallback
string
Absolute or relative URL. SignalWire will make a HTTP GET or POST request to this URL when a Stream is started, stopped or there is an error.
statusCallbackMethod
stringDefaults to POST
GET or POST. The type of HTTP request to use when requesting a statusCallback.
track
stringDefaults to inbound_track
This attribute can be one of: inbound_track, outbound_track, both_tracks. For both_tracks there will be both inbound_track and outbound_track events. If the stream is bidirectional, the only available attribute is inbound_track.
Looking to use our REST APIs?
You can utilize our REST API to both start and stop streams.
StatusCallback parameters
For a statusCallback, SignalWire will send a request with the following parameters:
AccountSid
string
The unique ID of the Account this call is associated with.
CallSid
string
A unique identifier for the call. May be used to later retrieve this message from the REST API.
ConferenceSid
string
If the stream is part of a conference, the unique identifier for the conference.
StreamError
string
If an error has occurred, this will contain a detailed error message. See StreamError Values for possible values.
StreamEvent
string
One of stream-started, stream-stopped, or stream-error.
StreamName
string
If defined, this is the unique name of the Stream. Defaults to the StreamSid.
StreamSid
string
The unique identifier for this Stream.
StreamTrack
string
The track configuration for this stream: inbound_track, outbound_track, or both_tracks.
Timestamp
string
The time of the event in ISO 8601 format.
Unique-ID
string
The unique call identifier.
StreamError values
When StreamEvent is stream-error, the StreamError field will contain one of the following values:
| Error Value | Meaning | Common Causes |
|---|---|---|
invalid_url | Invalid WebSocket URL format | URL doesn’t use wss:// protocol |
missing_url | No URL provided | url attribute not specified |
invalid_track | Invalid track configuration | Track value not one of: inbound_track, outbound_track, both_tracks |
codec_error | Codec not supported or misconfigured | Requested codec not enabled for your account, or multi-channel audio requested (only mono is supported) |
connection_refused | Remote endpoint rejected connection | Your WebSocket server refused the connection |
connection_refused_timeout_or_ssl_error | Connection timeout or SSL failure | WebSocket server unreachable or SSL certificate issues |
general_error | Internal stream initialization failed | Internal error during stream setup - contact support with StreamSid |
Duplicated stream ID | Stream ID already in use | Conference already has a stream with this ID |
Duplicated stream name | Stream name already in use | Conference already has a stream with this name |
Supported codecs
The codec attribute allows you to control the audio codec used for the stream. The following codecs are supported:
| Codec Value | Sample Rates Available |
|---|---|
PCMU (default) | 8000h |
L16 | 16000h, 24000h |
Codec Format Examples:
PCMU@8000h(default if no codec specified)L16@24000hL16@16000h
WebSocket connection
When establishing a stream, SignalWire initiates a WebSocket connection to your specified URL endpoint. The connection begins with an HTTP upgrade request containing the following headers:
Authorization
string
Bearer token for authentication if authBearerToken attribute is provided (format: “Bearer token_here”).
Connection
string
Connection type for the upgrade (value: “Upgrade”).
Host
string
The destination server hosting the WebSocket endpoint (e.g., “example.com”).
Sec-WebSocket-Key
string
Base64-encoded random value used for the WebSocket handshake.
Sec-WebSocket-Version
string
WebSocket protocol version (value: “13”).
Upgrade
string
Protocol upgrade request indicating a switch to WebSocket (value: “websocket”).
Once the WebSocket connection is established, SignalWire will send various events throughout the stream’s lifecycle. These events are delivered as JSON-formatted WebSocket messages, each containing an event property that identifies the message type.
SignalWire sends the following event types to your WebSocket server:
- Connected - Initial handshake message confirming the connection
- Start - Stream metadata and configuration details
- Media - Audio data packets
- DTMF - Touch-tone digit events
- Mark - Audio playback completion acknowledgments (echoed back when you send a mark)
- Stop - Stream termination notification
When using bidirectional streams with <Connect><Stream>, you can also send messages to SignalWire:
- Media - Send audio data into the call
- Mark - Request playback completion acknowledgment
- Clear - Flush the audio buffer
- DTMF - Inject DTMF tones into the call
Connected message
SignalWire sends the Connected event immediately after establishing the WebSocket connection. This initial message outlines the communication protocol for all subsequent interactions.
| Property | Description |
|---|---|
| event | The string value of connected. |
| protocol | Defines the protocol for the WebSocket connection’s lifetime. Value: Call |
| version | Semantic version of the protocol. Current version: 0.2.0 |
Example Connected message
{
"event": "connected",
"protocol": "Call",
"version": "0.2.0"
}Start message
SignalWire delivers this message right after the Connected event, providing essential stream configuration details. This message appears only once when the stream initializes.
| Property | Description |
|---|---|
| event | The string value of start. |
| sequenceNumber | Message sequence tracking, starting from “1” and incrementing with each message. |
| start | Container holding stream configuration and metadata details. |
| start.streamSid | The unique identifier of the Stream. |
| start.accountSid | The Account identifier that created the Stream. |
| start.callSid | Call session identifier where the stream originated. |
| start.tracks | Array specifying which audio directions will be transmitted. Possible values: ["inbound"], ["outbound"], or ["inbound", "outbound"]. |
| start.customParameters | Object containing custom key-value pairs configured during stream creation. Only present when custom parameters are defined. |
| start.mediaFormat | Configuration details for audio data formatting. |
| start.mediaFormat.encoding | Audio codec format. Possible values: audio/x-mulaw (PCMU), audio/x-L16 (L16). |
| start.mediaFormat.sampleRate | Audio sampling frequency in Hz. Possible values: 8000 (PCMU), 16000 (L16), or 24000 (L16). |
| start.mediaFormat.channels | Audio channel count. Always 1 (mono). Multi-channel audio is not supported. |
Example Start message
{
"event": "start",
"sequenceNumber": "1",
"start": {
"streamSid": "7d56cc11-536d-4a45-b4fb-ed3d55be843b",
"accountSid": "b08dacad-2f6c-4de1-93d6-cc732e0c69c5",
"callSid": "76ac3c36-56da-4a3e-a0d6-b5f8df6da9ad",
"tracks": [\
"inbound"\
],
"customParameters": {},
"mediaFormat": {
"encoding": "audio/x-L16",
"sampleRate": 24000,
"channels": 1
}
}
}Media message
Media messages deliver the actual audio content from the call as it flows through the stream.
| Property | Description |
|---|---|
| event | The string value of media. |
| sequenceNumber | Sequential message counter for ordering, starting at “1” and incrementing per transmission. |
| media | Container with audio data and associated metadata. |
| media.track | Audio track identifier. One of: inbound or outbound. |
| media.chunk | Chunk counter for this track. Starts at “1” and increments with each chunk. |
| media.timestamp | Presentation timestamp in milliseconds from the start of the stream. |
| media.payload | Base64-encoded raw audio data. |
Example Media message
{
"event": "media",
"sequenceNumber": "42",
"media": {
"track": "inbound",
"chunk": "1",
"timestamp": "0",
"payload": "<base64-encoded-audio>"
}
}Stop message
SignalWire transmits a stop message when the stream terminates or the associated call concludes.
| Property | Description |
|---|---|
| event | The string value of stop. |
| sequenceNumber | Message sequence counter. |
Example stop message
{
"event": "stop",
"sequenceNumber": "999"
}DTMF message
SignalWire generates DTMF messages whenever touch-tone key presses are detected in the audio stream.
| Property | Description |
|---|---|
| event | Event type identifier set to dtmf. |
| sequenceNumber | Message sequence counter. |
| streamSid | Stream identifier. Only included for bidirectional streams. |
| dtmf | Container holding the detected touch-tone details. |
| dtmf.digit | The digit that was pressed. Values: 0-9, *, #, A-D. |
| dtmf.duration | Duration of the key press in milliseconds. |
Example DTMF message
{
"event": "dtmf",
"sequenceNumber": "123",
"streamSid": "7d56cc11-536d-4a45-b4fb-ed3d55be843b",
"dtmf": {
"digit": "5",
"duration": 2000
}
}Mark message
SignalWire delivers mark messages as acknowledgments for completed audio playback or cleared buffer operations. These responses match the mark identifiers from your earlier transmissions to SignalWire.
| Property | Description |
|---|---|
| event | Event type designation set to mark. |
| streamSid | Stream connection identifier. Only included for bidirectional streams. |
| mark | Container with the mark acknowledgment details. |
| mark.name | The mark identifier echoed back from your original transmission. |
Example Mark message
{
"event": "mark",
"streamSid": "7d56cc11-536d-4a45-b4fb-ed3d55be843b",
"mark": {
"name": "my-custom-mark"
}
}Sending WebSocket messages
When you create a Stream within a <Connect><Stream> element, the connection becomes bidirectional. Your application can transmit WebSocket messages to SignalWire, enabling you to inject audio into the active call and manage the stream’s behavior.
The messages that your WebSocket server can send back to SignalWire are:
- Media - Send audio data back into the call
- Mark - Track when audio playback completes
- Clear - Interrupt buffered audio
- DTMF - Inject DTMF tones into the call
Send a media message
Transmitting audio to SignalWire requires constructing a valid media message with the correct structure.
The payload encoding depends on the codec specified in your Stream configuration:
- Default (PCMU/mulaw):
audio/x-mulawwith 8000 Hz sample rate - L16@16000h: Linear PCM with 16000 Hz sample rate
- L16@24000h: Linear PCM with 24000 Hz sample rate
All audio must be base64 encoded. SignalWire queues incoming media messages and plays them sequentially. To stop playback and clear the queue, transmit a clear message.
Ensure your media.payload contains only raw audio data without file format headers. Including format headers will result in corrupted audio playback.
| Property | Description |
|---|---|
| event | Specifies the message type. Set to "media" for audio data. |
| streamSid | Target stream identifier for audio playback |
| media | Container object holding the audio payload |
| media.payload | Base64-encoded audio data (format varies by codec configuration) |
Example media message (payload abbreviated):
{
"event": "media",
"streamSid": "c0c7d59b-df06-435e-afbc-9217ce318390",
"media": {
"payload": "a3242sa..."
}
}Send a mark message
Transmit a mark message following your media messages to receive confirmation when audio playback finishes. SignalWire responds with a matching mark identifier once the audio completes playing (or immediately if no audio is queued).
You’ll also receive mark confirmations when the audio queue is cleared via a clear message.
| Property | Description |
|---|---|
| event | Message type identifier. Set to "mark" for completion tracking. |
| streamSid | Target stream identifier for the mark operation |
| mark | Container object with mark details |
| mark.name | Custom identifier to track specific audio segments or playback events |
Example mark message:
{
"event": "mark",
"streamSid": "c0c7d59b-df06-435e-afbc-9217ce318390",
"mark": {
"name": "my label"
}
}Send a clear message
Transmit a clear message to halt audio playback and flush the audio queue. This action triggers SignalWire to return any pending mark messages for the cleared audio segments.
| Property | Description |
|---|---|
| event | Message type identifier. Set to "clear" for audio interruption. |
| streamSid | Target stream identifier where audio should be stopped. |
Example clear message:
{
"event": "clear",
"streamSid": "c0c7d59b-df06-435e-afbc-9217ce318390"
}Send a DTMF message
Transmit a DTMF message to inject touch-tone digits into the call. This allows you to programmatically send DTMF tones as if they were pressed on a keypad.
| Property | Description |
|---|---|
| event | Message type identifier. Set to "dtmf" for DTMF injection. |
| streamSid | Target stream identifier where DTMF should be sent. |
| dtmf | Container object with DTMF details |
| dtmf.digit | The digit to send. Valid values: 0-9, *, #, A-D |
Example DTMF message:
{
"event": "dtmf",
"streamSid": "c0c7d59b-df06-435e-afbc-9217ce318390",
"dtmf": {
"digit": "5"
}
}Examples
Conference stream
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial trim="do-not-trim">
<Conference beep="false" startConferenceOnEnter="true" trim="do-not-trim" streamUrl="wss://206.189.19.130:8765/">test
<Stream name="my_conference_stream"
url="wss://206.189.19.130:8765/"
streamStartConferenceOnEnter="true"
bidir="true">
<Parameter name="foo1" value="bar1"/>
<Parameter name="foo2" value="bar2"/>
</Stream>
</Conference>
</Dial>
</Response>Bidirectional stream
The <Stream> instruction can allow you to receive audio into the call too. In this case, the stream must be bidirectional. The external service (e.g., an AI agent) will then be able to both hear the call and play audio.
To initialize a bidirectional stream, wrap the <Stream> instruction in <Connect> instead of <Start>.
<Connect>
<Stream url="wss://mystream.ngrok.io/audiostream" />
</Connect>Starting and stopping streams
It is possible to stop a stream at any time by name. For instance by naming the Stream “mystream”, you can later use the unique name of “mystream” to stop the stream.
<Start>
<Stream name="mystream" url="wss://mystream.ngrok.io/audiostream" />
</Start><Stop>
<Stream name="mystream" />
</Stop>Custom parameters
To pass parameters towards the wss server, it is possible to include additional key value pairs. This can be done by using the nested <Parameter> cXML noun. These parameters will be added to the Start message, as json.
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Start>
<Stream url="wss://your-application.com/audiostream" >
<Parameter name="Cookie" value ="948f9938-299a-d43e-0df4-af3a7eccb0ac"/>
<Parameter name="Type" value ="SIP" />
</Stream>
</Start>
</Response>Notes on usage
- The url does not support query string parameters. To pass custom key value pairs to the WebSocket, make use of Custom Parameters instead.
- There is a one to one mapping of a stream to a websocket connection, therefore there will be at most one call being streamed over a single websocket connection. Information will be provided so that you can handle multiple inbound connections and manage the association between the unique stream identifier (StreamSid) and the connection.
- On any given call there are inbound and outbound tracks,
inboundrepresents the audio Signalwire receives from the call,outboundrepresents the audio generated by Signalwire for the Call.
*Twilio and TwiML are trademarks of Twilio, Inc. SignalWire, Inc. and its products are not affiliated with or endorsed by Twilio, Inc.
Verto
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.
The <Verto> noun is used to create a Verto connection. This is a SignalWire specific noun that is used to establish a connection between the inbound call to the Verto client.
When using the <Verto> noun to dial a Verto client, the client address is formatted as: <resource_name>@<space_sip_domain>.verto.signalwire.com.
Verb attributes
The <Verto> verb does not support any attributes.
Nesting
No other verbs can be nested within <Verto> however, <Verto> is nested within the <Dial> verb.
Request parameters
After a Dial attempt is made, SignalWire can make a request to the <Dial> verb’s action attribute. In addition to the Standard Request Parameters, the following are parameters passed back to your application when SignalWire makes the request.
| Parameter | type | Description |
|---|---|---|
DialCallSID | string | The unique identifier for the call. |
DialSipHangupDirection | string | The direction of the hangup. |
DialCallStatus | string | The status of the call. |
DialCallDuration | string | The duration of the call. |
HangupDirection | string | The direction of the hangup. |
Examples
A simple Verto dial
<?xml version="1.0"?>
<Response>
<Dial>
<Verto>Test@mySip-domain.verto.signalwire.com</Verto>
</Dial>
</Response>Dialing a Verto client with Dial attributes
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial
record="record-from-answer"
method="GET"
action="https://www.example.com/after_dial">
<Verto>Test@mySip-domain.verto.signalwire.com</Verto>
</Dial>
</Response>VirtualAgent
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.
Deprecated Notice
Dialogflow application creation and management through the SignalWire Compatibility API is deprecated. Only existing Dialog applications will continue to function; new Dialog applications can no longer be created.
<Connect> verb’s <VirtualAgent> noun permits connecting the call to a Dialogflow agent.
For example, one can connect to Dialogflow with:
XMLNode.jsC#PythonRuby
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Connect action="https://example.com/next-xml-instructions" >
<VirtualAgent connectorName="my-agent" />
</Connect>
</Response>Noun attributes
connectorName
stringRequired
The Google Project ID of the agent to use. Find a list of IDs in the Dialogflow page in the UI.
After a Dialogflow conversation is completed, SignalWire can make a request to the <Connect> verb’s action attribute. In addition to the Standard Request Parameters, the following are parameters passed back to your application when SignalWire makes the request.
VirtualAgentError
string
An error message, in case VirtualAgentStatus is "failed".
VirtualAgentErrorCode
string
An error code, in case VirtualAgentStatus is "failed".
VirtualAgentProvider
string
The provider of the VirtualAgent (e.g., Dialogflow)
VirtualAgentProviderData
string
A JSON object (serialized as a string) containing data about the Dialogflow interaction.
VirtualAgentStatus
string
E.g. failed or transfer
*Twilio and TwiML are trademarks of Twilio, Inc. SignalWire, Inc. and its products are not affiliated with or endorsed by Twilio, Inc.
