I need to start with a disclaimer. I strongly dislike robocalls. So much so that I no longer answer my phone if I do not recognize the caller. While that has caused me to miss a few important telephone calls, it has also saved me a tremendous amount of aggravation. Robocalls are also more than just an annoyance. More often than not, they are scams trying to separate me from my money and/or personal information. That said, I still want to show you how you can use Avaya CPaaS APIs and inboundXML to write a robocall service of your very own.
To ease the pain, perhaps I shouldn’t refer to them as robocalls. So, for the remainder of this article, think about writing an outbound voice campaign application that can be used to spread useful information via the telephone network.
The key to a voice campaign is the outbound call and the Avaya CPaaS Make Call REST API makes that easy. At its core, you need two telephone numbers — the caller and the called. Since we are using CPaaS, the caller will be a CPaaS number. You can purchase your own number from the CPaaS Dashboard. The called number is whoever you wish to bother with your useful information — just don’t let it be me.
Next, you need the useful information. This comes from a script that executes when the outbound call is answered. In the world of CPaaS, this script is provided by inboundXML elements. The inboundXML elements can perform something as simple as speak a bunch of text once the call has been answered, or they can provide IVR-like functionality for a dynamic conversation with the called party.
The beauty of the Make Call API is that it doesn’t care what happens after the call has been answered. Its job it to make the call and then get out of the way.
To help visualize this in code, I’ve put together a simple application that reads data from command line arguments and then kicks off the make call and inboundXML process.
The arguments are:
--called=<ten digit telephone number> # The called party
-v # If present, instruct CPaaS to release the call if an answering machine is detected
Since this is a node.js application, all invocations begin with “node <application-name> <arguments>.”
Here are two invocation examples for an application I called voiceCampaign.js:
node voiceCampaign.js --called=6512345678
node voiceCampaign.js --called=6512345678 -v
Got all that? Great! Let’s take a look at my sample application.
/* This application uses Avaya CPaaS to make a call and launch an inboundXML script once the call has been answered. It takes two parameters: --called=xxxxxxxxxx -- Required. The 10-digit called party -v -- Optional. Hangup if an answering machine is detected. For example: node voiceCampaign --called=6512307765 -v CPAAS_XML_URL refers to a CPaaS XML Bin that contains instruction to be executed once the call answers. The URL in the application will cause the words "This is a robocall. Please do not hang-up on me." to be spoken the the called party. You are free to create any XML script that you choose. */ const request = require('request-promise'); const CPAAS_MAKE_CALL = "/Calls.json" // Set the following to match your environment const CPAAS_URL = "https://api-us.cpaas.avayacloud.com/v2/Accounts/"; const CPAAS_USER = "CPAAS Account SID"; const CPAAS_TOKEN = "CPaaS Auth Token"; const CPAAS_FROM = "CPaaS Telephone Number in E.164 Format"; const CPAAS_XML_URL = "https://us.cpaas.avayacloud.com/data/inboundxml/e23a1327b8a45db6804a8f8087d32cb940bfe9c1"; const ARGS = getArgs(); // Retrieve command line arguments makeVoiceCall(); async function makeVoiceCall() { if (ARGS.hasOwnProperty("called")) { calledParty = "+1" + ARGS.called; // Put the number in E.164 format const auth = "Basic " + Buffer.from(CPAAS_USER + ":" + CPAAS_TOKEN, "utf-8").toString("base64"); parameters = `From=${CPAAS_FROM}&To=${calledParty}&Url=${CPAAS_XML_URL}`; if (ARGS.hasOwnProperty("v")) { parameters += "&IfMachine=hangup"; } options = { url: `${CPAAS_URL}${CPAAS_USER}${CPAAS_MAKE_CALL}`, headers: {'Content-Type' : 'text/plain', 'Accept' : 'application/json', 'Authorization' : auth}, body: parameters, method: 'POST' } var response = await request.post(options, function(e , r , body) { }); } } /* Get command line arguments and return them in a JSON object */ function getArgs () { const args = {}; // The first two arguments are "node" and the node file process.argv .slice(2, process.argv.length) .forEach( arg => { // long arg if (arg.slice(0,2) === '--') { const longArg = arg.split('='); const longArgFlag = longArg[0].slice(2,longArg[0].length); const longArgValue = longArg.length > 1 ? longArg[1] : true; args[longArgFlag] = longArgValue; } // flags else if (arg[0] === '-') { const flags = arg.slice(1,arg.length).split(''); flags.forEach(flag => { args[flag] = true; }); } }); return args; }
You have the option of using the CPaaS node.js helper library to make the Make Call request, but in this case I chose to invoke the REST API directly. To see a similar example where I use the helper library to send an SMS text, take a look at the second application in Building Communications Applications Using Avaya OneCloud CPaaS.
You are more than welcome to use my inboundXML URL, but I suggest writing one of your own. It’s easy to do that with the XML Bins tool found on the CPaaS Dashboard. The URL I use points to a script that contains:
<Response>
<Say language=”en” voice=”female”>This is a robocall. Please do not hangup on me.</Say>
</Response>
Check out the inboundXML documentation to learn how to add powerful functionality such as call recording into your script.
You may find the getArgs() function useful for other node.js applications. I’ve used it in several command line solutions I’ve written.
Mischief Managed
I hope you found this useful. While my sample application only makes one campaign call per invocation, it wouldn’t be too difficult to read numbers from a database and place lots of calls. That way you can be annoying to as many people as you’d like in a very efficient and extremely inexpensive manner.
As always, feel free to reach out to me with any questions you might have. I am here to help.