IVR with Voicemails Forwarded to Email - Node.js
Overview
This advanced example builds an application that implements a simple phone tree IVR with a few interesting features, including:
- Parallel dialing to multiple phone numbers
- Recording a voicemail and using a dynamic greeting
- Transcribing voicemail and sending both the text and the recording via email
What do you need to run this code?
Check out the full code on our Github Repository here
You will need the SignalWire Node.JS SDK, and your SignalWire Credentials. You can find these by logging into your SignalWire space and navigating to the API tab. For more information on navigating your SignalWire space check here
The application also uses the Express web framework and Mailgun to send the emails, and you will need an API key from that service. You could also use any other email API.
Running the application
Setup Your Environment File
- Copy from example.env
- Save new file called .env
- Fill in the fields with your own values
PRIMARY_SALES=+15557788999
SECONDARY_SALES=+15554433222
RECRUITERS_GROUP=+15556677888,+15559998877
ACCOUNTING_GROUP=+15554455777
JOBS_EMAIL=jobs@yourdomain.com
ACCOUNT_EMAIL=accounts@yourdomain.com
EMAIL_FROM=me@samples.mailgun.org
MAILGUN_DOMAIN=your-Mailgun-domain
MAILGUN_API_KEY=your-Mailgun-api-key
Build and run via Docker
It is simpler to run the application via Docker, by first building the image with docker build -t nodeivr .
followed by docker run -it --rm -p 3000:3000 --name nodeivr --env-file .env nodeivr
.
Build and Run locally
If you are running the application locally, first load the .env
file with set -o allexport; source .env; set +o allexport
, then run npm install
followed by npm start
.
When you configure a SignalWire number to test, you should add /entry
to the end of the URL you input, such as https://yourname.ngrok.io/entry
.
Otherwise, simply head to http://localhost:3000
Step by Step Code Walkthrough
In the Github Repo there are 6 files. We are mainly concerned with the env.example
which we will use to set up our .env
file, and index.js
where the application lives.
Entry
The core of the application is the entry
route, where we ask for the user's choice via DTMF.
app.post("/entry", (req, res, next) => {
var response = new RestClient.LaML.VoiceResponse();
gather = response.gather({ timeout: 5, numDigits: 1, action: formatUrl("mainmenu") });
gather.say("Hello! Press 1 for sales, 2 for recruiting or 4 for accounting.");
respondAndLog(res, response);
});
The SignalWire Compatibility APIs require that code is translated into XML, so here is the XML version of what the code above does!
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Gather timeout="5" numDigits="1" action="/mainmenu">
<Say>Hello! Press 1 for sales, 2 for recruiting or 4 for accounting.</Say>
</Gather>
</Response>
MainMenu
Based on what number the user inputs, we then redirect to the correct action in the mainmenu
handler. Whether the user dials sales, recruiting, or accounting, you can see below that we dial every member of the group at the same time. When one person picks up, the rest of the calls will be terminated.
app.post("/mainmenu", (req, res, next) => {
console.log(req.body);
var response = new RestClient.LaML.VoiceResponse();
switch (req.body.Digits) {
case "2":
dial = response.dial({
timeout: 20,
action: formatUrl("voicemail", "?Email=" + JOBS_EMAIL + "&Message=Recruiting"),
});
var recruiters = RECRUITERS_GROUP.split(",");
recruiters.forEach(function (item) {
dial.number(item);
});
break;
case "4":
dial = response.dial({
timeout: 20,
action: formatUrl("voicemail", "?Email=" + ACCOUNT_EMAIL + "&Message=Accounting"),
});
dial.number(ACCOUNTING_GROUP);
break;
default:
dial = response.dial({ timeout: 20, action: formatUrl("primarysalesdial") });
dial.number(PRIMARY_SALES);
}
respondAndLog(res, response);
});
For example, if the caller enters 2
, this is the XML that is returned. Multiple <Number>
entries are dialed at the same time, the first one to pick up hangs up the other.
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial timeout="20" action="/voicemail?Email=jobs@yourdomain.com&Message=Recruiting">
<Number>+15556677888</Number>
<Number>+15559998877</Number>
</Dial>
</Response>