How to Send Voice Notifications

A phone call is a high-priority method for delivering critical alerts. In this guide, you will learn how to automate voice notifications to a list of recipients, play a custom message, and capture user confirmation via keypad (DTMF) input.

Prerequisites

Initialize your Project Folder

  1. Create the environment where your code and security keys will live.
  2. Open your terminal and create a new directory:
mkdir voice-notifications && cd voice-notifications
  1. Initialize the project and install the Vonage SDK and Express:
npm init -y npm install @vonage/server-sdk express

Expose Your Local Server

Vonage needs to send webhooks to your local machine. Use ngrok to expose your server:

ngrok http 3000

ngrok will forward your local port 3000 to a public URL like https://{random-id}.ngrok.app.

Important: Keep this terminal window open while developing and testing. If you close ngrok, you’ll need to update your webhook URLs with the new address.

Copy this URL. You’ll need it when configuring your Vonage application in the next step.

Note: The free version of ngrok generates a new random URL each time you restart it. For a consistent URL during development, consider using ngrok reserved domains or upgrading to a paid plan.

Create a Vonage Application

Generate your credentials via the Dashboard and save them to the folder you just created.

  1. Log in to the Vonage Dashboard.

  2. Go to Applications > Create a new application.

  3. Authentication: Click Generate public and private keys.

    • A file named private.key will download.
    • Move this private.key file from your Downloads folder into your voice-notifications folder.
  4. Capabilities: Enable Voice.

  5. In the Voice settings, set the following webhooks:

    • Answer URL: https://{random-id}.ngrok.app/answer (Method:
      GET
      )
    • Event URL: https://{random-id}.ngrok.app/event (Method:
      POST
      )
  6. Click Save Changes at the bottom.

Create the Webhook Server (server.js)

When Vonage answers a call, it fetches a Call Control Object (NCCO) from your answer_url. This JSON array defines the "script" the call follows. Create a file named server.js and set up the webhook to provide the NCCO:


const express = require('express');
const app = express();
app.use(express.json());

app.get('/answer', (req, res) => {
  // NCCO defines what the recipient hears
  res.json([
    {
      action: 'talk',
      text: 'This is a priority notification. Please press 1 to confirm receipt.'
    },
    {
      action: 'input',
      type: [ 'dtmf' ],
      dtmf: { maxDigits: 1 }
    }
  ]);
});

app.post('/event', (req, res) => {
  // Capture the button press
  if (req.body.dtmf && req.body.dtmf.digits === '1') {
    console.log(`✅ Confirmation received from UUID: ${req.body.uuid}`);
  }
 if (status) {
    console.log(`Call Status Update: ${status} (UUID: ${req.body.uuid})`);
  }
  res.status(204).send();
});

app.listen(3000, () => console.log('🚀 Webhook server listening on port 3000'));

Create the Broadcast Script (broadcast.js)

Create a file named broadcast.js. This script triggers the outbound calls.


const { Vonage } = require('@vonage/server-sdk');

// --- 1. CONFIGURATION ---
const API_KEY = "YOUR_API_KEY";
const API_SECRET = "YOUR_API_SECRET";
const APP_ID = "YOUR_APP_ID";
const VONAGE_NUMBER = "YOUR_VONAGE_NUMBER";
const TUNNEL_URL = "https://{random-id}.ngrok.app" // From the ngrok step above

// --- 2. PLACEHOLDER PROTECTION ---
const config = { API_KEY, API_SECRET, APP_ID, VONAGE_NUMBER, TUNNEL_URL };
Object.keys(config).forEach(key => {
    if (config[key].includes("YOUR")) {
        console.error(`❌ ERROR: The ${key} placeholder has not been updated!`);
        process.exit(1);
    }
});

const vonage = new Vonage({
  apiKey: API_KEY,
  apiSecret: API_SECRET,
  applicationId: APP_ID,
  privateKey: './private.key'
});

const recipients = [
  { name: 'Alice', number: '15551234567' }
];

async function broadcast() {
  for (const person of recipients) {
    try {
      const result = await vonage.voice.createOutboundCall({
        to: [{ type: 'phone', number: person.number }],
        from: { type: 'phone', number: VONAGE_NUMBER },
        answer_url: [`${TUNNEL_URL}/answer`],
        event_url: [`${TUNNEL_URL}/event`]
      });
      console.log(`☎️  Calling ${person.name}... (UUID: ${result.uuid})`);
    } catch (err) {
      console.error(`❌ Failed to call ${person.name}:`, err.message);
    }
  }
}

broadcast();

Replace YOUR_VONAGE_NUMBER with any of your Vonage numbers. If you have a new Vonage account with no numbers yet, you can use the test number 123456789 as the caller ID, and call the number you originally provided during sign-up. Please note that this feature is only available for demo or trial accounts until you add credit to your account.

Test your Notification

  1. Start your server: Run node server.js in your project folder.
  2. Start the broadcast: In a separate terminal, run node broadcast.js. Your phone will ring, play the message, and log your confirmation to the console when you press "1".

Next Steps

Customization: Change text-to-speech voice or use the stream action in your NCCO to play pre-recorded MP3 files instead of text-to-speech.

Voice AI: Listen to the recipient answer with speech-to-text or connect a voice bot with WebSocket.

Answering Machines: Use answering machine detection to leave a voicemail message.

Scalability: For large lists, implement a queue system to respect Vonage Rate Limits.