code examples

Sent logo
Sent TeamMar 8, 2026 / code examples / vonage

How to Send SMS Messages with Vonage API in Node.js: Complete Express Integration Guide

Build a production-ready SMS API with Vonage and Node.js Express. Complete tutorial with authentication, rate limiting, error handling, and deployment. Send SMS messages programmatically in minutes.

How to Send SMS Messages with Vonage API in Node.js: Complete Express Integration Guide

Meta Description: Build a production-ready SMS API with Vonage and Node.js Express. Complete tutorial with authentication, rate limiting, error handling, and deployment. Send SMS messages programmatically in minutes.

Build a production-ready Node.js application using Express to send SMS messages via the Vonage Messages API (formerly Nexmo). This comprehensive tutorial covers project setup, REST API development, security best practices, error handling, testing, and deployment to production environments.

You'll create a functional REST API endpoint that accepts phone numbers and message content, securely sends SMS messages using the Vonage Node.js SDK, and handles errors gracefully. This forms a solid foundation for integrating SMS capabilities into web applications, mobile backends, notification systems, two-factor authentication (2FA), one-time password (OTP) delivery, appointment reminders, and customer communication workflows.

Last Updated: January 15, 2025
Compatible With: Vonage Messages API v3, Node.js 18+, Express 4.x

What You'll Build: Production SMS API

Your Application:

A REST API built with Node.js and Express that exposes a /send-sms endpoint. This endpoint accepts a recipient phone number in E.164 format and message body, then uses the Vonage Messages API to deliver SMS messages to recipients worldwide.

Problem Solved:

Create a reusable, server-side component for programmatic SMS delivery. Abstract direct interaction with the Vonage REST API into a simple, authenticated API call within your own infrastructure. Enable SMS functionality without exposing Vonage credentials to client applications.

Technology Stack:

  • Node.js – JavaScript runtime for building server-side applications (v18+ recommended for Long-Term Support with native fetch API and improved performance).
  • Express.js – Minimal and flexible Node.js web framework for creating RESTful API servers and routes.
  • Vonage Node.js Server SDK – Official library (@vonage/server-sdk) for interacting with Vonage Communications APIs, specifically the Messages API for SMS delivery.
  • dotenv – Module to load environment variables from a .env file into process.env, keeping API keys and secrets secure.
  • Joi – Schema description language and data validator for JavaScript, ensuring request data integrity.
  • Helmet – Security middleware for Express that sets various HTTP headers.
  • Express Rate Limit – Rate limiting middleware to prevent API abuse.
  • Morgan – HTTP request logger middleware for Node.js.

System Architecture:

A client application (web frontend, mobile app, or microservice) sends an HTTP POST request with JSON payload to the /send-sms endpoint of your Node.js/Express API server. The API authenticates the request, validates input data, and uses the Vonage SDK (configured with API credentials from environment variables) to communicate with the Vonage Messages API over HTTPS. Vonage's carrier network then delivers the SMS message to the recipient's mobile device.

Prerequisites:

  • Node.js and npm (or yarn) – Install from nodejs.org. Version 18 LTS or later recommended for optimal stability and security patches.
  • Vonage API Account – Sign up for free at Vonage API Dashboard. New accounts receive complimentary credit for testing SMS delivery.
  • Vonage Virtual Number – Rent a Vonage phone number capable of sending SMS messages through the Vonage Dashboard. Number availability and pricing vary by country.
  • Basic JavaScript and REST API knowledge – Familiarity with asynchronous programming, HTTP methods, and JSON.
  • Text editor or IDE (e.g., Visual Studio Code, WebStorm, or Sublime Text).
  • (Optional) API Testing Tool – Postman, Insomnia, or curl for endpoint testing.

Final Outcome:

A running Node.js Express application with a secure, authenticated endpoint (/send-sms) that successfully sends SMS messages via Vonage when provided with a valid recipient phone number, message content, and correct API credentials. The application includes robust input validation, comprehensive error handling, request logging, rate limiting, and deployment-ready configuration.


1. Node.js Project Setup and Dependency Installation

Initialize your Node.js project and install the necessary packages for SMS API development.

1.1 Create Project Directory:

Open your terminal and create a new directory for the Vonage SMS project:

bash
mkdir vonage-sms-sender
cd vonage-sms-sender

1.2 Initialize Node.js Project:

Create a package.json file to manage dependencies, scripts, and project metadata:

bash
npm init -y

If using yarn: yarn init -y

This generates a basic package.json with default values. You can customize the name, version, description, and other fields later.

1.3 Install Required Dependencies:

Install Express web framework, the Vonage Server SDK, dotenv for environment variable management, and joi for request validation:

bash
npm install express @vonage/server-sdk dotenv joi

If using yarn: yarn add express @vonage/server-sdk dotenv joi

Package Explanations:

  • express (v4.18+) – Web framework for building HTTP servers and REST APIs
  • @vonage/server-sdk (v3.12+) – Official Vonage library for SMS, voice, and messaging APIs
  • dotenv (v16.3+) – Loads environment variables from .env files
  • joi (v17.11+) – Schema-based validation library

1.4 Create Project Structure:

Create the basic files and folders for your SMS API application:

bash
# Linux/macOS
touch index.js .env .gitignore smsService.js

# Windows (Command Prompt)
type nul > index.js
type nul > .env
type nul > .gitignore
type nul > smsService.js

# Windows (PowerShell)
New-Item index.js -ItemType File
New-Item .env -ItemType File
New-Item .gitignore -ItemType File
New-Item smsService.js -ItemType File

File Descriptions:

  • index.js – Main entry point for your Express application, defines routes and middleware
  • smsService.js – Module dedicated to handling Vonage SMS API interactions
  • .env – Stores sensitive configuration like API keys and secrets. Never commit to version control.
  • .gitignore – Specifies files that Git should ignore (credentials, dependencies, logs)

1.5 Configure .gitignore:

Open .gitignore and add these lines to prevent committing sensitive files and unnecessary directories:

text
# .gitignore
node_modules/
.env
npm-debug.log
yarn-error.log
.DS_Store
*.log
dist/
build/

This prevents accidentally exposing your Vonage API credentials or uploading large dependency folders to Git repositories.

1.6 Configure Environment Variables:

Open the .env file and add your Vonage API credentials and configuration:

text
# .env
VONAGE_API_KEY=YOUR_VONAGE_API_KEY_HERE
VONAGE_API_SECRET=YOUR_VONAGE_API_SECRET_HERE
VONAGE_FROM_NUMBER=YOUR_VONAGE_VIRTUAL_NUMBER_HERE
PORT=3000
NODE_ENV=development
API_KEY=your-secure-api-key-here

Environment Variable Descriptions:

  • VONAGE_API_KEY – Your Vonage API key from the Vonage Dashboard. Found under "API Settings" or "Your API Keys".
  • VONAGE_API_SECRET – Your Vonage API secret from the dashboard. Keep this confidential.
  • VONAGE_FROM_NUMBER – Your Vonage virtual number in E.164 format without spaces or dashes (e.g., 14155551234 for a US number). This appears as the sender ID.
  • PORT – The port your Express server will listen on (default: 3000). Change for production or to avoid port conflicts.
  • NODE_ENV – Environment identifier (development, production, test). Used for conditional logic.
  • API_KEY – Custom API key for authenticating requests to your SMS endpoint. Generate a strong random string.

Security Best Practices:

  • Never hardcode credentials in source code
  • Use different .env files for development, staging, and production
  • Rotate API keys regularly
  • Limit API key permissions in Vonage Dashboard

Your project structure now looks like this:

text
vonage-sms-sender/
├── node_modules/
├── .env
├── .gitignore
├── index.js
├── smsService.js
└── package.json

2. Build the SMS Service Module with Vonage SDK

Create a dedicated module to handle all Vonage SMS API interactions. This separation of concerns makes your code more maintainable, testable, and reusable.

2.1 Implement smsService.js:

Open smsService.js and add this code to initialize the Vonage client and create the SMS sending function:

javascript
// smsService.js
const { Vonage } = require('@vonage/server-sdk');
require('dotenv').config();

// Initialize Vonage client with credentials from environment variables
const vonage = new Vonage({
  apiKey: process.env.VONAGE_API_KEY,
  apiSecret: process.env.VONAGE_API_SECRET,
});

/**
 * Send an SMS message via Vonage
 * @param {string} to - Recipient phone number in E.164 format (e.g., "14155551234")
 * @param {string} text - Message content
 * @returns {Promise<object>} - Vonage API response
 */
async function sendSms(to, text) {
  const from = process.env.VONAGE_FROM_NUMBER;

  if (!from) {
    throw new Error('VONAGE_FROM_NUMBER environment variable not set');
  }

  try {
    // Send SMS using Vonage SDK
    const response = await vonage.sms.send({
      to,
      from,
      text,
    });

    // Check if message was sent successfully
    if (response.messages[0].status === '0') {
      console.log(`SMS sent successfully to ${to}. Message ID: ${response.messages[0]['message-id']}`);
      return {
        success: true,
        messageId: response.messages[0]['message-id'],
        to,
      };
    } else {
      // Vonage returned an error
      const error = response.messages[0];
      console.error(`SMS failed to send to ${to}. Error: ${error['error-text']}`);
      throw new Error(`Vonage API Error: ${error['error-text']}`);
    }
  } catch (error) {
    console.error('Error sending SMS:', error.message);
    throw error;
  }
}

module.exports = { sendSms };

How It Works:

  1. Import Dependencies – Load the Vonage SDK and dotenv for environment variables.
  2. Initialize Vonage Client – Create a Vonage instance with your API key and secret from environment variables. Authentication uses the API Key/Secret pair.
  3. sendSms Function – Exports an async function that accepts recipient number and message text.
  4. Configuration Validation – Checks if VONAGE_FROM_NUMBER is set before attempting to send. Throws descriptive error if missing.
  5. Send SMS via Vonage API – Calls vonage.sms.send() with the to, from, and text parameters.
  6. Response Handling – Vonage returns an array of message objects. Status code '0' indicates success. Other codes indicate various error conditions.
  7. Success Response – Logs success message and returns structured response with messageId for tracking.
  8. Error Handling – Catches API errors, network errors, and Vonage-specific error codes. Throws descriptive exceptions.

Key Points:

  • E.164 Phone Number Format – All phone numbers must use international format without spaces: country code + number (e.g., 14155551234 for US, 447700900000 for UK).
  • Vonage Status Codes – Status '0' means success. Codes 1-15 represent different error conditions (throttling, invalid params, invalid credentials, etc.).
  • Async/Await Pattern – Modern JavaScript syntax for handling asynchronous Vonage API calls.
  • Error Propagation – Throwing errors allows the calling code (Express route) to handle them appropriately.

3. Create the Express REST API Server

Build your Express server with a /send-sms endpoint that uses the SMS service module.

3.1 Implement index.js with API Endpoint:

Open index.js and add this code to create your REST API server with validation and error handling:

javascript
// index.js
const express = require('express');
const Joi = require('joi');
const { sendSms } = require('./smsService');
require('dotenv').config();

const app = express();
const PORT = process.env.PORT || 3000;

// Middleware to parse JSON request bodies
app.use(express.json());

// Validation schema for SMS requests
const smsSchema = Joi.object({
  to: Joi.string()
    .pattern(/^\d{10,15}$/)
    .required()
    .messages({
      'string.pattern.base': 'Phone number must contain 10-15 digits in E.164 format',
      'any.required': 'Recipient phone number is required',
    }),
  text: Joi.string()
    .min(1)
    .max(160)
    .required()
    .messages({
      'string.min': 'Message cannot be empty',
      'string.max': 'Message cannot exceed 160 characters',
      'any.required': 'Message text is required',
    }),
});

// POST /send-sms endpoint
app.post('/send-sms', async (req, res) => {
  try {
    // Validate request body
    const { error, value } = smsSchema.validate(req.body);

    if (error) {
      return res.status(400).json({
        success: false,
        error: 'Validation failed',
        details: error.details.map(detail => detail.message),
      });
    }

    const { to, text } = value;

    // Send SMS via Vonage
    const result = await sendSms(to, text);

    // Return success response
    return res.status(200).json({
      success: true,
      message: 'SMS sent successfully',
      messageId: result.messageId,
      to: result.to,
    });

  } catch (error) {
    console.error('Error in /send-sms endpoint:', error.message);

    // Return error response
    return res.status(500).json({
      success: false,
      error: 'Failed to send SMS',
      details: error.message,
    });
  }
});

// Health check endpoint
app.get('/health', (req, res) => {
  res.status(200).json({ status: 'OK', timestamp: new Date().toISOString() });
});

// Start server
app.listen(PORT, () => {
  console.log(`Server running on http://localhost:${PORT}`);
  console.log(`Send SMS: POST http://localhost:${PORT}/send-sms`);
});

How It Works:

  1. Express Setup – Initialize Express app and configure JSON body parsing middleware.
  2. Environment Variables – Load configuration from .env file using dotenv.
  3. Validation Schema – Define Joi schema to validate incoming SMS requests:
    • to – Phone number with 10-15 digits, E.164 format validation
    • text – Message content, 1-160 characters (standard SMS length)
  4. POST /send-sms Endpoint:
    • Validates request body against the schema
    • Returns HTTP 400 Bad Request if validation fails with specific error messages
    • Calls sendSms() from your SMS service module
    • Returns HTTP 200 OK with success details (messageId, recipient) on successful delivery
    • Returns HTTP 500 Internal Server Error if SMS sending fails
  5. Health Check EndpointGET /health returns server status, useful for monitoring and load balancers.
  6. Start Server – Listens on configured port with console feedback.

API Request/Response Examples:

Successful Request:

json
POST /send-sms
Content-Type: application/json

{
  "to": "14155551234",
  "text": "Your verification code is 123456"
}

Success Response (HTTP 200):

json
{
  "success": true,
  "message": "SMS sent successfully",
  "messageId": "0B00000123456789",
  "to": "14155551234"
}

Validation Error Response (HTTP 400):

json
{
  "success": false,
  "error": "Validation failed",
  "details": [
    "Phone number must contain 10-15 digits in E.164 format"
  ]
}

Key Features:

  • Input Validation – Joi schema ensures data integrity before processing, preventing invalid API calls.
  • Structured Error Handling – Try-catch blocks prevent server crashes and provide meaningful error responses.
  • Clear JSON Responses – Consistent response format for success and failure cases.
  • Console Logging – Request and error logging for debugging and monitoring.
  • Health Endpoint – Useful for container orchestration, load balancers, and uptime monitoring.

4. Test Your SMS API Endpoint

Verify your SMS endpoint works correctly using curl, Postman, or other API testing tools.

4.1 Start the Development Server:

Run your Node.js application:

bash
node index.js

You should see console output:

text
Server running on http://localhost:3000
Send SMS: POST http://localhost:3000/send-sms

4.2 Test SMS Sending with curl:

Send a test SMS using curl in a new terminal window:

bash
curl -X POST http://localhost:3000/send-sms \
  -H "Content-Type: application/json" \
  -d '{
    "to": "14155551234",
    "text": "Hello from Vonage SMS API!"
  }'

Expected Success Response (HTTP 200):

json
{
  "success": true,
  "message": "SMS sent successfully",
  "messageId": "0B00000123456789",
  "to": "14155551234"
}

Check the recipient's phone – they should receive the SMS message (ensure you have Vonage credit and a valid number).

4.3 Test Input Validation:

Send an invalid request missing the phone number:

bash
curl -X POST http://localhost:3000/send-sms \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Test message without phone number"
  }'

Expected Validation Error (HTTP 400):

json
{
  "success": false,
  "error": "Validation failed",
  "details": [
    "Recipient phone number is required"
  ]
}

Test with an invalid phone number format:

bash
curl -X POST http://localhost:3000/send-sms \
  -H "Content-Type: application/json" \
  -d '{
    "to": "555-1234",
    "text": "Invalid format test"
  }'

Expected Response (HTTP 400):

json
{
  "success": false,
  "error": "Validation failed",
  "details": [
    "Phone number must contain 10-15 digits in E.164 format"
  ]
}

4.4 Test with Postman:

  1. Open Postman and create a new POST request.
  2. Set URL to http://localhost:3000/send-sms.
  3. Set Headers: Content-Type: application/json.
  4. Set Body (raw JSON):
    json
    {
      "to": "14155551234",
      "text": "Testing Vonage SMS from Postman"
    }
  5. Click Send.

You should receive a success response, and the recipient phone should receive the SMS message.

4.5 Test Health Check Endpoint:

bash
curl http://localhost:3000/health

Expected Response (HTTP 200):

json
{
  "status": "OK",
  "timestamp": "2025-01-15T10:30:00.000Z"
}

Use this endpoint for application monitoring, load balancer health checks, and uptime verification.


5. Add Production Security Features

Enhance your SMS API for production deployment with authentication, rate limiting, security headers, and request logging.

5.1 Install Security Dependencies:

Install Helmet for security headers, CORS for cross-origin requests, and Express Rate Limit for rate limiting:

bash
npm install helmet cors express-rate-limit morgan

If using yarn: yarn add helmet cors express-rate-limit morgan

5.2 Implement Security Middleware:

Update index.js to include comprehensive security middleware:

javascript
// index.js (updated with security features)
const express = require('express');
const helmet = require('helmet');
const cors = require('cors');
const rateLimit = require('express-rate-limit');
const morgan = require('morgan');
const Joi = require('joi');
const { sendSms } = require('./smsService');
require('dotenv').config();

const app = express();
const PORT = process.env.PORT || 3000;
const API_KEY = process.env.API_KEY || 'your-secret-api-key';

// Validate required environment variables at startup
const requiredEnvVars = ['VONAGE_API_KEY', 'VONAGE_API_SECRET', 'VONAGE_FROM_NUMBER', 'API_KEY'];
requiredEnvVars.forEach(varName => {
  if (!process.env[varName]) {
    console.error(`Error: Missing required environment variable ${varName}`);
    process.exit(1);
  }
});

// Security middleware
app.use(helmet()); // Sets security-related HTTP headers
app.use(cors()); // Enable Cross-Origin Resource Sharing
app.use(express.json()); // Parse JSON request bodies
app.use(morgan('combined')); // Log all HTTP requests

// Rate limiting middleware – prevents API abuse
const limiter = rateLimit({
  windowMs: 60 * 1000, // 1 minute window
  max: 10, // Max 10 requests per minute per IP
  message: {
    success: false,
    error: 'Too many requests. Please try again later.',
  },
  standardHeaders: true, // Return rate limit info in headers
  legacyHeaders: false,
});

// Apply rate limiter to SMS endpoint
app.use('/send-sms', limiter);

// API Key authentication middleware
function authenticateApiKey(req, res, next) {
  const apiKey = req.headers['x-api-key'];

  if (!apiKey || apiKey !== API_KEY) {
    return res.status(401).json({
      success: false,
      error: 'Unauthorized. Invalid or missing API key.',
      hint: 'Include X-API-Key header with your request',
    });
  }

  next();
}

// Validation schema
const smsSchema = Joi.object({
  to: Joi.string()
    .pattern(/^\d{10,15}$/)
    .required()
    .messages({
      'string.pattern.base': 'Phone number must contain 10-15 digits in E.164 format',
      'any.required': 'Recipient phone number is required',
    }),
  text: Joi.string()
    .min(1)
    .max(160)
    .required()
    .messages({
      'string.min': 'Message cannot be empty',
      'string.max': 'Message cannot exceed 160 characters',
      'any.required': 'Message text is required',
    }),
});

// POST /send-sms endpoint with authentication
app.post('/send-sms', authenticateApiKey, async (req, res) => {
  try {
    // Validate request body
    const { error, value } = smsSchema.validate(req.body);

    if (error) {
      return res.status(400).json({
        success: false,
        error: 'Validation failed',
        details: error.details.map(detail => detail.message),
      });
    }

    const { to, text } = value;

    // Send SMS via Vonage
    const result = await sendSms(to, text);

    // Return success response
    return res.status(200).json({
      success: true,
      message: 'SMS sent successfully',
      messageId: result.messageId,
      to: result.to,
    });

  } catch (error) {
    console.error('Error in /send-sms endpoint:', error.message);

    // Return error response
    return res.status(500).json({
      success: false,
      error: 'Failed to send SMS',
      details: error.message,
    });
  }
});

// Health check endpoint
app.get('/health', (req, res) => {
  res.status(200).json({
    status: 'OK',
    timestamp: new Date().toISOString(),
    uptime: process.uptime(),
  });
});

// Global error handler
app.use((err, req, res, next) => {
  console.error('Unhandled error:', err);

  res.status(err.status || 500).json({
    success: false,
    error: err.message || 'Internal server error',
  });
});

// 404 handler for unknown routes
app.use((req, res) => {
  res.status(404).json({
    success: false,
    error: 'Route not found',
    availableEndpoints: [
      'POST /send-sms',
      'GET /health',
    ],
  });
});

// Start server
app.listen(PORT, () => {
  console.log(`Server running on http://localhost:${PORT}`);
  console.log(`Send SMS: POST http://localhost:${PORT}/send-sms`);
  console.log(`Environment: ${process.env.NODE_ENV}`);
});

Security Features Explained:

  1. Helmet – Sets HTTP headers to protect against common web vulnerabilities (XSS, clickjacking, MIME sniffing).
  2. CORS – Enables cross-origin requests, allowing frontend applications on different domains to call your API.
  3. Rate Limiting – Prevents abuse by limiting requests to 10 per minute per IP address. Adjust values based on your needs.
  4. API Key Authentication – Requires X-API-Key header matching your secret key. Prevents unauthorized access.
  5. Request Logging – Morgan logs all HTTP requests with timestamps, methods, URLs, status codes, and response times.
  6. Environment Validation – Checks all required variables exist at startup, preventing runtime errors.
  7. Global Error Handler – Catches unhandled errors and returns consistent JSON responses.
  8. 404 Handler – Returns helpful error message for unknown routes with available endpoints.

Test with Authentication:

bash
curl -X POST http://localhost:3000/send-sms \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-secure-api-key-here" \
  -d '{
    "to": "14155551234",
    "text": "Authenticated SMS test"
  }'

Without the API key header, you'll receive a 401 Unauthorized error.


6. Implement Advanced Error Handling

Enhance error handling for production reliability with specific error messages and Vonage error code mapping.

6.1 Enhanced SMS Service Error Handling:

Update smsService.js with comprehensive error handling and Vonage error code mapping:

javascript
async function sendSms(to, text) {
  const from = process.env.VONAGE_FROM_NUMBER;

  if (!from) {
    throw new Error('Server configuration error: VONAGE_FROM_NUMBER not set');
  }

  try {
    const response = await vonage.sms.send({ to, from, text });

    if (response.messages[0].status === '0') {
      console.log(`SMS sent successfully to ${to}. Message ID: ${response.messages[0]['message-id']}`);
      return {
        success: true,
        messageId: response.messages[0]['message-id'],
        to,
      };
    } else {
      const error = response.messages[0];
      
      // Map Vonage error codes to user-friendly messages
      const errorMessages = {
        '1': 'Message throttled – too many requests',
        '2': 'Missing parameters',
        '3': 'Invalid parameters',
        '4': 'Invalid credentials',
        '5': 'Internal error',
        '6': 'Invalid message',
        '7': 'Number barred',
        '8': 'Partner account barred',
        '9': 'Partner quota exceeded',
        '15': 'Invalid sender address',
      };

      const userMessage = errorMessages[error.status] || error['error-text'];
      throw new Error(`SMS failed: ${userMessage}`);
    }
  } catch (error) {
    if (error.code === 'ECONNREFUSED') {
      throw new Error('Cannot connect to Vonage API. Check your network connection.');
    } else if (error.code === 'ETIMEDOUT') {
      throw new Error('Vonage API request timed out. Please try again.');
    }
    
    throw error;
  }
}

Vonage Error Code Mapping:

  • Status 1 – Throttled – You've exceeded your rate limit
  • Status 2 – Missing parameters – Required fields not provided
  • Status 3 – Invalid parameters – Malformed or invalid data
  • Status 4 – Invalid credentials – API key or secret incorrect
  • Status 5 – Internal error – Vonage service issue
  • Status 6 – Invalid message – Message content violates policies
  • Status 7 – Number barred – Recipient number blocked or invalid
  • Status 9 – Partner quota exceeded – Account credit exhausted
  • Status 15 – Invalid sender address – FROM number not authorized

This error mapping helps you quickly diagnose issues and provide meaningful feedback to API consumers.


7. Deploy Your SMS API to Production

Prepare your application for production deployment with deployment scripts and hosting platform configuration.

7.1 Add NPM Scripts:

Update package.json to include useful scripts for development and production:

json
{
  "name": "vonage-sms-sender",
  "version": "1.0.0",
  "description": "Production-ready SMS API using Vonage and Express",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "dev": "nodemon index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": ["vonage", "sms", "api", "express", "nodejs"],
  "author": "Your Name",
  "license": "MIT",
  "dependencies": {
    "express": "^4.18.2",
    "@vonage/server-sdk": "^3.12.0",
    "dotenv": "^16.3.1",
    "joi": "^17.11.0",
    "helmet": "^7.1.0",
    "cors": "^2.8.5",
    "express-rate-limit": "^7.1.5",
    "morgan": "^1.10.0"
  },
  "devDependencies": {
    "nodemon": "^3.0.2"
  },
  "engines": {
    "node": ">=18.0.0",
    "npm": ">=9.0.0"
  }
}

Install nodemon for automatic server restarts during development:

bash
npm install --save-dev nodemon

Run in development mode with auto-restart:

bash
npm run dev

7.2 Deploy to Heroku:

Deploy your SMS API to Heroku's cloud platform:

  1. Install Heroku CLI – Download from Heroku CLI.

  2. Login to Heroku:

    bash
    heroku login
  3. Create Heroku App:

    bash
    heroku create your-vonage-sms-api
  4. Set Environment Variables:

    bash
    heroku config:set VONAGE_API_KEY=your_api_key
    heroku config:set VONAGE_API_SECRET=your_api_secret
    heroku config:set VONAGE_FROM_NUMBER=your_from_number
    heroku config:set API_KEY=your_secure_api_key
    heroku config:set NODE_ENV=production
  5. Deploy Application:

    bash
    git init
    git add .
    git commit -m "Initial commit – Vonage SMS API"
    git push heroku main
  6. Test Deployed API:

    bash
    curl -X POST https://your-vonage-sms-api.herokuapp.com/send-sms \
      -H "Content-Type: application/json" \
      -H "X-API-Key: your_secure_api_key" \
      -d '{"to": "14155551234", "text": "Hello from Heroku!"}'

7.3 Deploy to Railway:

Railway offers simple Node.js deployment with automatic builds:

  1. Create account at Railway.app
  2. Connect your GitHub repository
  3. Add environment variables in Railway dashboard
  4. Deploy with automatic builds on git push
  5. Railway provides HTTPS URL automatically

7.4 Deploy to Render:

Render provides free tier for Node.js applications:

  1. Create account at Render.com
  2. Create new Web Service from Git repository
  3. Configure environment variables
  4. Set build command: npm install
  5. Set start command: npm start
  6. Deploy with automatic SSL certificate

7.5 Deploy with PM2 (VPS/Cloud Server):

For VPS deployment (DigitalOcean, AWS EC2, Linode), use PM2 process manager:

bash
# Install PM2 globally
npm install -g pm2

# Start application with PM2
pm2 start index.js --name vonage-sms-api

# Configure PM2 to start on system boot
pm2 startup
pm2 save

# Monitor application
pm2 status
pm2 logs vonage-sms-api

# Restart application
pm2 restart vonage-sms-api

PM2 provides automatic restarts on crashes, load balancing, and zero-downtime reloads.


Frequently Asked Questions (FAQ)

How much does it cost to send SMS messages with Vonage?

Vonage SMS pricing varies by destination country. US SMS typically costs $0.0075 per message (less than 1 cent). International rates range from $0.01 to $0.50+ per message depending on the country. Check current pricing at Vonage SMS Pricing. New accounts include free credit ($2) for testing. Volume discounts available for high-volume senders.

What phone number format should I use for international SMS?

Always use E.164 format – the international standard for phone numbers. Format: [country code][area code][local number] without spaces, dashes, or special characters. Examples: 14155551234 (US), 447700900000 (UK), 61412345678 (Australia), 919876543210 (India). Remove leading zeros and include the country code prefix.

Can I send SMS messages to international phone numbers?

Yes. Vonage supports SMS delivery to 200+ countries worldwide. Ensure your Vonage account has international SMS enabled (check Dashboard → Settings → SMS). Verify sufficient account credit for international delivery. Pricing varies significantly by country – some regions cost 10-50x more than US domestic SMS. Test with small volumes first.

How do I handle SMS delivery receipts and status updates?

Vonage can send delivery receipt callbacks (webhooks) to your server when SMS messages are delivered or fail. Configure webhook URL in Vonage Dashboard under Settings → SMS Settings → Delivery Receipts. Implement a POST endpoint (e.g., /webhooks/delivery-receipt) to receive status updates. Delivery receipts include message ID, status, timestamp, and error codes. Store these in your database for tracking and analytics.

What's the character limit for SMS messages?

Standard SMS supports 160 characters using GSM-7 encoding (basic Latin alphabet, numbers, common symbols). Messages using special characters, emojis, or non-Latin scripts use Unicode (UCS-2) encoding, which reduces the limit to 70 characters per segment. Vonage automatically concatenates longer messages into multiple segments (up to 6 segments = 918 GSM-7 characters or 402 Unicode characters). Each segment is billed separately.

How do I prevent abuse and spam using my SMS API?

Implement multiple security layers: (1) Require API key authentication (shown in Section 5), (2) Enable rate limiting to restrict requests per IP/user (10-100 requests per minute), (3) Validate phone numbers against allowlists or known patterns, (4) Monitor usage with logging and alerting, (5) Set spending limits in Vonage Dashboard to prevent unexpected charges, (6) Implement CAPTCHA for user-facing forms, (7) Add phone number verification (send confirmation code before allowing sends), (8) Block disposable/virtual numbers if needed.

What are the differences between Vonage Messages API and SMS API?

Vonage offers two SMS APIs: (1) SMS API (used in this tutorial) – Legacy, simpler API with straightforward REST endpoints, supports basic SMS sending and delivery receipts. (2) Messages API – Newer unified API supporting SMS, MMS, WhatsApp, Viber, Facebook Messenger, and more channels. Offers advanced features like message concatenation, Unicode support, and channel failover. For basic SMS needs, SMS API is sufficient and simpler. For multi-channel messaging, use Messages API.

How do I test SMS sending without spending money?

Vonage provides several testing options: (1) Use free credit from new account signup ($2-10 depending on promotion), (2) Test with Vonage virtual numbers in sandbox mode (check documentation), (3) Send messages to your own verified phone numbers only during development, (4) Use Vonage's test credentials if available for your account type, (5) Mock the Vonage SDK in unit tests to avoid actual API calls. Always set strict rate limits and spending alerts during development.