Skip to content

Cxml Voice

Fresh

Voice 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
ringingThe call is ringing.
in-progressThe call was answered and is in progress.
queuedThe call is ready and in line to initiate.
failedThe call could not be completed. Usually occurs when phone number does not exist.
busyThe caller encountered a busy signal.
no-answerThe call ended without an answer.
completedThe call was answered and ended normally.
canceledThe 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:

ValueDescription
truePlays a beep when a caller leaves or enters a conference. The default value for beep.
falseDisables the beep when callers leave and enter conferences.
onEnterOnly plays a beep when a caller enters a conference.
onExitOnly plays a beep when a caller leaves a conference.

Events for the statusCallbackEvent attribute

The statusCallbackEvent attribute has the following events:

EventDescription
startThe 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.
endThe conference ends when the last participant in the call or a participant with endConferenceOnExit set to true leaves the call.
joinWhen a participant joins a conference.
leaveWhen a participant leaves a conference.
muteWhen a participant has been muted or un-muted.
holdWhen a participant has been put on hold or put out of hold.
speakerWhen 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:

ValueDescription
in-progressThe recording has begun.
completedThe recording has completed and is accessible.
failedThe 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:

NounDescription
<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:

ValueDescription
completedThe number that was dialed answered the call and was successfully connected to the caller.
answeredWhen calling to a conference, the number that was dialed answered the call and was successfully connected to the caller.
busySignalWire received a busy signal when connecting to the dialed number.
no-answerThe number that was dialed did not answer the call in time.
failedSignalWire was unable to connect to the dialed number. This usually occurs when the dialed number does not exist.
canceledThe 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:

ValueDescription
bridgedThe call was bridged and removed from the queue.
bridging-in-progressSignalWire is instructed to bridge the call.
errorAn error occurred either through the <Enqueue> verb or through the document retrieved from the waitUrl.
hangupThe caller hung up while still in the queue.
leaveThe caller left the queue through the <Leave> verb.
redirectedThe call was redirected out of the queue, through a REST API request, while the caller was in the queue.
redirected-from-bridgedThe queued and bridged session was transferred out.
queue-fullThe queue was full, so the placement into the queue was not accepted.
system-errorSignalWire 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:

NounDescription
plain textThe 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:

ValueDescription
initiatedDialing of a call has begun.
ringingThe call has begun ringing.
answeredThe call has been answered.
completedThe 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

ValueDescription
successPayment processed successfully
too-many-failed-attemptsMaximum retry attempts reached
payment-connector-errorGateway communication failure
caller-interrupted-with-starUser canceled with * key
caller-hung-upCall terminated by user
validation-errorInvalid parameter provided
internal-errorSystem 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

EventDescription
payment-card-numberCollecting card number
expiration-dateCollecting expiration date
security-codeCollecting CVV/security code
postal-codeCollecting postal code
bank-routing-numberCollecting routing number
bank-account-numberCollecting account number
payment-processingProcessing transaction

For values

ValueDescription
payment-card-numberRequesting the customer’s credit or debit card details
expiration-dateRequesting the expiration date of the customer’s payment card
security-codeRequesting the security code (CVV) of the customer’s payment card
postal-codeRequesting the postal code linked to the customer’s payment card
payment-processingExecuting the payment transaction

Error types

ErrorDescription
input-timeoutUser input timeout
invalid-card-numberFailed card validation
invalid-card-typeUnsupported card type
invalid-dateInvalid expiration date
invalid-security-codeInvalid CVV format
invalid-postal-codeInvalid postal code format
invalid-bank-routing-numberInvalid routing number
invalid-bank-account-numberInvalid account number
session-in-progressConcurrent 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

  1. Always use HTTPS for callback URLs
  2. Implement webhook validation
  3. Monitor payment status callbacks
  4. Handle errors gracefully
  5. Store tokens securely
  6. Use appropriate timeout values
  7. Implement proper error handling
  8. Validate all inputs
  9. Monitor transaction patterns
  10. 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

AttributeTypeDefaultDescription
namerequiredstring-The identifier for your custom parameter.
valuerequiredstring-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 StepDescription
payment-card-numberPrompt for credit/debit card number
expiration-datePrompt for card expiration date
security-codePrompt for card security code (CVV)
postal-codePrompt for billing postal code
bank-routing-numberPrompt for bank routing number
bank-account-numberPrompt for bank account number
payment-processingMessage 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:

NounDescription
plain textThe 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:

TypeDescription
audio/mpegmpeg layer 3 audio
audio/wavwav format audio
audio/wavewav format audio
audio/x-wavwav format audio
audio/aiffaudio interchange file format
audio/x-aifcaudio interchange file format
audio/x-aiffaudio interchange file format
audio/x-gsmGSM audio format
audio/gsmGSM 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:

NounDescription
plain textThe 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:

ValueDescription
in-progressSIP REFER accepted and SignalWire received 200 via SIP NOTIFY.
busySIP REFER accepted and SignalWire received 486 or 600 via SIP NOTIFY.
no-answerSIP REFER accepted and SignalWire received 487 via SIP NOTIFY.
canceledSIP REFER accepted, however the call ended before the transfer completed.
failedAn 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:

NounDescription
<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:

NounDescription
plain textThe 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.

TagDescription
<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.

ValueDescription
noneNo pause. Can be used to remove a pause that would normally occur.
x-weakNo pause.
weakTreat adjacent words as if separated by a single comma.
mediumTreat adjacent words as if separated by a single comma.
strongSentence break.
x-strongParagraph break.

level attribute

The level attribute has the following values. Default is moderate.

ValueDescription
strongIncrease the volume and slow down the speaking rate. Speech is louder and slower.
moderateIncrease the volume and slow down the speaking rate, but not as much as strong.
reducedDecrease the volume and speed up the speaking rate. Speech is softer and faster.

alphabet attribute

The alphabet attribute has the following values.

ValueDescription
ipaThe International Phonetic Alphabet (IPA).
x-sampaThe 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.

ValueDescription
silentNo volume.
x-softLowest volume.
softLower volume.
mediumNormal volume.
loudLouder volume.
x-loudLoudest 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.

ValueDescription
x-lowLowest pitch.
lowLower pitch.
mediumNormal pitch.
highHigher pitch.
x-highHighest 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.

ValueDescription
x-slowSlowest rate.
slowSlower rate.
mediumNormal rate.
fastFaster rate.
x-fastFastest rate.

interpret-as attribute

The interpret-as attribute has the following values.

ValueDescription
charactersSpell out each letter.
spell-outSpell out each letter.
cardinalInterpret value as cardinal number.
numberInterpret value as cardinal number.
ordinalInterpret value as ordinal number.
digitsSpell each digit separately.
fractionInterpret value as fraction.
unitInterpret value as measurement.
dateInterpret value as a date. Use format attribute to indicate format of date: mdy, dmy, ymd, md, dm, ym, my, d, m, y.
timeInterpret as a duration of minutes and seconds.
telephoneInterpret as telephone number.
addressInterpret as part of a street address.
interjectionInterpret 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:

ValueDescription
initiatedDialing of a call has begun.
ringingThe call has begun ringing.
answeredThe call has been answered.
completedThe 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&amp;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:

NounDescription
plain textThe 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 ValueMeaningCommon Causes
invalid_urlInvalid WebSocket URL formatURL doesn’t use wss:// protocol
missing_urlNo URL providedurl attribute not specified
invalid_trackInvalid track configurationTrack value not one of: inbound_track, outbound_track, both_tracks
codec_errorCodec not supported or misconfiguredRequested codec not enabled for your account, or multi-channel audio requested (only mono is supported)
connection_refusedRemote endpoint rejected connectionYour WebSocket server refused the connection
connection_refused_timeout_or_ssl_errorConnection timeout or SSL failureWebSocket server unreachable or SSL certificate issues
general_errorInternal stream initialization failedInternal error during stream setup - contact support with StreamSid
Duplicated stream IDStream ID already in useConference already has a stream with this ID
Duplicated stream nameStream name already in useConference 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 ValueSample Rates Available
PCMU (default)8000h
L1616000h, 24000h

Codec Format Examples:

  • PCMU@8000h (default if no codec specified)
  • L16@24000h
  • L16@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.

PropertyDescription
eventThe string value of connected.
protocolDefines the protocol for the WebSocket connection’s lifetime. Value: Call
versionSemantic 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.

PropertyDescription
eventThe string value of start.
sequenceNumberMessage sequence tracking, starting from “1” and incrementing with each message.
startContainer holding stream configuration and metadata details.
start.streamSidThe unique identifier of the Stream.
start.accountSidThe Account identifier that created the Stream.
start.callSidCall session identifier where the stream originated.
start.tracksArray specifying which audio directions will be transmitted. Possible values: ["inbound"], ["outbound"], or ["inbound", "outbound"].
start.customParametersObject containing custom key-value pairs configured during stream creation. Only present when custom parameters are defined.
start.mediaFormatConfiguration details for audio data formatting.
start.mediaFormat.encodingAudio codec format. Possible values: audio/x-mulaw (PCMU), audio/x-L16 (L16).
start.mediaFormat.sampleRateAudio sampling frequency in Hz. Possible values: 8000 (PCMU), 16000 (L16), or 24000 (L16).
start.mediaFormat.channelsAudio 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.

PropertyDescription
eventThe string value of media.
sequenceNumberSequential message counter for ordering, starting at “1” and incrementing per transmission.
mediaContainer with audio data and associated metadata.
media.trackAudio track identifier. One of: inbound or outbound.
media.chunkChunk counter for this track. Starts at “1” and increments with each chunk.
media.timestampPresentation timestamp in milliseconds from the start of the stream.
media.payloadBase64-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.

PropertyDescription
eventThe string value of stop.
sequenceNumberMessage 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.

PropertyDescription
eventEvent type identifier set to dtmf.
sequenceNumberMessage sequence counter.
streamSidStream identifier. Only included for bidirectional streams.
dtmfContainer holding the detected touch-tone details.
dtmf.digitThe digit that was pressed. Values: 0-9, *, #, A-D.
dtmf.durationDuration 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.

PropertyDescription
eventEvent type designation set to mark.
streamSidStream connection identifier. Only included for bidirectional streams.
markContainer with the mark acknowledgment details.
mark.nameThe 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-mulaw with 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.
PropertyDescription
eventSpecifies the message type. Set to "media" for audio data.
streamSidTarget stream identifier for audio playback
mediaContainer object holding the audio payload
media.payloadBase64-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.

PropertyDescription
eventMessage type identifier. Set to "mark" for completion tracking.
streamSidTarget stream identifier for the mark operation
markContainer object with mark details
mark.nameCustom 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.

PropertyDescription
eventMessage type identifier. Set to "clear" for audio interruption.
streamSidTarget 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.

PropertyDescription
eventMessage type identifier. Set to "dtmf" for DTMF injection.
streamSidTarget stream identifier where DTMF should be sent.
dtmfContainer object with DTMF details
dtmf.digitThe 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, inbound represents the audio Signalwire receives from the call, outbound represents 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.

ParametertypeDescription
DialCallSIDstringThe unique identifier for the call.
DialSipHangupDirectionstringThe direction of the hangup.
DialCallStatusstringThe status of the call.
DialCallDurationstringThe duration of the call.
HangupDirectionstringThe 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.

SignalWire Developer Documentation