Skip to main content

SIP Voicemail

Having voicemail available is an important part of any phone system, and calls to SIP endpoints are no exception. There are a couple different ways to handle voicemails for SIP. You could use a Domain Application set up with two cXML application webhooks. The first would dial your SIP endpoint with a timeout parameter. The second would record a voicemail if the call was not answered within the timeout time.

To demonstrate how to set this up without a Domain application, this example will accomplish the same task with the Compatibility SDK with Python. We will configure a DID (SignalWire phone number) to accept incoming calls and dial our SIP endpoint, then record a voicemail if the call is unanswered. You can clone the GitHub repo to follow along, test, and change to meet your needs.

Setup Your Environment

First, you need to provide the application with environmental variables. Copy the contents of env.example and save them in a new file called .env. Fill in your SignalWire credentials.

# Project ID copied from the API Credentials in your SignalWire Space
PROJECT_ID=
# API token copied from the API Credentials in your SignalWire Space
API_TOKEN=
# Your SignalWire Space URL copied from the API Credentials in your SignalWire Space
SIGNALWIRE_URL=

If you need help finding this information, check out our guide to Navigating Your SignalWire Space.

The Compatibility SDK will pull these environmental variables from the .env file without any import statement as long as the .env file is in the same parent directory.

Run Your Server

This example serves our webhooks using a Flask server. After your environmental variables are set, you can install dependencies with pipenv install then start the Flask server with pipenv run dev. If you prefer to use Docker, build the image with docker build -t sipvoicemail . and run it with docker run --p 3000:3000 --env-file .env sipvoicemail.

Test Endpoints with Ngrok

Now, we need a way for our SignalWire service to reach those webhooks. SignalWire requires that your webhooks be publicly accessible for them to be used with our services. So, we recommend using Ngrok to provide an HTTPS URL for testing. In your Ngrok CLI, run ngrok http 3000, where 3000 is the port we set in our Flask server. It will return a secure URL you can copy for the next step.

Configure a Number to Accept Incoming Calls

For this voicemail setup, a phone number is the intermediary that accepts incoming calls and dials your SIP endpoint. In your SignalWire Dashboard, you can purchase a phone number and edit its settings to direct calls to the Ngrok URL. The settings for your phone number of choice will look something like this:

A screenshot of the edit pane for a given phone number in the Phone Numbers tab.
Phone number settings

With your server and Ngrok running, you should now be able to dial this number and test this example.

Code Walkthrough

All the logic of our program lives within the index.py file. It is a simple Flask server serving just three POST routes: an entry route, a voicemail route, and a hangup route.

When a call comes in, our setup will hit the default endpoint we have defined. It says a message then dials our SIP endpoint. It is important to note that our dial method has a 15 second timeout before its "action" redirects it to the voicemail route.

The voicemail route will confirm that the call status is "completed" then ask the caller to record a message. It then starts a recording, and its "action" directs the call the the hangup route when the recording finishes.

The hangup route receives the recording object then hangs up the call.

You will notice that these routes all use the same syntax to use the Compatibility SDK. We generate XML to run and send it with the following lines.

response = VoiceResponse()

# logic with XML verbs, for example:
response.say("Welcome to SignalWire.")

return Response(str(response), mimetype="text/xml")

Following the same pattern, you can use cXML to extend this example to suit your needs.

Wrap Up

This guide shows you one of the ways to set up voicemail if your phone system ends at SIP endpoints.

For an example of a full IVR using the Python Compatibility SDK, see Dynamic IVR using Python. Although that example dials numbers, you can easily substitute SIP endpoints as we did here.