code examples

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

Send SMS with Node.js and Vonage API: Complete Express Integration Guide 2025

Learn how to send SMS messages using Node.js, Express, and the Vonage SMS API. Step-by-step tutorial with code examples, error handling, authentication, and production deployment best practices.

Send SMS with Node.js and Vonage: A Developer Guide

Learn how to send SMS with Node.js using the Vonage SMS API and Express framework. This comprehensive tutorial walks you through building a production-ready REST API endpoint for programmatic text messaging, from initial setup to deployment, with complete code examples and best practices for authentication, error handling, and rate limiting.

By the end of this guide, you will have a functional Express API endpoint that accepts a recipient phone number and message content, then uses the Vonage Node SDK to send SMS messages globally.

If you're comparing SMS providers for your Node.js application, you may also want to explore sending SMS with Twilio and Node.js, Infobip SMS integration for Node.js, or Plivo Node.js SMS implementation to understand feature differences and pricing.

Key Technologies:

  • Node.js: A JavaScript runtime environment for building server-side applications.
  • Express.js: A minimal and flexible Node.js web application framework used to create our API endpoint.
  • Vonage Node Server SDK (@vonage/server-sdk): The official library for interacting with Vonage APIs from Node.js.
  • Vonage SMS API: The Vonage service used for sending and receiving SMS messages globally.
  • dotenv: A module to load environment variables from a .env file into process.env.

Prerequisites:

  • Node.js and npm: Ensure Node.js (which includes npm) is installed on your system. You can download it from nodejs.org. Verify installation by running node -v and npm -v in your terminal. Note: The Vonage Node Server SDK requires Node.js v18 or higher for optimal compatibility with modern features like async/await and ES modules.
  • Vonage API Account: Sign up for a free Vonage API account at developer.vonage.com. New accounts receive free credit for testing.
  • Vonage API Key and Secret: Find these on your Vonage API Dashboard after signing up.
  • Vonage Phone Number or Alphanumeric Sender ID: You need a Vonage virtual number or have set up an Alphanumeric Sender ID to send messages from. You can purchase numbers in the dashboard under ""Numbers"" > ""Buy numbers"". Note: For trial accounts, you might be restricted to sending messages to verified numbers only initially.
  • Text Editor/IDE: Such as VS Code, Sublime Text, or WebStorm.
  • (Optional) Postman or curl: For testing the API endpoint we create.

System Architecture:

The system is straightforward:

  1. A client (e.g., Postman, curl, a frontend application) sends a POST request to our Node.js/Express API endpoint (/send-sms).
  2. The Express server receives the request, extracts the recipient number and message content.
  3. The server uses the Vonage Node SDK, configured with your API credentials, to call the Vonage SMS API.
  4. Vonage processes the request and delivers the SMS message to the recipient's phone via the carrier network.
  5. Vonage returns a response to our server, which then relays a success or error message back to the client.
[Client] ---- HTTP POST ----> [Node.js/Express API] ---- Vonage API Call ----> [Vonage Platform] ---- SMS ----> [Recipient Phone] <---- HTTP Response --- <---- API Response ----

1. Setting up the Project

Let's initialize our Node.js project and install the necessary dependencies.

  1. Create Project Directory: Open your terminal and create a new directory for your project, then navigate into it:

    bash
    mkdir vonage-sms-sender
    cd vonage-sms-sender
  2. Initialize Node.js Project: Run npm init to create a package.json file. You can accept the defaults by adding the -y flag:

    bash
    npm init -y

    This file tracks your project's metadata and dependencies.

  3. Install Dependencies: We need Express for the web server, the Vonage SDK to interact with the API, and dotenv to manage environment variables securely. Running npm install will add these packages to your node_modules folder and record the specific versions in your package.json.

    bash
    npm install express @vonage/server-sdk dotenv
  4. Create Project Files: Create the main files for our application:

    bash
    touch server.js vonageService.js .env .gitignore
    • server.js: This will contain our Express application setup and API endpoint.
    • vonageService.js: This module will encapsulate the logic for interacting with the Vonage SDK.
    • .env: This file will store our sensitive API credentials (API Key, API Secret, Vonage Number/Sender ID). Never commit this file to version control.
    • .gitignore: Specifies intentionally untracked files that Git should ignore.
  5. Configure .gitignore: Add node_modules and .env to your .gitignore file to prevent committing dependencies and secrets:

    text
    # .gitignore
    
    node_modules/
    .env
    *.log
  6. Set up package.json Start Script: Open package.json and add a start script under scripts to easily run your server. Your package.json will look similar to this after running npm install and adding the start script (specific versions will vary):

    json
    {
      ""name"": ""vonage-sms-sender"",
      ""version"": ""1.0.0"",
      ""description"": ""Node.js app to send SMS via Vonage"",
      ""main"": ""server.js"",
      ""scripts"": {
        ""start"": ""node server.js"",
        ""test"": ""echo \""Error: no test specified\"" && exit 1""
      },
      ""keywords"": [
        ""vonage"",
        ""sms"",
        ""node"",
        ""express""
      ],
      ""license"": ""ISC"",
      ""dependencies"": {
        ""@vonage/server-sdk"": ""^x.y.z"",
        ""dotenv"": ""^x.y.z"",
        ""express"": ""^x.y.z""
      }
    }

2. Integrating with Vonage (Configuration)

Now, let's configure the application to use your Vonage account credentials securely.

  1. Obtain Vonage Credentials:

    • Navigate to your Vonage API Dashboard.
    • Find your API key and API secret displayed prominently.
    • Go to ""Numbers"" > ""Your numbers"" to find your Vonage virtual phone number, or ensure you have an Alphanumeric Sender ID configured if applicable (check regional restrictions).
  2. Configure .env File: Open the .env file and add your credentials. Replace the placeholder values with your actual Vonage details.

    dotenv
    # .env
    
    # Vonage API Credentials
    VONAGE_API_KEY=YOUR_API_KEY
    VONAGE_API_SECRET=YOUR_API_SECRET
    
    # Vonage Sender ID (Use your Vonage number or Alphanumeric Sender ID)
    # Ensure the number is in E.164 format if using a number (e.g., 14155552671)
    VONAGE_SENDER_ID=YOUR_VONAGE_NUMBER_OR_SENDER_ID
    
    # Server Port
    PORT=3000
    • VONAGE_API_KEY: Your Vonage API Key.
    • VONAGE_API_SECRET: Your Vonage API Secret.
    • VONAGE_SENDER_ID: The 'from' number or ID for the SMS. This must be a valid Vonage number associated with your account or an approved Alphanumeric Sender ID. Use E.164 format (e.g., 14155552671) for phone numbers.
    • PORT: The port number your Express server will listen on.

    Security: The .env file keeps your secrets out of your codebase. Ensure it's listed in .gitignore.

  3. Whitelisting (Trial Accounts): If you are using a trial Vonage account, you might need to whitelist the phone numbers you intend to send SMS messages to.

    • In the Vonage Dashboard, navigate to ""Sandbox & Tools"" > ""Test Numbers"".
    • Add the recipient phone numbers you will use for testing and verify them following the instructions (usually via an SMS or voice call code).
    • Failure to do this on a trial account will likely result in a ""Non-Whitelisted Destination"" error when sending.

3. Implementing Core Functionality (SMS Service)

Let's create the service logic to handle sending the SMS via the Vonage SDK.

  1. Create vonageService.js: Open vonageService.js and add the following code:

    javascript
    // vonageService.js
    const { Vonage } = require('@vonage/server-sdk');
    
    // Initialize Vonage client from environment variables
    const vonage = new Vonage({
      apiKey: process.env.VONAGE_API_KEY,
      apiSecret: process.env.VONAGE_API_SECRET
    });
    
    /**
     * Sends an SMS message using the Vonage API.
     * @param {string} recipient - The recipient phone number in E.164 format (e.g., '14155552671').
     * @param {string} messageText - The text content of the SMS message.
     * @returns {Promise<object>} A promise that resolves with the Vonage API response data on success.
     * @throws {Error} Throws an error if the message sending fails.
     */
    async function sendSms(recipient, messageText) {
      const sender = process.env.VONAGE_SENDER_ID;
    
      if (!recipient || !messageText || !sender) {
        throw new Error('Missing recipient, message text, or sender ID.');
      }
    
      console.log(`Attempting to send SMS from ${sender} to ${recipient}`);
    
      try {
        // Using vonage.sms.send for simpler SMS-only sending
        const responseData = await vonage.sms.send({
            to: recipient,
            from: sender,
            text: messageText
        });
    
        // Check response status from Vonage
        if (responseData.messages[0].status === '0') {
          console.log(`Message sent successfully to ${recipient}. Message UUID: ${responseData.messages[0]['message-id']}`);
          return responseData; // Resolve with the success response
        } else {
          const errorCode = responseData.messages[0].status;
          const errorText = responseData.messages[0]['error-text'];
          console.error(`Message failed with error code ${errorCode}: ${errorText}`);
          // Throw a specific error for easier handling upstream
          throw new Error(`Vonage API Error (${errorCode}): ${errorText}`);
        }
      } catch (error) {
        console.error('Error sending SMS via Vonage:', error);
        // Re-throw the error to be caught by the API route handler
        throw error;
      }
    }
    
    module.exports = { sendSms };

    Explanation:

    • We import the Vonage class from the SDK.
    • We initialize the vonage client using the API Key and Secret loaded from process.env (which dotenv will populate).
    • The sendSms function takes the recipient number and messageText as arguments.
    • It retrieves the sender ID from the environment variables.
    • Basic validation checks if required parameters are present.
    • We use vonage.sms.send(), which is a convenient method specifically for sending standard SMS. It takes an object with to, from, and text.
    • The function uses async/await for cleaner asynchronous code.
    • It checks the status property in the Vonage response. A status of '0' indicates success.
    • If successful, it logs the message ID and returns the response data.
    • If unsuccessful, it logs the error code and text provided by Vonage and throws an error.
    • A try...catch block handles potential network errors or issues during the API call itself.
    • The function is exported for use in our server file.

4. Building the API Layer (Express Server)

Now, let's set up the Express server and create the API endpoint to trigger the SMS sending.

  1. Create server.js: Open server.js and add the following code:

    javascript
    // server.js
    require('dotenv').config(); // Load environment variables from .env file
    const express = require('express');
    const { sendSms } = require('./vonageService'); // Import the SMS sending function
    
    const app = express();
    const port = process.env.PORT || 3000; // Use port from .env or default to 3000
    
    // Middleware to parse JSON request bodies
    app.use(express.json());
    // Middleware to parse URL-encoded request bodies
    app.use(express.urlencoded({ extended: true }));
    
    // --- API Endpoints ---
    
    // Health check endpoint
    app.get('/health', (req, res) => {
      res.status(200).json({ status: 'OK', timestamp: new Date().toISOString() });
    });
    
    // POST endpoint to send SMS
    app.post('/send-sms', async (req, res) => {
      const { to, message } = req.body; // Extract recipient and message from request body
    
      // --- Basic Input Validation ---
      if (!to || !message) {
        console.error('Validation Error: Missing ""to"" or ""message"" in request body');
        return res.status(400).json({
          success: false,
          message: 'Bad Request: Missing required fields ""to"" (recipient phone number) or ""message"".'
        });
      }
    
      // Basic E.164 format check (starts with +, followed by digits) - adjust regex as needed for stricter validation
      const e164Regex = /^\+[1-9]\d{1,14}$/;
      if (!e164Regex.test(to)) {
          console.error(`Validation Error: Invalid phone number format for ""to"": ${to}`);
          return res.status(400).json({
              success: false,
              message: 'Bad Request: Invalid recipient phone number format. Use E.164 format (e.g., +14155552671).'
          });
      }
    
    
      try {
        console.log(`Received request to send SMS to: ${to}`);
        const result = await sendSms(to, message); // Call the Vonage service function
    
        // Successfully sent SMS
        res.status(200).json({
          success: true,
          message: 'SMS sent successfully.',
          details: {
            to: result.messages[0].to,
            messageId: result.messages[0]['message-id'],
            status: result.messages[0].status,
            remainingBalance: result.messages[0]['remaining-balance'], // Useful info
            messagePrice: result.messages[0]['message-price'] // Useful info
          }
        });
      } catch (error) {
        console.error(`Failed to send SMS to ${to}:`, error.message);
    
        // Determine appropriate status code based on error (simplified here)
        // In production, you might inspect error types for more specific responses
        const statusCode = error.message.includes('Vonage API Error') ? 502 : 500; // 502 Bad Gateway if Vonage error, 500 otherwise
    
        res.status(statusCode).json({
          success: false,
          message: `Failed to send SMS. ${error.message}` // Include error message for client debugging
        });
      }
    });
    
    // --- Start Server ---
    app.listen(port, () => {
      console.log(`Server listening at http://localhost:${port}`);
      console.log(`Vonage Sender ID configured: ${process.env.VONAGE_SENDER_ID || 'NOT SET'}`);
      if (!process.env.VONAGE_API_KEY || !process.env.VONAGE_API_SECRET || !process.env.VONAGE_SENDER_ID) {
          console.warn('WARN: One or more Vonage environment variables (VONAGE_API_KEY, VONAGE_API_SECRET, VONAGE_SENDER_ID) are not set in .env');
      }
    });

    Explanation:

    • require('dotenv').config();: This line must be at the very top to load the .env variables before they are used anywhere else.
    • We import express and our sendSms function.
    • An Express application instance (app) is created.
    • express.json() and express.urlencoded() middleware are used to parse incoming JSON and URL-encoded request bodies, respectively. This enables us to access req.body.
    • A simple /health GET endpoint is included as a best practice for monitoring.
    • The core /send-sms POST endpoint is defined:
      • It extracts the to (recipient number) and message from the request body (req.body).
      • Input Validation: It checks if to and message are present. If not, it sends a 400 Bad Request response. It also includes a basic regex check for E.164 format.
      • It calls the sendSms function within an async function, using await to handle the promise.
      • A try...catch block handles potential errors during the sendSms call (either network issues or errors reported by Vonage).
      • Success Response: If sendSms resolves successfully, it sends a 200 OK response with success: true and relevant details from the Vonage response (like the message ID).
      • Error Response: If sendSms throws an error, it logs the error and sends an appropriate error response (e.g., 500 Internal Server Error or 502 Bad Gateway if it's a Vonage API issue) with success: false and the error message.
    • app.listen() starts the server on the specified port. We add logs to confirm the server is running and which Sender ID is configured, plus a warning if essential Vonage variables are missing.

5. Error Handling and Logging

We've implemented basic error handling, but let's refine it.

  • Consistent Error Strategy: Our current approach uses try...catch in the API route and throws/catches errors from the service layer. Errors are logged to the console, and appropriate HTTP status codes (400, 500, 502) with JSON error messages are returned to the client.
  • Logging: We are using console.log for informational messages and console.error for errors. For production, consider using a more robust logging library like Winston or Pino which enable:
    • Different log levels (debug, info, warn, error).
    • Structured logging (e.g., JSON format) for easier parsing by log analysis tools.
    • Writing logs to files or external services.
  • Retry Mechanisms: For transient network issues or specific Vonage rate-limit errors, implementing a retry strategy with exponential backoff could improve resilience. Libraries like async-retry can help implement this within the vonageService.js sendSms function, wrapping the vonage.sms.send call. This is beyond the scope of this basic guide but important for production.

Example Testing Error Scenario: Try sending a request without a to field to /send-sms. You should receive a 400 response. Try sending with invalid Vonage credentials in .env; you should receive a 502 or 500 response with an authentication error message.

6. Database Schema and Data Layer

This specific application does not require a database. It's a stateless API endpoint that processes requests immediately by calling an external service (Vonage).

If you were building a system to track sent messages, manage contacts, or queue messages, you would need a database (e.g., PostgreSQL, MongoDB) and a data access layer (possibly using an ORM like Prisma or Sequelize). This would involve defining schemas/models, setting up migrations, and writing functions to interact with the database.

7. Adding Security Features

Security is crucial, especially when dealing with APIs and credentials.

  • Input Validation and Sanitization:

    • We added basic validation for the presence of to and message and a format check for to.
    • For production, implement more robust validation using libraries like joi or express-validator.
    • Sanitize message content if it's ever displayed elsewhere, though for sending SMS directly, Vonage handles encoding. Be mindful of character limits and potential injection if constructing messages dynamically from untrusted input.
  • API Key Security:

    • Never hardcode API keys/secrets. Use environment variables (.env locally, platform-specific configuration in deployment).
    • Ensure .env is in .gitignore.
    • Rotate keys periodically if your platform supports it.
  • Rate Limiting:

    • Protect your API from abuse and excessive cost by implementing rate limiting. Use middleware like express-rate-limit.

    • Example (add after app.use(express.urlencoded...)):

      javascript
      const rateLimit = require('express-rate-limit');
      const limiter = rateLimit({
        windowMs: 15 * 60 * 1000, // 15 minutes
        max: 100, // Limit each IP to 100 requests per windowMs
        message: 'Too many requests from this IP, please try again after 15 minutes'
      });
      app.use('/send-sms', limiter); // Apply to the send-sms route
  • HTTPS: Always deploy your application behind HTTPS to encrypt traffic between the client and your server. Hosting platforms usually handle this.

  • Common Vulnerabilities: While less relevant for this simple API, be aware of OWASP Top 10 vulnerabilities (like injection, broken authentication, etc.) when building more complex applications.

8. Handling Special Cases

  • International Number Formatting: Always use the E.164 format for phone numbers (e.g., +14155552671, +447700900000). This ensures global compatibility. Our basic regex check enforces the starting +.
  • Character Limits & Encoding: Standard SMS messages have a 160-character limit (using GSM-7 encoding). Messages with characters outside this set (like emojis or many accented characters) use UCS-2 encoding, reducing the limit to 70 characters per SMS part. Longer messages are split into multiple parts (concatenated SMS). Vonage handles this splitting, but be aware it affects pricing (you pay per part). If sending emojis, ensure your sender ID supports unicode or the message might be garbled (Vonage usually handles this detection).
  • Sender ID Restrictions: Alphanumeric Sender IDs are not supported in all countries (e.g., USA requires standard numbers). Using a Vonage number is generally more reliable globally. Check Vonage documentation for country-specific regulations.
  • Delivery Reports (DLRs): This guide doesn't cover receiving DLRs, which confirm message delivery status to the handset. This requires setting up a separate webhook endpoint in your Vonage application settings and handling POST requests from Vonage.

9. Implementing Performance Optimizations

For this simple API, performance is largely dependent on the Vonage API response time.

  • Bottlenecks: The main potential bottleneck is the external API call to Vonage.
  • Caching: Caching is not applicable here as each request should trigger a unique SMS.
  • Resource Usage: Node.js is generally efficient. Ensure you handle asynchronous operations correctly (using async/await) to avoid blocking the event loop.
  • Load Testing: If expecting high volume, use tools like k6 or artillery to test how many concurrent requests your server and the Vonage API can handle. Monitor Vonage rate limits.
  • Concurrency: Node.js handles concurrency well via its event loop. If sending bulk messages, consider queuing requests (e.g., using Redis or RabbitMQ) and processing them with worker processes rather than handling everything synchronously within the API request, to provide faster responses to the client.

10. Adding Monitoring, Observability, and Analytics

For production readiness:

  • Health Checks: The /health endpoint provides a basic check. Monitoring services can poll this endpoint to verify the server is running.
  • Performance Metrics: Integrate Application Performance Monitoring (APM) tools (e.g., Datadog, New Relic, Dynatrace). These automatically instrument Express and Node.js to track request latency, error rates, throughput, and resource usage (CPU, memory).
  • Error Tracking: Use services like Sentry or Bugsnag. They capture unhandled exceptions and provide detailed context (stack traces, request data) for faster debugging. Integrate their Node.js SDKs.
  • Logging Aggregation: Send logs (preferably structured JSON) from your application (using Winston/Pino) to a centralized logging platform (e.g., Elasticsearch/Logstash/Kibana (ELK), Datadog Logs, Splunk). This enables searching, filtering, and creating dashboards based on log data (e.g., tracking SMS send failures by error code).
  • Dashboards: Create dashboards in your monitoring/logging tools to visualize key metrics:
    • API request rate and latency (overall and for /send-sms).
    • API error rate (4xx and 5xx).
    • Count of successful SMS sends vs. failures (based on logs or custom metrics).
    • Vonage API error codes distribution (from logs).
  • Alerting: Configure alerts in your monitoring system for critical issues:
    • High API error rate (> X%).
    • High API latency (> Y ms).
    • Server unresponsive (health check failing).
    • Specific Vonage error codes appearing frequently.

11. Troubleshooting and Caveats

  • Non-Whitelisted Destination Error: (Status Code 15 from Vonage) Occurs on trial accounts when sending to a number not added and verified in the ""Test Numbers"" section of the Vonage dashboard. Solution: Add and verify the recipient number.
  • Invalid Credentials Error: (Status Code 4 or similar auth errors) Double-check VONAGE_API_KEY and VONAGE_API_SECRET in your .env file. Ensure dotenv is loaded correctly (require('dotenv').config(); at the top of server.js). Make sure the .env file is in the root directory where you run node server.js.
  • Invalid Sender Address (from) Error: (Status Code 9 or similar) Ensure VONAGE_SENDER_ID in .env is a valid Vonage number associated with your account (in E.164 format) or an approved Alphanumeric Sender ID allowed in the destination country.
  • Invalid Message / Encoding Issues: If sending special characters/emojis results in ? or errors, ensure Vonage is correctly interpreting the content. vonage.sms.send generally handles this well. Using vonage.messages.send might require explicitly setting message_type: 'unicode'.
  • Rate Limiting by Vonage: If sending many messages quickly, you might hit Vonage's API rate limits (check their documentation for current limits). The API will return error responses (often status code 1). Implement delays or queuing if needed.
  • Missing .env Variables: The startup log in server.js includes a warning if key Vonage variables are missing. Ensure the .env file exists and is correctly formatted.
  • Incorrect to Number Format: Ensure the recipient number passed in the request body is in E.164 format. The API includes a basic check.
  • Vonage Service Outages: Check the Vonage Status Page if you suspect issues beyond your application.

12. Deployment and CI/CD

  • Environment Configuration: Do not deploy your .env file. Production environments (Heroku, AWS, Azure, Google Cloud, Render, etc.) provide mechanisms to set environment variables securely. Configure VONAGE_API_KEY, VONAGE_API_SECRET, VONAGE_SENDER_ID, and PORT in your chosen platform's settings.
  • Deployment Procedures:
    • Platforms like Heroku/Render: Connect your Git repository. The platform typically detects package.json, installs dependencies (npm install --production), and runs the start script (npm run start). Configure environment variables via their web UI or CLI.
    • Virtual Machines (EC2, etc.): Clone your repository, install Node.js/npm, run npm install --production, set environment variables (e.g., using systemd unit files or shell profiles), and use a process manager like pm2 to run your app (pm2 start server.js). Ensure firewalls allow traffic on your chosen PORT.
    • Serverless (AWS Lambda, etc.): Requires refactoring. Your Express app needs to be adapted to the platform's handler function signature (e.g., using frameworks like Serverless Framework or AWS SAM). Environment variables are set via function configuration.
  • CI/CD Pipeline:
    • Use tools like GitHub Actions, GitLab CI, or Jenkins.
    • Steps:
      1. Checkout Code: Get the latest code from your repository.
      2. Setup Node.js: Specify the Node.js version.
      3. Install Dependencies: Run npm ci (usually preferred over npm install in CI for deterministic builds).
      4. (Optional) Linting/Testing: Run code linters (eslint) and automated tests (jest, mocha).
      5. (Optional) Build Step: If using TypeScript or a build process, run it here.
      6. Deploy: Push the code/build artifacts to your hosting platform using its CLI or deployment mechanisms (e.g., heroku deploy, eb deploy, serverless deploy). Securely inject secrets/environment variables during this step.
  • Rollback Procedures: Familiarize yourself with your hosting platform's rollback mechanism (e.g., Heroku releases, AWS CodeDeploy rollbacks) to quickly revert to a previous working version if a deployment fails.

13. Verification and Testing

  1. Start the Server:

    bash
    npm start

    You should see the log message ""Server listening at http://localhost:3000"".

  2. Manual Verification (using curl): Open a new terminal window. Replace +1xxxxxxxxxx with a verified test number (if using a trial account) or any valid number (if using a paid account) in E.164 format. Replace YOUR_VONAGE_NUMBER_OR_SENDER_ID with the value you set.

    bash
    curl -X POST http://localhost:3000/send-sms \
         -H ""Content-Type: application/json"" \
         -d '{
               ""to"": ""+1xxxxxxxxxx"",
               ""message"": ""Hello from Node.js and Vonage!""
             }'
  3. Expected Success Output (Terminal running curl):

    json
    {
      ""success"": true,
      ""message"": ""SMS sent successfully."",
      ""details"": {
        ""to"": ""1xxxxxxxxxx"",
        ""messageId"": ""xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"",
        ""status"": ""0"",
        ""remainingBalance"": ""x.xxxx"",
        ""messagePrice"": ""x.xxxx""
      }
    }
  4. Expected Success Output (Terminal running server.js):

    Server listening at http://localhost:3000 Vonage Sender ID configured: YOUR_VONAGE_NUMBER_OR_SENDER_ID Received request to send SMS to: +1xxxxxxxxxx Attempting to send SMS from YOUR_VONAGE_NUMBER_OR_SENDER_ID to +1xxxxxxxxxx Message sent successfully to +1xxxxxxxxxx. Message UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  5. Check Your Phone: You should receive the SMS message on the recipient device.

  6. Test Failure Cases:

    • Send without to: curl -X POST http://localhost:3000/send-sms -H ""Content-Type: application/json"" -d '{""message"": ""test""}' (Expect 400)
    • Send without message: curl -X POST http://localhost:3000/send-sms -H ""Content-Type: application/json"" -d '{""to"": ""+1xxxxxxxxxx""}' (Expect 400)
    • Send with invalid to format: curl -X POST http://localhost:3000/send-sms -H ""Content-Type: application/json"" -d '{""to"": ""12345"", ""message"": ""test""}' (Expect 400)
    • Temporarily put incorrect credentials in .env and restart the server. Try sending again (Expect 500/502).
  7. (Optional) Automated Testing:

    • Unit Tests: Use frameworks like Jest or Mocha/Chai to test the vonageService.js logic. You would mock the @vonage/server-sdk to avoid making real API calls during tests, verifying that vonage.sms.send is called with the correct parameters based on input.
    • Integration Tests: Test the /send-sms endpoint using libraries like supertest. This makes actual HTTP requests to your running Express app (usually in a test environment), asserting the responses. You might still mock the Vonage call or have a dedicated test Vonage account.

Verification Checklist:

  • Project setup correctly (npm install successful).
  • .env file created with correct VONAGE_API_KEY, VONAGE_API_SECRET, VONAGE_SENDER_ID.
  • .env is listed in .gitignore.
  • Recipient number(s) whitelisted if using a trial Vonage account.
  • Server starts without errors (npm start).
  • /health endpoint returns 200 OK.
  • Sending a valid request to /send-sms using curl returns a 200 OK response with success: true.
  • The SMS message is received on the target phone number.
  • Sending invalid requests (missing fields, bad format) returns appropriate 400 errors.
  • Simulating API key errors results in 5xx errors.

This guide provides a solid foundation for sending SMS messages using Node.js and Vonage. Remember to consult the official Vonage Node SDK documentation and Vonage SMS API documentation.

Frequently Asked Questions

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

To send SMS with Node.js using Vonage, install the @vonage/server-sdk package, configure your API credentials in a .env file, initialize the Vonage client with new Vonage({ apiKey, apiSecret }), and call vonage.sms.send({ to, from, text }) with the recipient number, your Vonage number, and message text. The SDK returns a Promise that resolves with delivery status.

What Node.js version is required for Vonage SMS API?

The Vonage Node Server SDK requires Node.js v18 or higher for optimal compatibility with modern features like async/await and ES modules. While older versions may work, v18+ ensures full support for all SDK features and security updates.

How much does it cost to send SMS with Vonage?

Vonage SMS pricing varies by destination country. New accounts receive free credit for testing. You can check real-time pricing in your Vonage Dashboard under "Pricing" or view the message-price field in API responses. Trial accounts have daily limits and require recipient number whitelisting.

How do I handle Vonage SMS API errors in Node.js?

Vonage SMS API returns status codes in responses: status '0' indicates success, while non-zero codes indicate errors. Common errors include status 15 (Non-Whitelisted Destination on trial accounts), status 4 (Invalid Credentials), and status 1 (Throttled/Rate Limited). Implement try...catch blocks and check the status and error-text fields in responses.

What is E.164 phone number format for Vonage SMS?

E.164 is the international telephone numbering format required by Vonage: a + symbol followed by country code and subscriber number, with no spaces or special characters (e.g., +14155552671 for US numbers, +447700900000 for UK). Use the regex /^\+[1-9]\d{1,14}$/ to validate E.164 format.

Can I send SMS from localhost with Vonage?

Yes, you can send SMS from localhost using Vonage. The Vonage API only requires outbound HTTPS connections, so your local Node.js application can make API calls without exposing ports or using webhooks. However, receiving delivery receipts (DLRs) requires a publicly accessible webhook URL.

How do I secure Vonage API credentials in Node.js?

Store Vonage API credentials in environment variables using the dotenv package. Create a .env file with VONAGE_API_KEY and VONAGE_API_SECRET, add .env to .gitignore, and load variables with require('dotenv').config() before initializing the Vonage client. Never hardcode credentials or commit them to version control.

What is the rate limit for Vonage SMS API?

Vonage SMS API has a default rate limit of 30 requests per second per API key. Exceeding this limit returns status code 1 (Throttled). For higher throughput, contact Vonage support. US 10DLC numbers have additional per-minute limits based on campaign type. Implement rate limiting middleware like express-rate-limit to protect your API.

How do I send SMS to international numbers with Vonage Node.js?

To send international SMS, ensure the recipient number is in E.164 format with the correct country code (e.g., +61 for Australia, +81 for Japan). Some countries have regulatory requirements like sender ID registration. Check Vonage's country-specific documentation and verify your account has international messaging enabled.

Why am I getting "Non-Whitelisted Destination" error from Vonage?

The "Non-Whitelisted Destination" error (status code 15) occurs on Vonage trial accounts when sending to numbers not verified in your dashboard. Navigate to "Sandbox & Tools" > "Test Numbers", add the recipient number, and verify it via SMS or voice call. Upgrade to a paid account to remove this restriction.

Frequently Asked Questions

How to send SMS messages with Node.js?

Use the Vonage SMS API with the Vonage Node Server SDK and Express.js. Create an Express API endpoint that takes the recipient's number and message, then uses the SDK to send the SMS through Vonage's API.

What is the Vonage Node Server SDK?

It's the official library (`@vonage/server-sdk`) for interacting with Vonage APIs from your Node.js application. This SDK simplifies making API calls to Vonage's services, including the SMS API.

Why does Vonage require an API key and secret?

The API key and secret authenticate your application with Vonage's platform. These credentials verify your identity and authorize access to your Vonage account features and services.

When should I whitelist recipient numbers with Vonage?

Whitelisting is necessary for Vonage trial accounts. Add the recipient numbers you'll be testing with to the "Test Numbers" section of your Vonage dashboard to avoid "Non-Whitelisted Destination" errors.

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

Store your API key, secret, and sender ID in a `.env` file. Use the `dotenv` package to load these variables into `process.env` within your application. Never commit `.env` to version control.

What is the role of Express.js in sending SMS with Vonage?

Express.js creates the API endpoint that receives requests to send messages. It handles routing, middleware, and communication with both the client making the request and the Vonage API.

How to handle errors when sending SMS via Vonage?

Use `try...catch` blocks to handle errors from the Vonage API call. Check the Vonage response status and log errors appropriately. Provide informative error responses to the client.

How do I handle international phone numbers when sending SMS?

Always use the E.164 format (e.g., +14155552671). This standardized format ensures Vonage routes messages internationally without issue.

How to check the status of sent SMS messages?

The Vonage API returns a status code in its response. A '0' status means success. For delivery confirmation, you need to implement Vonage Delivery Receipts (DLRs) using webhooks.

What are some Vonage SMS limitations to be aware of?

SMS messages have character limits: 160 for GSM-7 encoding and 70 for UCS-2 (used for special characters). Longer messages are split, increasing costs. Alphanumeric sender IDs have country restrictions.

How to troubleshoot the 'Non-Whitelisted Destination' error?

This error (code 15) is specific to Vonage trial accounts. Ensure the recipient number is added and verified in the 'Test Numbers' section of the Vonage dashboard.

How to handle Vonage API rate limits in my application?

Monitor Vonage's API documentation for rate limits. If you anticipate high message volume, implement rate limiting in your Express app using middleware like `express-rate-limit` and consider using a message queue.

What is E.164 format and why does Vonage require it?

E.164 is an international standard for phone numbers. It includes a '+' and country code (e.g., +1 for USA). Using E.164 ensures correct routing of your SMS globally.

Can I use emojis in my SMS messages via Vonage?

Yes, but be aware that emojis typically require UCS-2 encoding, reducing the character limit per SMS segment to 70. Vonage handles encoding, but ensure your sender ID supports Unicode.