code examples
code examples
Send SMS with Node.js, Express, and Vonage Messages API (2025 Guide)
Learn how to send SMS messages using Node.js, Express, and Vonage Messages API. Step-by-step tutorial with JWT authentication, error handling, security best practices, and production deployment strategies.
Send SMS with Node.js, Express, and Vonage: Complete Tutorial
What you'll build: A secure Node.js application with an Express API endpoint that sends SMS messages via the Vonage Messages API.
Time required: 45–60 minutes
Skill level: Intermediate (requires basic Node.js, Express, and REST API knowledge)
By the end of this tutorial, you'll have a production-ready Express API endpoint that accepts a recipient phone number and message text, then uses the Vonage Node.js SDK to send SMS messages programmatically. This tutorial covers how to send SMS notifications, alerts, and transactional messages using the Vonage API, complete with JWT authentication and error handling.
Project Overview and Goals
Goal: Create a secure and reliable Node.js SMS service that exposes a REST API endpoint to send SMS messages using the Vonage Messages API.
Technologies:
- Node.js: A JavaScript runtime for building server-side applications (minimum version: 18.x recommended).
- Express: A minimal and flexible Node.js web application framework used to create the API endpoint.
- Vonage Messages API: A unified messaging API for sending and receiving messages across multiple channels (SMS, MMS, WhatsApp). This tutorial focuses on SMS messaging functionality.
- Vonage Node.js SDK (
@vonage/server-sdk): Simplifies interaction with the Vonage APIs. dotenv: A module to load environment variables from a.envfile intoprocess.env.
Outcome: A functional Express application with a /send-sms endpoint capable of sending SMS messages when provided with a recipient number and text.
Prerequisites:
- Node.js 18.x or higher and npm (or yarn) installed. Download Node.js
- A Vonage API account. Sign up for free.
- A Vonage virtual phone number capable of sending SMS. Acquire one through the Vonage Dashboard.
- Basic understanding of Node.js, Express, and REST APIs.
- A tool for making HTTP requests (like
curl, Postman, or Insomnia).
Pricing: Vonage SMS pricing varies by destination country (typically $0.0075–$0.02 per SMS in the US). Check the Vonage SMS pricing page for your target regions. For comprehensive SMS cost comparisons, review Twilio SMS pricing and international SMS regulations.
System Architecture
The basic flow:
- A client (your frontend application, another service, or a testing tool like Postman) sends a POST request to your Express API endpoint (
/send-sms) with the recipient's phone number and message text. - The Express application receives the request, validates the input, and retrieves Vonage credentials (Application ID, Private Key, Vonage Number) from environment variables.
- The application uses the Vonage Node.js SDK to make an authenticated request to the Vonage Messages API, instructing it to send the SMS.
- The Vonage platform handles the delivery of the SMS message to the recipient's phone.
- Vonage sends a response back to your Express application (indicating success or failure), which then relays an appropriate response to the client.
sequenceDiagram
participant Client
participant ExpressApp as Node.js/Express API
participant VonageSDK as @vonage/server-sdk
participant VonageAPI as Vonage Messages API
participant Recipient
Client->>+ExpressApp: POST /send-sms (to, text)
ExpressApp->>+VonageSDK: Initialize (App ID, Private Key)
ExpressApp->>+VonageSDK: send({ channel: 'sms', message_type: 'text', to, from, text })
VonageSDK->>+VonageAPI: Send SMS Request
VonageAPI-->>-Recipient: Deliver SMS
VonageAPI-->>-VonageSDK: API Response (e.g., message_uuid)
VonageSDK-->>-ExpressApp: Return Promise (resolve/reject)
ExpressApp-->>-Client: API Response (Success/Error)1. Setting Up Your Node.js SMS Project
Initialize your Node.js project and install the necessary dependencies.
-
Create Project Directory: Open your terminal and create a new directory for your project, then navigate into it.
bashmkdir vonage-sms-sender cd vonage-sms-sender -
Initialize npm: Create a
package.jsonfile to manage your project's dependencies and scripts.bashnpm init -y -
Install Dependencies: Install Express, the Vonage Server SDK, and
dotenv.bashnpm install express @vonage/server-sdk dotenvexpress: Web framework for creating the API endpoint.@vonage/server-sdk: Official Vonage SDK for Node.js (handles authentication and API calls).dotenv: Loads environment variables from.envfiles (keeps credentials secure).
-
Create Project Structure: Create the main application file and files for managing sensitive credentials.
bashtouch index.js .env .gitignoreindex.js: Contains your Express application code..env: Stores your Vonage API credentials and configuration. Never commit this file to version control..gitignore: Specifies files Git should ignore.
-
Configure
.gitignore: Addnode_modulesand.envto prevent committing dependencies and sensitive credentials.Code# Dependencies node_modules/ # Environment variables .env # Vonage private key file (if stored in project) private.key -
Configure for ES Modules: Modify your
package.jsonto include a start script and specify ES Modules (required forimportsyntax inindex.js).Why ES Modules? They provide modern JavaScript syntax with
import/exportstatements. The alternative is CommonJS usingrequire(). We use ES Modules for cleaner, more maintainable code. If you need CommonJS, remove"type": "module"and convertimportstatements torequire().json{ "name": "vonage-sms-sender", "version": "1.0.0", "description": "Sends SMS using Node.js, Express, and Vonage", "main": "index.js", "type": "module", "scripts": { "start": "node index.js", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ "vonage", "sms", "express", "node" ], "license": "ISC", "dependencies": { "@vonage/server-sdk": "^3.12.1", "dotenv": "^16.4.5", "express": "^4.19.2" } }Start your server using
npm start.
Troubleshooting: If you encounter module errors during npm install, delete node_modules and package-lock.json, then run npm install again. The package-lock.json file ensures consistent dependency versions across installations.
2. Vonage API Integration and Authentication
To send SMS with the Vonage Messages API, you need to create a Vonage Application and configure JWT authentication credentials securely.
Authentication Method: Vonage Messages API uses JWT (JSON Web Token) authentication based on an Application ID and Private Key. This differs from older Vonage APIs that used API Key/Secret pairs. The SDK handles JWT generation automatically.
-
Create a Vonage Application:
- Log in to your Vonage API Dashboard.
- Navigate to "Applications" → "Create a new application".
- Give your application a name (e.g., "Node SMS Sender").
- Click "Generate public and private key". This downloads a
private.keyfile. Save this file securely. For this guide, save it in the root of your project directory (vonage-sms-sender/private.key). Addprivate.keyto your.gitignorefile. - Enable the "Messages" capability. Enter placeholder webhook URLs:
https://example.com/webhooks/inboundandhttps://example.com/webhooks/status. For sending SMS, these aren't immediately required, but Vonage requires them to be filled. If you later need to receive messages or delivery receipts, replace these with functional endpoints (usengrokfor local development). - Click "Generate new application".
- Copy your Application ID from the next screen.
-
Link Your Vonage Number:
- While viewing your newly created application details, go to the "Linked numbers" section.
- Find the Vonage virtual number you want to send SMS from and click "Link". If you don't have one, go to "Numbers" → "Buy numbers" to purchase one first.
-
Configure Environment Variables: Open the
.envfile you created earlier and add your Vonage credentials and number.Code# Vonage Credentials VONAGE_APPLICATION_ID=YOUR_APPLICATION_ID_HERE VONAGE_PRIVATE_KEY_PATH=./private.key VONAGE_VIRTUAL_NUMBER=YOUR_VONAGE_VIRTUAL_NUMBER_HERE # Server Configuration PORT=3000- Replace
YOUR_APPLICATION_ID_HEREwith the Application ID from the Vonage dashboard. - Ensure
VONAGE_PRIVATE_KEY_PATHpoints to the correct location of your downloadedprivate.keyfile relative toindex.js. - Replace
YOUR_VONAGE_VIRTUAL_NUMBER_HEREwith the Vonage phone number you linked to the application (use E.164 format, e.g.,14155550100). PORT=3000: Sets the port your Express server will listen on.
Security Note: The
.envfile and theprivate.keyfile contain sensitive credentials. Ensure they are never committed to your Git repository. Use environment variable management tools provided by your hosting platform for production deployments. For local development, providing the file path is convenient. For production deployments (see Section 12), you'll typically provide the content of the key via an environment variable. - Replace
3. Building the SMS Sending Endpoint
Write the Express code to initialize the Vonage Node.js SDK and create the /send-sms API endpoint for sending SMS messages.
// index.js
import express from 'express';
import { Vonage } from '@vonage/server-sdk';
import dotenv from 'dotenv';
// Load environment variables from .env file
dotenv.config();
// --- Configuration ---
const PORT = process.env.PORT || 3000;
const VONAGE_APPLICATION_ID = process.env.VONAGE_APPLICATION_ID;
const VONAGE_PRIVATE_KEY_PATH = process.env.VONAGE_PRIVATE_KEY_PATH;
const VONAGE_VIRTUAL_NUMBER = process.env.VONAGE_VIRTUAL_NUMBER;
// Validate required environment variables
if (!VONAGE_APPLICATION_ID || !VONAGE_PRIVATE_KEY_PATH || !VONAGE_VIRTUAL_NUMBER) {
console.error(`
-------------------------------------------------
ERROR: Missing required Vonage environment variables.
Check your .env file and ensure the following are set:
- VONAGE_APPLICATION_ID
- VONAGE_PRIVATE_KEY_PATH
- VONAGE_VIRTUAL_NUMBER
-------------------------------------------------
`);
process.exit(1);
}
// --- Initialize Vonage SDK ---
// The SDK uses the Application ID and Private Key for JWT authentication
// For production, load the key content directly from process.env.VONAGE_PRIVATE_KEY_CONTENT
const vonage = new Vonage({
applicationId: VONAGE_APPLICATION_ID,
privateKey: VONAGE_PRIVATE_KEY_PATH,
});
// --- Initialize Express App ---
const app = express();
// Middleware to parse JSON request bodies
app.use(express.json());
// --- API Endpoint to Send SMS ---
app.post('/send-sms', async (req, res) => {
console.log('Received request to /send-sms:', req.body);
// 1. Input Validation
const { to, text } = req.body;
if (!to || !text) {
console.error('Validation Error: Missing "to" or "text" in request body');
return res.status(400).json({
success: false,
message: 'Missing required fields: "to" (recipient phone number) and "text" (message content).',
});
}
// Basic E.164-like format check (allows '+' and digits, 7-15 digits long)
if (!/^\+?\d{7,15}$/.test(to)) {
console.error(`Validation Error: Invalid format for "to" number: ${to}`);
return res.status(400).json({
success: false,
message: 'Invalid format for "to" number. Use E.164 format (e.g., +14155550100) with 7-15 digits.',
});
}
// 2. Prepare Vonage API Request
const messageRequest = {
channel: 'sms',
message_type: 'text',
to: to,
from: VONAGE_VIRTUAL_NUMBER,
text: text,
};
// 3. Send SMS using Vonage SDK
try {
console.log('Attempting to send SMS via Vonage:', messageRequest);
const response = await vonage.messages.send(messageRequest);
console.log('Vonage API Success Response:', response);
res.status(200).json({
success: true,
message: 'SMS send request accepted by Vonage.',
message_uuid: response.message_uuid,
});
} catch (error) {
console.error('Vonage API Error:', error.response ? error.response.data : error.message);
let errorMessage = 'Failed to send SMS due to a server or Vonage API error.';
let statusCode = 500;
if (error.response && error.response.data) {
const { type, title, detail, invalid_parameters } = error.response.data;
errorMessage = `Vonage API Error: ${title || 'Unknown Error'} – ${detail || error.message}`;
if (invalid_parameters) {
errorMessage += ` Invalid parameters: ${JSON.stringify(invalid_parameters)}`;
statusCode = 400;
} else if (type && type.includes('authentication')) {
statusCode = 401;
} else {
statusCode = error.response.status || 500;
}
} else if (error.message.includes('authenticate')) {
errorMessage = 'Authentication failed. Check your Vonage Application ID and Private Key path.';
statusCode = 401;
}
res.status(statusCode).json({
success: false,
message: errorMessage,
errorDetails: error.response ? error.response.data : { code: error.code, message: error.message },
});
}
});
// --- Health Check Endpoint ---
app.get('/health', (req, res) => {
res.status(200).json({ status: 'UP', timestamp: new Date().toISOString() });
});
// --- Start Server ---
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
console.log(`Vonage App ID: ${VONAGE_APPLICATION_ID}`);
console.log(`Vonage Number: ${VONAGE_VIRTUAL_NUMBER}`);
console.log(`Private Key Path: ${VONAGE_PRIVATE_KEY_PATH}`);
console.log(`\nSend POST requests to http://localhost:${PORT}/send-sms`);
console.log(`Health check available at http://localhost:${PORT}/health`);
console.log(`\n--- ${new Date().toISOString()} ---`);
});Code Explanation:
- Imports: Import
express, theVonageclass from the SDK, anddotenv. - Configuration: Load environment variables using
dotenv.config()and store them in constants. Validate that critical Vonage variables are set. - Vonage SDK Initialization: Create an instance of the
Vonageclient, passing theapplicationIdandprivateKeypath. This configuration is specific to APIs like Messages that use JWT authentication based on application keys. The comment notes how this changes for production key handling. - Express Initialization: Create an Express app instance and use
express.json()middleware to parse incoming JSON request bodies. Middleware order matters – JSON parsing must occur before route handlers. /send-smsEndpoint (POST):- Defined as an
asyncfunction to useawaitfor the asynchronousvonage.messages.sendcall. - Input Validation: Checks if
toandtextproperties exist inreq.body. Includes a basic E.164-like format check for thetonumber using a regular expression. Returns400 Bad Requestif validation fails. - Prepare Request: Constructs the payload object required by
vonage.messages.sendfor an SMS message, using the validated input and the Vonage number from.env. - Send SMS: Calls
vonage.messages.send(messageRequest)within atry...catchblock. - Success Handling: If the promise resolves, Vonage accepted the request. Log the response (which contains the
message_uuid) and send a200 OKresponse to the client. - Error Handling: If the promise rejects, the
catchblock executes. Log the detailed error (checking forerror.response.datawhich often contains specific Vonage error details). Provide an informative error message and status code (e.g., 400 for invalid parameters, 401 for auth issues, 500 for generic errors) to the client.
- Defined as an
/healthEndpoint (GET): A simple endpoint to verify the server is running.- Start Server:
app.listenstarts the Express server on the configuredPORT.
4. API Security and Validation Best Practices
The /send-sms endpoint works but needs additional security and validation for production SMS applications:
Authentication/Authorization: For a production API, protect this endpoint. Common methods include:
- API Keys: Require clients to send a secret API key in a header (e.g.,
X-API-Key). Validate this key using middleware. - JWT (JSON Web Tokens): Implement user authentication and require a valid JWT for accessing the endpoint.
- IP Whitelisting: Restrict access to specific IP addresses if applicable.
Implementing full authentication is beyond this basic guide, but is crucial for production.
Request Validation: The current validation is basic. Use a dedicated validation library like Joi or express-validator for more robust checks:
| Validation Type | Purpose | Example |
|---|---|---|
| Phone number format | Stricter E.164 validation | Check country code validity |
| Message length | Enforce character limits | Limit to 1,600 characters |
| Content filtering | Prevent prohibited content | Block spam keywords |
| Rate limiting | Prevent abuse | Limit requests per IP |
// Example using basic checks (expand with a library for production)
if (text.length > 1600) {
return res.status(400).json({
success: false,
message: 'Message text exceeds maximum length of 1,600 characters.'
});
}API Documentation: Use tools like Swagger/OpenAPI to document your endpoint, including request/response formats and authentication requirements.
5. SMS Error Handling and Retry Strategies
Consistent Error Strategy: We've implemented basic try...catch and return structured JSON errors. Standardize error responses across your API.
Logging: The current console.log and console.error are suitable for development. For production, use a dedicated logging library (like Winston or Pino) to:
- Log to files or external logging services (e.g., Datadog, Loggly).
- Control log levels (info, warn, error, debug).
- Include timestamps and request context in logs.
Retry Mechanisms: Network issues or temporary Vonage problems might cause requests to fail.
- Client-Side Retries: The client calling your
/send-smsendpoint can implement retries with exponential backoff. - Server-Side Retries (Caution): Implementing retries within your
/send-smsendpoint for Vonage calls can be risky – you might accidentally send duplicate messages if the initial request succeeded but the response failed. It's generally safer to rely on Vonage's internal retries and potentially implement an idempotent design (e.g., using a unique request ID provided by the client) if you need server-side retries.
6. Database Schema and Data Layer
For this specific task of only sending an SMS via an API call, a database is not required. If you were building features like tracking message history, managing user preferences, or queuing messages, you would need a database (e.g., PostgreSQL, MongoDB) with appropriate schemas and data access patterns (like using an ORM like Prisma or Sequelize).
7. Security Features
Input Validation: Already mentioned – crucial to prevent malformed requests and potential vulnerabilities. Sanitize input if incorporating it into dynamic responses or logs elsewhere.
API Key Security: Protect your Vonage credentials (.env, private.key) rigorously. Use environment variables in deployment, not hardcoded values.
Rate Limiting: Protect your API (and your Vonage account balance) from abuse or accidental loops by implementing rate limiting:
npm install express-rate-limit// index.js (add near the top)
import rateLimit from 'express-rate-limit';
// ... (after app initialization)
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',
standardHeaders: true,
legacyHeaders: false,
});
// Apply the rate limiting middleware to /send-sms
app.use('/send-sms', limiter);HTTPS: Always use HTTPS for your API in production to encrypt data in transit. Use a reverse proxy like Nginx or Caddy, or hosting platform features (like Heroku, Vercel) to handle SSL termination.
Helmet: Use the helmet middleware for Express to set various security-related HTTP headers:
npm install helmet// index.js
import helmet from 'helmet';
// ...
app.use(helmet());
// ...8. Handling Special Cases (SMS Specific)
| Feature | Details | Considerations |
|---|---|---|
| Character Encoding & Limits | SMS messages have 160-character limit for GSM-7, 70 characters for UCS-2 (Unicode, emojis) | Longer messages split into segments, billed separately |
| International Numbers | Use E.164 format (e.g., +447700900000, +14155550100) | Ensure your Vonage account is enabled for target countries |
| Sender ID | Typically your Vonage virtual number | Some countries support Alphanumeric Sender IDs (requires pre-registration) |
| Restricted Content | Carriers filter messages with certain keywords | Avoid spam-related content |
9. Performance Optimizations
For a simple endpoint like this, complex optimizations are usually unnecessary.
- Async Operations: Node.js is inherently non-blocking. Using
async/awaitensures your server isn't blocked while waiting for the Vonage API response. - Load Testing: For high-throughput scenarios, use tools like
k6,Artillery, orApacheBenchto test how many requests per second your endpoint can handle. Monitor CPU/Memory usage. - Caching: Not directly applicable for sending unique SMS messages.
10. Monitoring, Observability, and Analytics
- Health Checks: The
/healthendpoint is a basic health check. Monitoring services (like UptimeRobot, Pingdom, or AWS CloudWatch) can ping this endpoint to ensure your service is running. - Logging: Centralized logging (as mentioned before) is key for observability.
- Error Tracking: Use services like Sentry or Bugsnag to automatically capture and report errors that occur in your application.
- Vonage Dashboard: Monitor SMS delivery status, usage, and costs directly in the Vonage API Dashboard under "Logs" > "Messages API logs".
- Metrics: Track metrics like request latency, error rates (4xx, 5xx), and the number of SMS sent. Tools like Prometheus/Grafana or Datadog APM can help.
11. Troubleshooting and Caveats
Common Issues:
| Issue | Cause | Solution |
|---|---|---|
| "Non-Whitelisted Destination" error | Trial account restrictions | Whitelist recipient numbers in Vonage Dashboard or add payment details to upgrade |
| Authentication failed | Incorrect credentials | Verify VONAGE_APPLICATION_ID, VONAGE_PRIVATE_KEY_PATH, and file content |
Invalid from number | Number not linked or wrong format | Ensure number is linked to application and uses E.164 format |
Invalid to number | Wrong format or unsupported | Use E.164 format, verify country support |
| Firewall issues | Blocked outbound HTTPS | Allow connections to *.vonage.com or *.nexmo.com on port 443 |
| Private key permissions | File not readable | Ensure Node.js process has read permissions for private.key |
Port conflict (EADDRINUSE) | Port already in use | Stop other application or change PORT in .env |
| ES Module errors | Missing "type": "module" | Add to package.json or convert to CommonJS using require() |
Detailed Solutions:
- Trial Account Limitations: Most common issue. New Vonage accounts operate in trial/demo mode. You must whitelist recipient phone numbers in the Vonage Dashboard (usually under Account Settings or a dedicated "Test Numbers" section) before you can send SMS. Upgrade your account by adding payment details to remove this restriction.
- SDK/API Errors: Check the
errorDetailsin the JSON response from your API for specific error messages from Vonage (e.g., "Invalid Credentials," "Parameter missing," "Throughput capacity exceeded"). Consult the Vonage API Error Codes documentation.
12. Deployment and CI/CD
Environment Configuration: Do not deploy your .env file or private.key directly. Use your hosting provider's mechanism for setting environment variables securely (e.g., Heroku Config Vars, AWS Parameter Store/Secrets Manager, Docker secrets).
Private Key Handling in Production: The current code reads the key from a file path (VONAGE_PRIVATE_KEY_PATH). For production, provide the content of the private key via a secure environment variable (e.g., VONAGE_PRIVATE_KEY_CONTENT). Adapt the Vonage SDK initialization in index.js:
// Example adaptation for reading key content from env var
const vonage = new Vonage({
applicationId: process.env.VONAGE_APPLICATION_ID,
privateKey: process.env.VONAGE_PRIVATE_KEY_CONTENT
});Platform Choice: Deploy to platforms like:
- Heroku: Simple deployment with Config Vars for environment variables
- Vercel: Serverless deployment for Node.js applications
- AWS: EC2, Lambda, Fargate, or Elastic Beanstalk
- Google Cloud: App Engine or Cloud Run
- Azure: App Service
- Docker: Containerize for any platform
CI/CD Pipeline: Set up a pipeline (e.g., GitHub Actions, GitLab CI, Jenkins) to automate:
- Running linters/formatters (
eslint,prettier) - Running tests (Unit, Integration)
- Building the application (if necessary, e.g., for TypeScript)
- Deploying to staging/production environments with correct environment variables
Process Management: Use a process manager like pm2 in production to keep your Node.js application running, handle restarts on crashes, and manage logs.
13. Testing Your SMS API
-
Start the Server:
bashnpm startYou should see output indicating the server is running on the configured port (default 3000).
-
Manual Verification (using
curl): Open another terminal window. Run the followingcurlcommand, replacing the placeholder value:bashcurl -X POST \ http://localhost:3000/send-sms \ -H 'Content-Type: application/json' \ -d '{ "to": "YOUR_PERSONAL_PHONE_NUMBER", "text": "Hello from Node.js and Vonage! Sent at: '"$(date)"'" }'Replace:
YOUR_PERSONAL_PHONE_NUMBERwith your actual mobile number (use E.164 format like+14155550123). Ensure this number is whitelisted in your Vonage dashboard if using a trial account.- Verify
http://localhost:3000matches your server's host and port if you changed the defaultPORTin.env.
-
Check Expected Output:
- Terminal (curl): You should receive a JSON response like:
Or an error response if something went wrong:json
{ "success": true, "message": "SMS send request accepted by Vonage.", "message_uuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" }json{ "success": false, "message": "Vonage API Error: Authentication Failed – Invalid Credentials…", "errorDetails": { /* ... Vonage error object ... */ } } - Terminal (Server Logs): Check the logs where
npm startis running. You should see the incoming request, the attempt to send, and the success or error details logged. - Your Phone: You should receive the SMS message shortly after a successful API response.
- Vonage Dashboard: Check the Messages API logs in the Vonage dashboard to see the record of the sent message and its status.
- Terminal (curl): You should receive a JSON response like:
-
Test Edge Cases:
- Send without
toortextfield → Expect 400 Bad Request - Send with an invalid
tonumber format (e.g.,123,abc) → Expect 400 Bad Request - Temporarily invalidate credentials in
.env→ Expect 401/500 error - Send a very long message → Verify segmentation handling
- Send without
-
Automated Testing (Conceptual):
- Unit Tests: Use frameworks like Jest or Mocha/Chai to test individual functions/modules in isolation. Mock the Vonage SDK (
@vonage/server-sdk) to avoid making actual API calls during unit tests. Test input validation logic. - Integration Tests: Use tools like
supertestto make actual HTTP requests to your running application (potentially mocking the Vonage SDK call at the boundary) to test the endpoint logic, request/response flow, and middleware.
- Unit Tests: Use frameworks like Jest or Mocha/Chai to test individual functions/modules in isolation. Mock the Vonage SDK (
Frequently Asked Questions
What is the Vonage Messages API and how does it work?
The Vonage Messages API is a unified messaging platform that allows you to send and receive messages across multiple channels including SMS, MMS, WhatsApp, Viber, and Facebook Messenger. This tutorial focuses specifically on SMS messaging using the API.
How do I get Vonage API credentials for SMS?
Sign up for a free Vonage API account at dashboard.nexmo.com. Create a Vonage Application in the dashboard, enable the Messages capability, and generate your Application ID and private key. These credentials authenticate your API requests.
What is E.164 phone number format?
E.164 is the international telephone numbering standard. Format: +[country code][subscriber number]. Examples: +14155550100 (US), +447700900000 (UK). Always use E.164 format for the to and from fields when sending SMS via Vonage.
How do I handle SMS delivery failures and errors?
Implement robust error handling using try-catch blocks. Check the error.response.data object for Vonage-specific error details. Common failures include invalid credentials (401), invalid phone numbers (400), or rate limits exceeded. Use the message UUID returned on success to track delivery status via webhooks or the Vonage Dashboard.
What are the SMS character limits?
Standard SMS supports 160 characters for GSM-7 encoding (Latin characters). Messages using UCS-2 encoding (Unicode, emojis, non-Latin characters) are limited to 70 characters. Longer messages are automatically split into multiple segments, each billed separately. The Vonage API handles segmentation automatically.
Can I send SMS to international phone numbers with Vonage?
Yes, Vonage supports international SMS to 200+ countries. Ensure your Vonage account has international SMS enabled, use E.164 format for recipient numbers, and verify the destination country is supported. Pricing varies by country – check the Vonage pricing page for rates.
How do I secure my Vonage API keys and private keys?
Never commit .env files or private.key files to version control. Use environment variables for production deployments (Heroku Config Vars, AWS Secrets Manager, etc.). Implement rate limiting to prevent API abuse. Use HTTPS for all API communications. Consider IP whitelisting for additional security.
What's the difference between Vonage and Nexmo?
Vonage acquired Nexmo in 2016. The Vonage API is the rebranded Nexmo API. You'll still see "Nexmo" references in legacy documentation and URLs (like dashboard.nexmo.com), but the APIs and SDKs now use the Vonage brand name.
How do I handle trial account limitations?
New Vonage accounts operate in trial mode with restrictions. Whitelist recipient phone numbers in your Vonage Dashboard (Account Settings or Test Numbers section) before sending SMS. Errors like "Non-Whitelisted Destination" indicate this restriction. Add payment details to your account to remove trial limitations and send to any number.
Can I schedule SMS messages for later delivery with Vonage?
The Vonage Messages API doesn't directly support scheduled sending. Implement scheduling on your application side using cron jobs, task schedulers (like node-cron, Bull queue), or serverless functions with scheduled triggers (AWS Lambda with EventBridge, Google Cloud Scheduler) to call your /send-sms endpoint at the desired time.
Summary
You've built a complete Node.js Express application for sending SMS messages via Vonage's Messages API. This implementation includes:
- Secure authentication using Vonage Application ID and private key
- Input validation with E.164 format checking
- Comprehensive error handling for API failures and edge cases
- Security best practices including environment variable management, rate limiting, and HTTPS recommendations
- Production-ready features like health checks, logging guidance, and deployment strategies
Next Steps:
The application is ready for deployment and can be extended with features like:
- Webhook handlers for delivery receipts
- Message queuing for bulk sending
- Database integration for message history
- Multi-channel messaging (MMS, WhatsApp)
- Two-factor authentication (2FA) workflows
For additional resources, consult the Vonage API Documentation and the @vonage/server-sdk repository.