# Make a call and basic IVR menu with Node.js You can quickly see how the Voice API works by calling yourself using the API and playing a basic IVR menu. ## What you need to know before you start Before you can get started, you need the following already set up: * Set all Voice API [configuration settings](/docs/voice/getting-started). * [NPM](https://www.npmjs.com/) and a familiarity with how to install packages. * [Node.js](https://nodejs.org/en/) and a familiarity with how to create a new app. * [Ngrok](https://ngrok.com/) to create a public URL to your localhosted node backend ## Set up your Node.js application Create a new node app with npm. ```shell npm init ``` Accept the defaults for the application. ### Install your dependencies Add the fetch package with npm to generate the necessary dependencies. ```shell npm install 'body-parser' npm install 'express' npm install 'axios' npm install 'ngrok' ``` ## Create the files you will need Create a new file named **index.js** in the project and paste the provided "index.js" code into the file. index.js const express = require('express'); const bodyParser = require("body-parser"); const ngrok = require('ngrok'); const axios = require('axios') const PORT = 8081; const app = express(); app.use(bodyParser.json()); const APPLICATION_KEY = '' const APPLICATION_SECRET = '' const CLI = '' const TO_NUMBER = '' const eq = '\"' app.post('/', async (req, res) => { let eventName = req.body.event; //console.log(`:: INCOMING HTTP BODY :: ", req.body) switch (eventName){ case 'pie': var value = req.body.menuResult.value; console.log(`:: INCOMING EVENT ::`, req.body.event) //console.log(`:: INCOMING EVENT BODY ::`, req.body) console.log(`:: IVR MENU CHOICE :: Destination: `, TO_NUMBER, `selected value: `, value); case 'dice': console.log(`:: INCOMING EVENT ::`, req.body.event) //console.log(`:: INCOMING EVENT BODY ::`, req.body) res.sendStatus(200); break; default: //console.log(`:: INCOMING HTTP BODY::`, req.body) console.log(`:: ERROR :: Sorry, there was an error with your request. Please inspect HTTP body above`); res.sendStatus(404); } }); function calloutRunMenu(url) { axios({ method: 'post', url: 'https://calling.api.sinch.com/calling/v1/callouts', data: { "method": "CustomCallout", "customCallout": { "ice": "{\"action\": {\"name\": \"ConnectPstn\",\"number\": "+eq+TO_NUMBER+eq+",\"cli\": "+eq+CLI+eq+"}}", "ace": "{\"action\": {\"name\": \"RunMenu\",\"locale\": \"en-US\",\"menus\": [{\"id\": \"main\",\"mainPrompt\": \"#tts[ Welcome to the main menu. Press 1 to confirm order or 2 to cancel]\",\"timeoutMills\": 5000,\"options\": [ {\"dtmf\": \"1\",\"action\": \"return(confirm)\"}, {\"dtmf\": \"2\",\"action\": \"return(cancel)\"}]}]}}", "pie" : url, "dice" : url }}, auth: { username: APPLICATION_KEY, password: APPLICATION_SECRET }, headers: { 'content-type': 'application/json' } }).then((response) => { console.log(`:: INFO :: Custom Callout Data: ${response.config.data}`); }, (error) => { console.log(error); }); }; app.listen(PORT, async () => { const url = await ngrok.connect(PORT); console.log(`:: INFO :: Node.js local server is publicly-accessible at ${url}/`); console.log(`:: INFO :: Listening at http://localhost:` + PORT); console.log(`:: INFO :: CustomCallout initiated with outgoing IVR`); calloutRunMenu(url); }); ## Fill in your parameters Assign your values to the following parameters: | Parameter | Your value | | --- | --- | | `APPLICATION_KEY` | The key found on your Sinch [dashboard](https://dashboard.sinch.com/voice/apps). | | `APPLICATION_SECRET` | The secret found on your Sinch [dashboard](https://dashboard.sinch.com/voice/apps). | | `CLI` | Any purchased number you have with us on your account. Find the number on your Sinch [dashboard](https://dashboard.sinch.com/voice/apps) by clicking on your app, navigating to the Voice and Video tab, and looking in the Inbound Numbers section. | | `TO_NUMBER` | The phone number that you want to call. | Save the file. ## CustomCallout RunMenu and parsing the choice made Now you can execute the code and make your text-to-speech call. Run the following command: ```shell node index.js ``` The node listener will start, you will see your custom data that is sent. ```logs INFO :: Node.js local server is publicly-accessible at https://ffff-ff-fff-fff-ff.ngrok.io INFO :: Listening at http://localhost:8081 INFO :: CustomCallout initiated with outgoing IVR INFO :: Custom Callout Data: { "Method":"CustomCallout","customCallout":{"ice":"{\"action\": {\"destination\": {\"type\": \"number\",\"endpoint\": \"+00000000000\" },\"cli\": \"+00000000000\",\"name\": \"ConnectPstn\"}}","ace":"{\"action\": {\"name\": \"RunMenu\",\"locale\": \"en-US\",\"menus\": [{\"id\": \"main\",\"mainPrompt\": \"#tts[ Welcome to the main menu. Press 1 to confirm order or 2 to cancel]\",\"timeoutMills\": 5000,\"options\": [ {\"dtmf\": \"1\",\"action\": \"return(confirm)\"}, {\"dtmf\": \"2\",\"action\": \"return(cancel)\"}]}]}},"pie":"https://ffff-ff-fff-fff-ff.ngrok.io","dice":"https://ffff-ff-fff-fff-ff.ngrok.io"}} ``` You will recieve a callout to your selected number. Once a choice is made the PIE event will be returned to the callback server stated in the `pie` section of the customCallout. There are two possible choices as per the configured RunMenu (IVR) which are `confirm` or `cancel`. You will see in this message what choice was made, the `Destination` will show the `TO_NUMBER` you dialed. ```logs INCOMING EVENT :: pie IVR MENU CHOICE :: Destination: "+00000000000" selected value: confirm" ``` ## Bonus: Inspect the incoming HTTP Call Event bodies If you uncomment the `//console.log(`:: INCOMING HTTP BODY :: ", req.body)` lines to see the incoming call requests (example `pie` event below) This will give you a better visibility whilst developing and debugging your incoming call events. ```logs :: INCOMING HTTP BODY :: { event: 'pie', callid: '00000000-dddd-2222-eeee-444444444444', timestamp: '2022-02-14T10:53:16Z', menuResult: { addToContext: [], type: 'return', value: 'confirm', menuId: 'main', inputMethod: 'dtmf' }, version: 1, applicationKey: '11111111-aaaa-2222-bbbb-333333333333' } ``` ## Next steps The code you used in the **index.js** file sends a POST request to the Sinch API **/callouts** endpoint to make the call. Click [here](/docs/voice/api-reference/voice/callouts) to read more about the /callouts endpoint. - [API specification](/docs/voice/api-reference/voice)