code examples

Sent logo
Sent TeamMay 3, 2025 / code examples / Article

How to Send SMS with Vonage API in Node.js: Complete Express Tutorial

Learn how to send SMS with Vonage API using Node.js and Express. Step-by-step tutorial with @vonage/server-sdk 3.24.1, delivery receipts, error handling, and production deployment guide.

How to Send SMS Messages with Vonage API in Node.js Express

Learn how to send SMS messages with Vonage SMS API using Node.js and Express. This complete guide walks you through building a production-ready SMS application with @vonage/server-sdk 3.24.1, covering secure API credential management, error handling, delivery receipt tracking, and testing best practices.

You'll create a functional Express SMS server with a REST API endpoint that accepts a recipient phone number and message text, then delivers SMS messages reliably using the Vonage API. This Node.js SMS integration works for notifications, alerts, appointment reminders, or two-factor authentication (though Vonage's Verify API is purpose-built for 2FA workflows).

This tutorial uses Vonage's official Node.js SDK (@vonage/server-sdk) with comprehensive error handling for delivery receipts (DLRs) and message status tracking.

Current Versions (as of 2024–2025):

  • Node.js: v22 LTS (Active LTS until October 2025)
  • Express.js: 5.1.0 (requires Node.js 18 or higher)
  • @vonage/server-sdk: 3.24.1

Project Overview: Building a Vonage SMS API Integration

What You'll Build:

A Node.js Express server with a single API endpoint (POST /send-sms). This endpoint receives a destination phone number and text message body, then uses the Vonage Node.js SDK to send SMS messages programmatically.

Problem Solved:

Integrate SMS sending capabilities into Node.js applications quickly and reliably using Vonage's enterprise-grade communication platform.

Technologies Used:

TechnologyPurposeVersion
Node.jsJavaScript runtime for server-side applicationsv22 LTS
Express.jsMinimal web framework for creating the API endpoint5.1.0
Vonage SMS APICommunication Platform as a Service (CPaaS) for sending SMSLatest
@vonage/server-sdkOfficial Vonage Node.js SDK3.24.1
dotenvLoads environment variables from .env into process.env, keeping credentials secureLatest

System Architecture:

  1. A client (e.g., Postman, curl, another application) sends a POST request to the /send-sms endpoint.
  2. Express parses the request body to extract the recipient number and message text.
  3. The server uses the Vonage Node.js SDK (configured with your API credentials) to send a request to the Vonage SMS API.
  4. Vonage processes the request and sends the SMS message to the recipient's phone number.
  5. Vonage returns a response to your server, which sends a response back to the client.
mermaid
sequenceDiagram
    participant Client
    participant Express
    participant Vonage API
    participant Recipient

    Client->>Express: POST /send-sms
    Express->>Vonage API: vonage.sms.send()
    Vonage API->>Recipient: SMS delivery
    Vonage API-->>Express: Response (status, message-id)
    Express-->>Client: JSON response

Prerequisites: What You Need to Send SMS with Vonage

Prerequisites:

  • Node.js and npm: Install from nodejs.org
  • Vonage API Account: Sign up at Vonage API Dashboard – new accounts receive free testing credit
  • Vonage API Key and Secret: Find these on your Vonage API Dashboard main page
  • Vonage Phone Number: Rent a virtual number from Vonage. Go to Numbers > Buy numbers in the Vonage Dashboard. Ensure the number supports SMS in your target region
  • Verified Test Phone Number (for trial accounts): Trial accounts can only send SMS to verified numbers. Add and verify numbers in the Sandbox / Test Numbers page
  • Text Editor or IDE: VS Code, Sublime Text, or WebStorm
  • Basic terminal/command line knowledge

Step 1: Set Up Your Vonage Node.js SMS Project

Initialize your Node.js project and install the necessary dependencies.

  1. Create a Project Directory:

    bash
    mkdir vonage-sms-guide
    cd vonage-sms-guide
  2. Initialize the Node.js Project: Create a package.json file. The -y flag accepts default settings.

    bash
    npm init -y
  3. Install Dependencies: Install express, @vonage/server-sdk, and dotenv.

    bash
    npm install express @vonage/server-sdk dotenv
  4. Create Core Files:

    bash
    # On macOS/Linux
    touch index.js .env .gitignore
    
    # On Windows (Command Prompt)
    type nul > index.js
    type nul > .env
    type nul > .gitignore
    
    # On Windows (PowerShell)
    New-Item index.js -ItemType File
    New-Item .env -ItemType File
    New-Item .gitignore -ItemType File
  5. Configure Environment Variables (.env): Open .env and add your Vonage API credentials and rented number.

    • VONAGE_API_KEY: Your API key from the Vonage Dashboard
    • VONAGE_API_SECRET: Your API secret from the Vonage Dashboard
    • VONAGE_FROM_NUMBER: Your virtual phone number in E.164 format without spaces (e.g., 14155550100)
    • PORT: The port your Express server listens on (e.g., 3000)
    plaintext
    # .env
    VONAGE_API_KEY=YOUR_VONAGE_API_KEY
    VONAGE_API_SECRET=YOUR_VONAGE_API_SECRET
    VONAGE_FROM_NUMBER=YOUR_VONAGE_VIRTUAL_NUMBER
    PORT=3000

    Important: Replace placeholder values with your actual credentials.

  6. Configure Git Ignore (.gitignore): Prevent committing sensitive environment variables and node_modules.

    plaintext
    # .gitignore
    node_modules
    .env

Your project structure:

vonage-sms-guide/ ├── index.js ├── package.json ├── .env └── .gitignore

Step 2: Implement Vonage SMS API with Node.js and Express

Write the code for your Express server in index.js.

  1. Require Dependencies and Load Environment Variables:

    javascript
    // index.js
    const express = require('express');
    const { Vonage } = require('@vonage/server-sdk');
    require('dotenv').config();
    
    // Check if essential environment variables are set
    if (!process.env.VONAGE_API_KEY || !process.env.VONAGE_API_SECRET || !process.env.VONAGE_FROM_NUMBER) {
      console.error('Error: Missing Vonage API credentials or FROM number in .env file.');
      process.exit(1);
    }

    Why dotenv.config() first? It must run before accessing process.env variables from .env. The code checks that critical variables load successfully.

  2. Initialize Express App and Vonage Client: Create Express and Vonage SDK instances using environment variables.

    javascript
    // index.js (continued)
    const app = express();
    const port = process.env.PORT || 3000;
    
    const vonage = new Vonage({
      apiKey: process.env.VONAGE_API_KEY,
      apiSecret: process.env.VONAGE_API_SECRET
    });
  3. Add Middleware: Configure Express to parse JSON request bodies.

    javascript
    // index.js (continued)
    app.use(express.json());
    app.use(express.urlencoded({ extended: true }));
  4. Create the SMS Sending Endpoint (/send-sms): Define a POST route to handle SMS sending requests.

    javascript
    // index.js (continued)
    app.post('/send-sms', async (req, res) => {
      // Basic input validation
      const { to, text } = req.body;
      if (!to || !text) {
        return res.status(400).json({
          success: false,
          message: 'Missing `to` or `text` parameter in request body.'
        });
      }
    
      const from = process.env.VONAGE_FROM_NUMBER;
    
      try {
        const resp = await vonage.sms.send({ to, from, text });
    
        console.log('Message sent successfully:', resp);
    
        // Status '0' indicates successful submission to the Vonage network, not delivery to the handset.
        // DLR statuses include: DELIVRD (delivered), UNDELIV (undelivered), EXPIRED, FAILED, REJECTD, DELETED, UNKNOWN.
        if (resp.messages && resp.messages.length > 0 && resp.messages[0].status === '0') {
           res.status(200).json({
             success: true,
             message: 'SMS submitted successfully.',
             messageId: resp.messages[0]['message-id']
           });
        } else {
          console.error('Vonage API reported an issue:', resp);
          const errorText = (resp.messages && resp.messages.length > 0) ?
            resp.messages[0]['error-text'] : 'Unknown Vonage API error';
           res.status(500).json({
             success: false,
             message: `Failed to send SMS. Vonage error: ${errorText}`,
             details: resp
           });
        }
    
      } catch (error) {
        console.error('Error sending SMS:', error);
        res.status(500).json({
          success: false,
          message: 'Internal server error while sending SMS.',
          error: error.message
        });
      }
    });

    Key Points:

    • Define an async function to use await for the asynchronous vonage.sms.send call.
    • Basic validation checks if to and text are present in the request body.
    • Retrieve the from number from environment variables.
    • vonage.sms.send({ to, from, text }) makes the API call.
    • A try...catch block handles potential network errors or issues within the SDK call.
    • Inspect the resp object from Vonage. A status of '0' indicates successful submission to the network. Non-zero statuses indicate errors (e.g., invalid number, insufficient funds). Return the Vonage message-id on success.
    • Send appropriate JSON responses (success or error) back to the client with relevant status codes (200, 400, 500).
  5. Start the Server: Make the Express application listen for incoming requests on the configured port.

    javascript
    // index.js (continued)
    app.listen(port, () => {
      console.log(`Server listening at http://localhost:${port}`);
      console.log(`SMS sending endpoint available at POST http://localhost:${port}/send-sms`);
    });

Your index.js file is now complete.

Step 3: Test Your Vonage SMS Integration

Run the server and test the SMS sending functionality.

  1. Run the Server: Open your terminal in the project directory and run:

    bash
    node index.js

    You should see output indicating the server is running:

    Server listening at http://localhost:3000 SMS sending endpoint available at POST http://localhost:3000/send-sms
  2. Test with curl or Postman: Use curl (command-line) or Postman (GUI) to send a POST request to your endpoint.

    Using curl: Replace YOUR_RECIPIENT_NUMBER with the phone number you want to send the SMS to (use a verified number for trial accounts). Format the number including the country code (e.g., 14155550123).

    bash
    curl -X POST http://localhost:3000/send-sms \
         -H 'Content-Type: application/json' \
         -d '{
               "to": "YOUR_RECIPIENT_NUMBER",
               "text": "Hello from your Vonage Node.js App!"
             }'

    Using Postman:

    • Create a new request.

    • Set the method to POST.

    • Enter the URL: http://localhost:3000/send-sms.

    • Go to the Body tab, select raw, and choose JSON from the dropdown.

    • Enter the JSON payload:

      json
      {
        "to": "YOUR_RECIPIENT_NUMBER",
        "text": "Hello from your Vonage Node.js App!"
      }
    • Click Send.

  3. Check the Response:

    • Successful Submission: You should receive a JSON response with a 200 OK status:

      json
      {
        "success": true,
        "message": "SMS submitted successfully.",
        "messageId": "some-message-id-from-vonage"
      }

      Check the recipient phone – the SMS should arrive shortly. You should also see confirmation logs in the terminal where node index.js is running.

    • Error Response: If something goes wrong (e.g., invalid credentials, incorrect 'to' number format, trial account restrictions), you'll get an error response with a non-200 status code:

      json
      // Example: Missing parameter
      {
        "success": false,
        "message": "Missing `to` or `text` parameter in request body."
      }
      json
      // Example: Vonage API error (e.g., non-whitelisted number)
      {
          "success": false,
          "message": "Failed to send SMS. Vonage error: Non White-listed Destination - rejected",
          "details": { /* ... full Vonage response ... */ }
      }
      json
      // Example: Internal server error
      {
          "success": false,
          "message": "Internal server error while sending SMS.",
          "error": "Some specific error message"
      }

      Check the terminal logs for more detailed error information.

Step 4: Handle Vonage SMS API Errors and Delivery Receipts

Your current implementation includes basic try...catch blocks and logs errors to the console. For production systems, implement:

  • Structured Logging: Use libraries like Winston or Pino for structured logging (e.g., JSON format), which makes logs easier to parse and analyze, especially when sending them to log aggregation services (like Datadog, Splunk, ELK stack).
  • Centralized Logging: Configure your logger to send logs to a centralized platform instead of just console.log.
  • More Granular Error Handling: Check specific Vonage error codes (returned in the error-text or status fields) to provide more informative feedback or trigger specific actions (e.g., retry logic for temporary network issues, alerts for authentication failures). Common error codes include:
    • Error Code 15 (Rejection Code 10 for SMPP): "Illegal Sender" – occurs when sending SMS to the US or Canada without a US pre-approved long number, toll-free, 10DLC, or short code associated with your Vonage account.
    • Error Code 99: "General Error" – indicates a request was processed but failed due to various factors; check DLR details for specifics.
    • Non-zero status codes: Any status code other than '0' in the initial response indicates submission failure.
  • Delivery Receipts (DLRs): Sending the message successfully (status '0') only means Vonage accepted it for submission. To confirm delivery to the handset, set up a webhook endpoint to receive DLRs from Vonage. DLRs provide statuses like DELIVRD (delivered), UNDELIV (undelivered), EXPIRED, FAILED, REJECTD, DELETED, or UNKNOWN. Refer to the Vonage SMS API documentation and DLR Status documentation for complete error code listings.

Step 5: Secure Your Vonage API Credentials

  • API Key Security: Never commit your .env file or hardcode API keys/secrets directly in your source code. Use environment variables and ensure .env is in your .gitignore. In production environments, use your hosting provider's mechanism for managing secrets (e.g., AWS Secrets Manager, Heroku Config Vars, Kubernetes Secrets).
  • Input Validation: Your current validation is minimal. In a real application, perform more robust validation on the to phone number (e.g., check format using a library like libphonenumber-js version 1.11+ with metadata synced to September 2025, ~145 KB max metadata) and sanitize the text input to prevent potential injection attacks if the text is ever displayed elsewhere.
  • Rate Limiting: Protect your endpoint from abuse by implementing rate limiting (e.g., using express-rate-limit). This prevents users from sending excessive numbers of messages rapidly.
  • Authentication/Authorization: The current endpoint is open. In a real application, protect this endpoint, ensuring only authorized users or services can trigger SMS sending. This might involve API keys, JWT tokens, or session-based authentication added as middleware to the Express route.

Step 6: Troubleshoot Common Vonage SMS API Issues

IssueSolution
Non-Whitelisted Destination ErrorAdd and verify recipient numbers in your Vonage Sandbox / Test Numbers page. Upgrade your account (add payment details) to send to any number.
Invalid CredentialsDouble-check that VONAGE_API_KEY and VONAGE_API_SECRET in your .env file are correct and have no extra spaces.
Incorrect FROM NumberEnsure VONAGE_FROM_NUMBER is a valid number you rented from Vonage in the correct format (e.g., 14155550100).
Insufficient FundsCheck your balance in the dashboard. If your Vonage account runs out of credit, sending will fail.
Carrier FilteringMobile carriers might filter messages, especially if they appear spammy. Ensure your content is appropriate and consider using Alphanumeric Sender IDs (where supported) or Short Codes for higher volume/better deliverability.
SDK/API ChangesWhile @vonage/server-sdk is stable, always refer to the official Vonage documentation for the latest methods and response structures.
SMS API vs. Messages APIThis guide uses the simpler Vonage SMS API flow via vonage.sms.send(). For multi-channel messaging (WhatsApp, Facebook Messenger, MMS) or advanced features, explore the Vonage Messages API with vonage.messages.send().

Step 7: Deploy Your Vonage Node.js SMS Application

Deploy this application on a server or platform (like Heroku, Render, AWS EC2, Google Cloud Run, etc.). Key steps include:

  1. Environment Variables: Set VONAGE_API_KEY, VONAGE_API_SECRET, and VONAGE_FROM_NUMBER as environment variables on your chosen hosting platform. Do not upload the .env file.
  2. Dependencies: Ensure npm install runs in the deployment environment to install dependencies.
  3. Starting the App: Configure the platform to run your application using node index.js.
  4. Port: Ensure your application listens on the port assigned by the hosting environment (often provided via a PORT environment variable, which your code already handles).

A Procfile for platforms like Heroku:

plaintext
web: node index.js

Complete Vonage SMS Code Example

The complete code for this guide includes index.js, package.json, .gitignore, and a .env.example file.


Frequently Asked Questions About Vonage SMS with Node.js

How do I send SMS with Vonage in Node.js?

Install @vonage/server-sdk (version 3.24.1 for 2025) and create a Vonage client with your API key and secret. Use vonage.sms.send({ to, from, text }) to send messages. You need a Vonage account, API credentials, and a rented virtual number. The complete setup requires Express for the REST endpoint, dotenv for credential management, and proper error handling for production use.

What does Vonage status code 0 mean?

Status code '0' indicates successful submission to the Vonage network, not delivery to the recipient's handset. To confirm actual delivery, implement webhook endpoints to receive Delivery Receipts (DLRs) from Vonage. DLR statuses include: DELIVRD (delivered), UNDELIV (undelivered), EXPIRED, FAILED, REJECTD, DELETED, and UNKNOWN.

What is Vonage Error Code 15?

Error Code 15 (Rejection Code 10 for SMPP) means "Illegal Sender" – this occurs when sending SMS to the US or Canada without a US pre-approved long number, toll-free, 10DLC, or short code associated with your Vonage account. To resolve this, obtain the appropriate number type for US/Canada SMS delivery through your Vonage Dashboard.

What is Vonage Error Code 99?

Error Code 99 indicates a "General Error" – meaning the request was processed but failed due to various factors. Check the Delivery Receipt (DLR) details for specifics about why the message failed. This error requires examining the error-text field in the response and consulting the Vonage SMS API error documentation for detailed troubleshooting.

What version of @vonage/server-sdk should I use in 2025?

Use @vonage/server-sdk version 3.24.1 (latest as of early 2025) with Node.js v22 LTS and Express 5.1.0. Install with npm install @vonage/server-sdk@3.24.1. This version provides stable SMS API functionality with improved error handling. Always check npm for the latest version.

How do I handle the "Non-Whitelisted Destination" error?

This is the most common error for Vonage trial accounts. Trial accounts can only send SMS to verified numbers. Add and verify recipient numbers in your Vonage Sandbox / Test Numbers page. To send to any number, upgrade your account by adding payment details in the Vonage Dashboard.

What are Delivery Receipts (DLRs) in Vonage SMS?

Delivery Receipts (DLRs) are webhook notifications from Vonage confirming whether your SMS was delivered to the recipient's handset. DLRs provide statuses like DELIVRD (delivered), UNDELIV (undelivered), EXPIRED, FAILED, REJECTD, DELETED, or UNKNOWN. Implement a webhook endpoint to receive DLRs for reliable message tracking. See the DLR Status documentation.

Should I use Vonage SMS API or Messages API?

For simple SMS sending with Node.js Express, use the SMS API via vonage.sms.send() with API Key/Secret authentication (covered in this guide). For multi-channel messaging (WhatsApp, Facebook Messenger, MMS) or advanced features, use the Vonage Messages API with vonage.messages.send(), which requires Application ID and Private Key authentication.

How do I validate phone numbers before sending SMS with Vonage?

Use libphonenumber-js version 1.11+ (with metadata synced to September 2025, ~145 KB max metadata) to validate phone number format before calling the Vonage API. Install with npm install libphonenumber-js and parse numbers to E.164 format. This prevents API errors from invalid phone numbers and improves delivery rates.

Can I send SMS from a Vonage trial account?

Yes, but with restrictions. Trial accounts receive free testing credit but can only send SMS to verified numbers added in the Sandbox / Test Numbers page. Upgrade your account (add payment details) to send SMS to any number. Trial accounts are perfect for development and testing before production deployment.


Next Steps: Enhancing Your Vonage SMS Integration

You've successfully built a Node.js application capable of sending SMS messages using Express and the Vonage API.

From here, you could:

  • Implement webhook endpoints to receive incoming SMS messages or delivery receipts.
  • Integrate this functionality into a larger application.
  • Add more robust error handling, logging, and monitoring.
  • Build a frontend interface to interact with the API.
  • Explore the Vonage Messages API for multi-channel communication.

Frequently Asked Questions

How to send SMS with Node.js and Express?

Use the Vonage API and Express.js framework within your Node.js application. This involves setting up a POST route in Express to handle requests, and then utilizing the Vonage Node.js SDK to send messages via their SMS API. The server receives the recipient's number and message text, then uses Vonage to deliver the SMS.

What is the Vonage API used for in Node.js?

The Vonage API, a Communication Platform as a Service (CPaaS), enables sending SMS messages programmatically. In Node.js, you interact with it using the Vonage Node.js Server SDK, which simplifies sending SMS messages, managing two-factor authentication, and other communication tasks. The article provides a tutorial on its usage for sending SMS.

Why use dotenv in a Node.js SMS project?

Dotenv is a crucial module for storing sensitive information such as API keys and secrets as environment variables within a `.env` file. It's instrumental in keeping these credentials secure and outside your main codebase, protecting them from accidental exposure through version control systems like Git.

When should I use Vonage Verify API instead of SMS?

While you can use the Vonage SMS API for two-factor authentication (2FA), Vonage's Verify API is often better suited for this specific purpose. It provides more advanced 2FA features and simplifies the process, streamlining security implementations.

How to set up Vonage API credentials in Node.js?

Store your Vonage `API_KEY`, `API_SECRET`, virtual `FROM_NUMBER`, and `PORT` within a `.env` file. Then, use `dotenv.config()` in your `index.js` file to load these variables into your Node.js environment so your application can use them to authenticate with Vonage and send messages.

What Node.js packages are required for sending SMS with Vonage?

You'll need `express` for creating the API endpoint, `@vonage/server-sdk` to interact with the Vonage APIs, and `dotenv` to manage your Vonage API credentials securely as environment variables.

How to create an SMS API endpoint with Express?

Define a `POST` route handler in your Express app, typically at `/send-sms`. This endpoint receives the recipient's number (`to`) and the message body (`text`) as parameters in the request. Inside the handler, use the Vonage SDK to send the message using the provided parameters.

Why does Vonage SMS API sometimes return status 0 even if delivery fails?

A '0' status from the Vonage SMS API usually indicates successful message *submission* to the network, not final delivery to the recipient. To get confirmed delivery status, you need to implement delivery receipts (DLRs) using webhooks. These provide real-time updates on the message status as it progresses.

Can I send SMS to any number with a Vonage trial account?

No, trial accounts have restrictions. You can only send SMS to numbers you've specifically verified in the Vonage dashboard's Sandbox / Test Numbers page. To lift this restriction, you must upgrade to a paid Vonage account.

What is the purpose of the Vonage FROM_NUMBER?

The `VONAGE_FROM_NUMBER` is your designated Vonage Virtual Number, which acts as the sender ID for your outgoing SMS messages. This number is what recipients will see as the source of the SMS.

How to handle errors when sending SMS messages with Vonage API?

The example code uses basic `try...catch` blocks. For production, use libraries like Winston or Pino for structured logs and send them to centralized logging services. Implement more detailed error handling by checking Vonage error codes (like 'Non White-listed Destination') returned in the API response and take appropriate actions (e.g., retries or alerts).

How to test my Vonage SMS integration locally?

Once your Express server is running, use tools like `curl` or Postman to send `POST` requests to the `/send-sms` endpoint. The request body should be JSON formatted with the recipient's number (`to`) and message (`text`). Ensure your trial account numbers are whitelisted in the Vonage dashboard.

What are important security considerations when using the Vonage SMS API?

Never expose your API keys directly in your code. Always use environment variables (`.env` file) and make sure this file is included in your `.gitignore`. In production, manage secrets securely using your platform's specific mechanisms. Also implement input validation to prevent potential injection vulnerabilities and use rate limiting to protect against abuse.