SignalWire Status Callbacks

SignalWire allows for a variety of different types of callbacks that allow you to keep an eye on your traffic and perform actions based on incoming events.

What are status callbacks?

Status callbacks allow you to set up a form of event tracking that sends data to the webhook you specify on every status change. The type of data depends on the product: SMS status callbacks will show message status changes whereas recording status callbacks will update when a recording is completed.

In the sections below is comprehensive data on each type of status callback and examples of how to use them. You could easily build a system to monitor your throughput or delivery rate with SMS, push calls logs to your CRM, or simply send recordings via SMS when they are created. The possibilities of what to do with this data are endless!

Testing Status Callbacks

If you are building a status callback application and would like a full printout of all of the possible parameters you can use in your application, a helpful tool is webhook site! You can copy the unique URL on webhook site to use as your status callback url and you will see all the headers, form data, and query strings if there are any. This is a good way to see examples of the data returned as well as get exact parameter names.

We recommend using ngrok as a tunnel for local testing if you don't want to host this script on your own server. You can read more about ngrok here.

To run these exact examples, you will need the Flask framework and Python SignalWire SDK downloaded. However, you could recreate them or write your own example using any of the SignalWire SDKs and a web framework.

One of the most important parts of voice and SMS status callbacks is the error code for when things go amiss. You can read more about the possible error codes and what they mean here.

SMS Status Callbacks

One of the most popularly used forms of status callbacks is the SMS status callback! As messaging can often be high volume, it's crucial to be able to keep track of how your messaging campaigns are performing and handle any errors that start to pop up.

SMS status callbacks will allow SignalWire to make an HTTP request to your specified callback URL with the message status and error code (if present). Your app can use these parameters to keep track of delivery status, calculate the delivery rate, monitor throughput, monitor for emerging errors, and much more.

SMS Status Callback Parameter

The following parameters will be posted via an HTTP request to your webhook - you can use one or all of them depending on what type of information you are looking for.

Parameter Name

Parameter Description

Parameter Type

MessageStatus

The current status of the message at the time of the callback.

string

ErrorCode

If your message has failed or is undelivered, the error code may provide you with more information about what went wrong.

string

MessageSid

The unique ID of this message.

string

AccountSid

The unique ID of the project this message is associated with.

string

From

The 'From' number of the message

string

To

The 'To' number of the message

string

Body

The body of the message

string

NumMedia

The number of media files that were included with the message

integer

NumSegments

The number of segments that make up the entire message. If the body of the message is larger than 160 GSM-7 characters or 70 UCS-2 characters, it will automatically be broken up into smaller messages and annotated to attempt proper reconstruction on the recipient handset. Read more about this here.

integer

How to Set SMS Status Callbacks

You can set up SMS status callbacks in your API request for an outgoing message by using the StatusCallback parameter.

There are 8 possible SMS statuses that are expanded upon below.

Message Status

Description of Status

queued

The API request to send this message was processed successfully, and the message is currently waiting to be sent out. Read more about our queuing system here.

sending

The message is currently being transmitted by SignalWire to the nearest carrier upstream in the network.

sent

The nearest carrier upstream in the network has accepted the message.

delivered

Confirmation of receipt of the message by the nearest carrier upstream in the network.

undelivered

SignalWire has received notice from the nearest carrier upstream in the network that the message was not delivered.

failed

SignalWire could not send the message. There is no charge for failed messages.

receiving

SignalWire has received and is currently processing an inbound message.

received

The message has been received by one of the numbers in your account. Applies to inbound messages only.

📘

"Sent" vs "Delivered

SignalWire can’t and won’t show a message as Delivered unless we can 100% confirm delivery to the end network by getting a Delivery Receipt (DLR) from the receiving carrier. A status of Sent means that the message left SignalWire successfully and reached our downstream peer. Once we receive the Delivery Receipt indicating that the message entered the end carrier's network, it switches to Delivered.

If you see a message with a status of Delivered that did not reach the end handset, feel free to open a support ticket with the message SID for us to escalate the example to our carrier partners to find out why the MNOs (Verizon, AT&T, T-Mobile, etc) marked it as Delivered.

Some carriers may send delayed DLRs, and others may not send DLRs at all. Providers do not currently allow for any DLRs for MMS, so you will only ever see the status Sent.

You can also fetch messages individually or delete messages using our retrieve message API and delete message API!

SMS Status Callbacks Application Example

Below is an example of a simple delivery status tracker that could begin running before a message campaign goes out and end when a message campaign ends. While the app is running, it will log the status change event of every single message to the console with the following information: MessageStatus, MessageSid, and ErrorCode. This will happen for every outbound message in the same project that includes this script as the StatusCallback URL.

When a message returns a status of failed or undelivered, it will be added to a table that keeps track of all unsuccessful messages along with their MessageSid, MessageStatus, ErrorCode, ErrorMessage, DateSent, To, From, and Body. After every failed/undelivered message, this table will be printed so the updated list can be seen.

When the messaging campaign is over and the Flask app is closed, the whole table will be exported to CSV so that failed/undelivered messages can be easily investigated.

In the output below, you can see successful messages logged to the console as well as the table being updated when messages fail to deliver for any reason.

from flask import Flask, request
import logging
import pandas as pd
from signalwire.rest import Client as signalwire_client
import atexit

logging.basicConfig(level=logging.INFO)
app = Flask(__name__)

# create an empty array to keep track of all of our undelivered 
# or failed messages during the time this app is run
undeliveredArray = []

# define actions to take when flask app is closed 
# export dataframe of all failed or undelivered 
# messages to CSV with added detail 
def onExitApp(dataframe):
    dataframe.to_csv('failedAndUndeliveredMessages.csv', index=False, encoding='utf-8')
    print('SMS Callback App Exited')

# authenticate the SignalWire client
client = signalwire_client("ProjectID",
                           "AuthToken",
                           signalwire_space_url='YOUR_SPACE.signalwire.com')

# define route for SMS status callbacks to be posted to 
@app.route("/smsErrorTracker", methods=['POST'])
def newest_message():
    # get message sid, message status, and error code (if it exists) from callback parameters
    # if they don't exist, set to None 
    message_sid = request.values.get('MessageSid', None)
    message_status = request.values.get('MessageStatus', None)
    error_code = request.values.get('ErrorCode', None)
    
    # log every message that comes in to console 
    logging.info('SID: {}, Status: {}, ErrorCode: {}'.format(message_sid, message_status, error_code))
        
    # if the message is undelivered or failed, use message SID to fetch additional data 
    # about the failed message 
    if (message_status == "undelivered" or message_status == "failed"):
        message = client.messages(message_sid).fetch()
        
        # add identifying data from newest message to undelivered array 
        undeliveredArray.append([message_sid, message_status, error_code, message.error_message, message.date_sent, message.to, message.from_, message.body])
        # insert array into dataframe with columns for easier reading 
        df = pd.DataFrame(undeliveredArray, columns=('Message Sid', 'Message Status', 'Error Code', 'Error Message', 'Date Sent', 'To', 'From', 'Body'))
        # print dataframe to string for nicer formatting and set dataframe to our parameter in function for handling app exit 
        print(df.to_string())
        atexit.register(onExitApp, dataframe=df)
        
        # return 200OK 
    return ('', 200)

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

Voice Status Callbacks

Voice status callbacks allow you to get an advanced view of how your call center is performing in real-time as well as key analytics that can be used to track performance. Callback applications could be as simple as tracking failures or as complex as full-scale real-time monitoring of in-progress calls.

Voice status callbacks will allow SignalWire to make an HTTP request to your specified callback URL with the ForwardedFrom, CallerName, CallDuration, RecordingURL, RecordingSid, RecordingDuration, Timestamp, CallbackSource, and SequenceNumber. Your app can use these parameters to keep track of any associated recordings, caller info, average times of calls, or simply monitoring for failures.

Voice Status Callback Parameter

The following parameters will be posted via an HTTP request to your webhook - you can use one or all of them depending on what type of information you are looking for.

Parameter Name

Parameter Description

Parameter Type

ForwardedFrom

The number this call was forwarded from.

string

CallerName

The name of the caller. Only available if Caller ID lookup is enabled.

string

CallDuration

The duration, in seconds, of the finished call. Only present on the completed event.

integer

RecordingUrl

The URL of the recorded audio call

string

RecordingSid

The unique identifier for the audio recording

string

RecordingDuration

The duration, in seconds, of the recording

integer

CallbackSource

The source of the status callback

string

Timestamp

The timestamp, in RFC 2822 format, of when the event occurred.

string

SequenceNumber

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.

integer

CallSid

A unique identifier for the call.

string

AccountSid

The unique ID of the project this call is associated with.

string

From

The phone number that sent this call, in E.164 format.

string

To

The phone number of the call recipient, in E.164 format.

string

CallStatus

The status of the call. Can be one of the following values: ringing, in-progress, queued, failed, busy, no-answer, or completed.

string

ApiVersion

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.

string

Direction

An identifier to describe the direction of the call:
outbound-dial: calls launched through the verb
outbound-api: calls launched through the REST API
inbound: for inbound calls

string

ParentCallSid

A unique identifier for the call that created this call.

string

How to Set Voice Status Callbacks

You can use the StatusCallback while creating a call via the API or using Dial with Number, SIP, or Conference to get notifications with these parameters when the call is completed.

Alternatively, you can get every call progress event posted to your StatusCallbackURL parameter along with information about the call state as well as several helpful request parameters by using StatusCallbackEvent.

Once a call is created, it progresses through multiple states until it is finally completed. There are 8 possible call statuses that are expanded upon below:

Call Status

Status Description

ringing

The call is ringing

in-progress

The call was answered and is in progress.

queued

The call is ready and in line to initiate.

failed

The call could not be completed. Usually occurs when phone number does not exist.

busy

The caller encountered a busy signal.

no-answer

The call ended without an answer.

completed

The call was answered and ended normally.

canceled

The REST API canceled the call while it was ringing or queued.

You can also fetch messages individually or delete calls using our retrieve call API and delete call API!

Voice Status Callbacks Application Example

Below is an example of a simple call status tracker that will log every status change event ('initiated' to 'ringing', 'ringing' to 'answered', etc) to the console along with the CallSID, CallStatus, Timestamp, and Direction. If a call has reached an end-stage state, i.e. completed, canceled, no-answer, or busy`, it will be added to our table of call records. This table will exclude failed calls and in-progress calls so as to not have duplicate records.

If a call fails, it will be added to a separate table containing failed calls along with relevant data to investigate later. If at any point the number of failed calls in the table reaches 100, the table will be downloaded to CSV and an SMS alert will be sent out to notify whoever would be in charge of dealing with the failures. After the CSV has been downloaded and the alert has been sent, we will clear the failed calls array so it can begin appending new failed calls again.

After every call is appended to either of the tables, the tables will reprint so that it's easy to see the updated list of completed and failed calls. Below you can see the status alerts printed out for each call in red and the table that contains all of the completed calls along with relevant data.

For example sake, the script was changed to alert of call failures at 5 calls instead of 100. However, you can see below the table of 5 failed calls and console log statement confirming that the CSV was downloaded and the SMS alert was sent.

from flask import Flask, request
import logging
import pandas as pd
from signalwire.rest import Client as signalwire_client

logging.basicConfig(level=logging.INFO)
app = Flask(__name__)

# create empty arrays to store our call records - one for failed only and one to handle all other end stage statuses (not queued, not ringing, not answered, etc)
failedCallArray = []
allCallArray = []

# authenticate the SignalWire client
client = signalwire_client("ProjectID",
                           "AuthToken",
                           signalwire_space_url='example-space.signalwire.com')


@app.route("/CallStatus", methods=['POST'])
def incoming_calls():
    # grab incoming parameters posted to webhook and assign them variables
    call_sid = request.values.get('CallSid', None)
    call_status = request.values.get('CallStatus', None)
    event_timestamp = request.values.get('Timestamp', None)
    recording_url = request.values.get('RecordingUrl', None)
    call_direction = request.values.get('Direction', None)
    to_number = request.values.get('To', None)
    from_number = request.values.get('From', None)

    # log some basic information to print to console for EVERY status change
    logging.info('SID: {}, Status: {}, Timestamp: {}, Direction: {}'.format(call_sid, call_status, event_timestamp, call_direction))

    # create a separate array for all end stage statuse updates and add them to our call log table, display updated table
    if (call_status != 'ringing' and call_status != 'initiated' and call_status != 'answered' and call_status != 'in-progress' and call_status != 'queued' and call_status != 'failed'):
        allCallArray.append([call_sid, call_status, event_timestamp, call_direction, to_number, from_number, recording_url])
        adf = pd.DataFrame(allCallArray, columns=('Call SID', 'Call Status', 'Event Timestamp', 'Call Direction', 'To Number', 'From Number',
        'Recording URL (if present)'))
        print("All Calls")
        print(adf.to_string())

    # if call status is failed, log call record to call failure table and display table
    if (call_status == "failed"):
        failedCallArray.append([call_sid, call_status, event_timestamp, call_direction, to_number, from_number, recording_url])
        df = pd.DataFrame(failedCallArray, columns=('Call SID', 'Call Status', 'Event Timestamp', 'Call Direction', 'To Number', 'From Number', 'Recording URL (if present)'))
        print("Failed Calls")
        print(df.to_string())

        # if the number of failed calls is over 100
        if len(failedCallArray) > 100:
            # download call logs with necessary data to CSV and send an sms alert of the failures
            df.to_csv('failedCallReport.csv', index=False, encoding='utf-8')
            m = client.messages.create(
                body='Call Failure Alert! You have received 100 call failures. '
                     'A CSV of the failures has been downloaded and the failure database will now reset.',
                from_='+1xxxxxxxxxx',
                to='+1xxxxxxxxxx')
            print("CSV of Failed Calls Downloaded & Message Alert Sent")

            # clear array to start adding fresh logs again
            while len(failedCallArray) > 0:
                failedCallArray.pop()

    # Return 200 OK
    return ('', 200)

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

Recording Status Callbacks

A vital feature for working with inbound/outbound calls is call recording. If you're actively recording a call, the recording may not be available immediately. When there is a high volume of calls, it can be difficult to individually retrieve/handle each recording within your portal.

Recording status callbacks will allow SignalWire to make an HTTP request to your specified callback URL with the recording file as well as some other additional parameters. Your app can use these parameters to handle the recording whether by uploading the recording somewhere, pushing to external storage, sending via email, or maybe even using SignalWire SMS to forward the recording URL!

Recording Status Callback Parameters

The following parameters will be posted via an HTTP request to your webhook - you can use one or all of them depending on what type of information you are looking for.

Parameter Name

Parameter Description

Parameter Type

AccountSid

The unique ID of the project this call is associated with.

String

CallSid

A unique identifier for the call. May be used to later retrieve this message from the REST API.

String

RecordingSid

The unique identifier for the recording.

String

RecordingUrl

The URL for the audio recording.

String

RecordingStatus

The status of the recording.

String

RecordingDuration

The duration, in seconds, of the recording.

Integer

RecordingChannels

The number of channels in the recording.

Integer

RecordingSource

The type of call that initiated the recording.

String

How to Set Recording Status Callbacks & Recording Status Callback Events

You can set up recording status callbacks in your API request for an outgoing call or by using Dial, Conference, or Record.

You can use recordingStatusCallbackEvent to specify multiple events that you want your callback URL to receive HTTP requests for, but if you do not specify it will default to completed.

Call Recordings have three possible statuses.

Call Status

Status Description

in-progress

This status occurs as soon as the call recording has begun

completed

This status occurs when the file is available for access.

absent

The call recording was too short to be processed or the call was silent so no audio was detected.

You can also fetch recordings individually or delete recordings using our retrieve recording API and delete recording API!

Recording Status Callback Application Example

Below is an example of an application that could be used to process incoming recordings and forward them to a specific person. We need to use request.form.get('ParameterName') in order to gather the CallSid and RecordingUrl parameters and store them in their own variables. If you want to include more parameters either to print to console or include in the message, you can gather them using the same format here.

We then create a SignalWire client object with our project details and authentication. All that's left there is to create a message object and send all of the necessary information within the Body with the To number being the end destination number and the From number being a SignalWire number.

from flask import Flask, request
from signalwire.rest import Client as signalwire_client

app = Flask(__name__)


@app.route("/sendRecording", methods=["POST"])
def message():
    # accept incoming parameters and store them. Feel free to add any extra parameters that you would like to print to
    # to console or add to your message. This example will show CallSID and recording URL.
    call_sid = request.form.get('CallSid')
    recording_url = request.form.get('RecordingUrl')

    # create a client object connected to our account & project
  client = signalwire_client("ProjectID", "AuthToken", signalwire_space_url = 'YOURSPACE.signalwire.com')

    # create a text message and send ourselves the text
    m = client.messages.create(
        body='You have received a voicemail. Listen to the recording here: "' + recording_url +
             '". The Call SID is ' + call_sid,
        from_='+1xxxxxxxxxx',
        to='+1xxxxxxxxxx'
    )
    return recording_url

Transcription Status Callbacks

If you are already using recordings, you may also want to transcribe them as well! Transcription callbacks will allow SignalWire to make an HTTP request to your specified callback URL with the transcription text as well as some other additional parameters. Your app can use these parameters to handle the transcription by uploading to your CRM, sending via email, or maybe even using SignalWire SMS to forward the body of the transcription!

Transcription Status Callback Parameters

The following parameters will be posted via an HTTP request to your webhook - you can use one or all of them depending on what type of information you are looking for.

Parameter Title

Parameter Description

Parameter Type

TranscriptionSid

The unique, 34 character ID of the transcription.

String

TranscriptionText

The text of the transcription.

String

TranscriptionStatus

The status of the transcription (completed or failed).

String

TranscriptionUrl

The URL for the transcription's REST API resource.

String

RecordingSid

The unique, 34 character identifier for the recording from which the transcription was generated from.

String

RecordingUrl

The URL for the audio recording from which the transcription was generated from.

String

How to Set Transcription Status Callbacks

You can set up transcription status callbacks by using Record and setting transcribe to True and transcribeCallback to your webhook URL.

You can also fetch transcriptions individually or delete transcriptions using our retrieve transcription API and delete transcription API!

Transcription Status Callback Application Example

Below is an example of an application that could be used for transcription status callbacks to process incoming transcriptions and forward them to someone's phone number. We need to use request.form.get('ParameterName') in order to gather the CallSid, TranscriptionText, and From number parameters and store them in their own variables. If you want to include more parameters either to print to console or include in the message, you can gather them using the same format here.

We then create a SignalWire client object with our project details and authentication. All that's left there is to create a message object and send all of the necessary information within the Body with the To number being the end destination number and the From number being a SignalWire number.

@app.route("/message", methods=["POST"])
def message():
    # gather necessary paramters and store them in an accessible variable 
    call_sid = request.form.get('CallSid')
    transcription_text = request.form.get('TranscriptionText')
    from_number = request.form.get('From')

    # create a client object connected to our account & project
    client = signalwire_client("ProjectID", "AuthToken", signalwire_space_url = 'YOURSPACE.signalwire.com')

    # create a text message and the text with necessary parameters 
    m = client.messages.create(
        body='You have received a voicemail from the number ' + from_number +
             '. The voicemail transcription is as follows: "' + transcription_text +
             '" and the Call SID is ' + call_sid,
        from_='+1xxxxxxxxxx',
        to='+1xxxxxxxxxx'
    )
    return transcription_text

Did this page help you?