Build a Simple dynamic IVR

How to build your own IVR with SignalWire

Stack Engineer Kevin Garabedian

In a very useful code snippet, Kevin takes the well known functionality of an IVR (interactive voice response) system and introduces a simple yet effective mechanism to make it almost infinitely flexible.

We're all familiar with the menu system that greets us on many of the calls we make to companies these days. They are, perhaps, loved (by the companies using them for effective call direction) and hated (by those calling the companies) in equal measure and yet by applying some good sense to their construction they can be more palatable to callers.

Learn more about how to build and IVR that won't send your customers running. 

This is where Kevin's mechanism comes in... He's cleverly created a framework that can then be populated with the contents of a JSON file, thus making menu systems both flexible and scalable without having to go back to the code!

Check out the instructions and code below:

Getting Started

You will need a machine with Python installed, the SignalWire SDK, a provisioned SignalWire phone number, and optionaly Docker if you decide to run it in a container.

For this demo we will be using Python, but more languages may soon become available.

Running Simple Dynamic IVR - Methods and Endpoints
Endpoint: /get_menu
Methods: GET OR POST
Requests generate a menu, it will default to main menu if no menu is specified.  The get_menu, will look for dtmf entries to select action for routing and moving along a menu tree.
Endpoint: /get_voicemail
Methods: GET OR POST
Requests to get_voicemail, produce a LaML Voice response to simulate an endpoint.

Setup Your Menus
  • Edit the menus.json file
  • This example file has 3 menus. Each menu contains an index, which is equal to the keypress on the menu, a verbiage, and an action.
  "main": {
    "1": {
      "verbiage": "For sales press 1",
      "action": "/get_menu?menu=sales"
    "2": {
      "verbiage": "For tech support press 2",
      "action": "/get_menu?menu=tech"
  "sales": {
    "1": {
      "verbiage": "For partners, press 1",
      "action": "/get_voicemail?group=sale_partners"
    "2": {
      "verbiage": "For assistance with a purchase, press 2",
      "action": "/get_voicemail?group=sale_support"
  "tech": {
    "1": {
      "verbiage": "For issues with your internet, press 1",
      "action": "/get_voicemail?group=internet_support"
    "2": {
      "verbiage": "For issues with your cell phone, press 2",
      "action": "/get_voicemail?group=mobile_support"

Setup Your Environment File
  • Copy from example.env and fill in your values
  • Save new file called .env
  • Your file should look something like this:
## This is the full name of your SignalWire Space. e.g.:
# Your Project ID - you can find it on the `API` page in your Dashboard.
# Your API token - you can generate one on the `API` page in your Dashboard
# The phone number you'll be using for this Snippets. Must include the `+1` , e$
# Hostname

Build and Run on Docker

Let's get started!

  • Use our pre-built image from Docker Hub
    For Python:
    docker pull signalwire/snippets-simple-dynamic-ivr:python

    (or build your own image)

    • Build your image
    docker build -t snippets-simple-dynamic-ivr .
    • Run your image:
    docker run --publish 5000:5000 --env-file .env snippets-simple-dynamic-ivr
    • The application will run on port 5000

    Build and Run Natively
    1. Replace environment variables
    2. From command line run, python3

    More Documentation

    You can find more documentation on LaML, Relay, and all Signalwire APIs at:


    If you have any questions, please open an issue on this repo or join our fantastic Slack community and chat with others in the SignalWire community!

    If you need assistance or support with your SignalWire services please file a support ticket from your Dashboard.