code examples
code examples
Send SMS with Node.js, Express, and Vonage
A guide on building a Node.js Express application to send SMS messages using the Vonage Messages API, covering setup, coding, error handling, and deployment.
This guide provides a complete walkthrough for building a Node.js Express application capable of sending SMS messages using the Vonage Messages API. We'll cover everything from project setup and configuration to implementing the core sending logic, handling errors, and deploying the application.
By the end of this tutorial, you will have a functional API endpoint that accepts a phone number and a message, sending an SMS via Vonage. This serves as a foundational building block for features like notifications, alerts, or two-factor authentication.
Project Overview and Goals
- Goal: Create a secure and reliable backend service to send SMS messages programmatically.
- Problem Solved: Enables applications to communicate with users via SMS for various purposes without needing manual intervention.
- Technologies:
- Node.js: A JavaScript runtime for building server-side applications.
- Express: A minimal and flexible Node.js web application framework for creating the API endpoint.
- Vonage Messages API: A versatile API for sending messages across various channels, including SMS. We use this for its robustness and multi-channel capabilities.
@vonage/server-sdk: The official Vonage Node.js library for interacting with Vonage APIs.dotenv: A module to load environment variables from a.envfile, keeping sensitive credentials out of the codebase.
- Architecture:
+-------------+ +---------------------+ +----------------+ +-----------------+ | HTTP Client | ----> | Node.js/Express API | ----> | Vonage SDK/API | ----> | SMS Recipient | | (e.g., curl)| | (/api/send-sms) | | (Messages API) | | (Mobile Phone) | +-------------+ +---------------------+ +----------------+ +-----------------+ | - Validate Request | | - Load Credentials | | - Call Vonage SDK | | - Return Response | +---------------------+ - Outcome: A simple Express application with a single POST endpoint (
/api/send-sms) that uses Vonage to send an SMS message. - Prerequisites:
- Node.js and npm (or yarn) installed. Download Node.js
- A Vonage API account. Sign up for Vonage
- A Vonage virtual phone number capable of sending SMS.
- Basic understanding of Node.js, Express, and REST APIs.
- (Optional but recommended) Vonage CLI installed (
npm install -g @vonage/cli). (Useful for tasks like managing Vonage numbers, applications, or checking account balance via the command line.) - (Optional)
ngrokfor testing webhooks if you extend functionality later. Download ngrok
1. Setting up the Project
Let's initialize our 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 Node.js Project: This command creates a
package.jsonfile to manage your project's dependencies and scripts.bashnpm init -y -
Install Dependencies: We need Express for the web server, the Vonage SDK to communicate with the API, and
dotenvto manage environment variables securely.bashnpm install express @vonage/server-sdk dotenv --saveexpress: Web framework.@vonage/server-sdk: Vonage API client library.dotenv: Loads environment variables from.env.
-
Create Project Structure: Create the main application file and a file for environment variables.
bashtouch index.js .env .gitignoreYour basic structure should look like this:
vonage-sms-sender/ node_modules/ .env .gitignore index.js package.json package-lock.json -
Configure
.gitignore: It's crucial to prevent sensitive information and unnecessary files from being committed to version control. Add the following lines to your.gitignorefile:Code# Dependencies node_modules/ # Environment variables .env # Logs logs/ *.log npm-debug.log* yarn-debug.log* yarn-error.log* # OS generated files .DS_Store Thumbs.db- Why
.env? This file will contain your secret API keys, private key content, and other configuration details. It must never be committed to Git.
- Why
2. Integrating with Vonage and Core Functionality
Now, let's configure Vonage and write the code to initialize the SDK and send an SMS.
-
Vonage Account Setup:
- If you haven't already, sign up for a Vonage API account.
- Navigate to your Vonage API Dashboard.
-
Create a Vonage Application: The Messages API typically uses Application ID and Private Key authentication for enhanced security.
- Go to ""Your applications"" in the Vonage Dashboard.
- Click ""+ Create a new application"".
- Give it a name (e.g., ""Node SMS Sender App"").
- Click ""Generate public and private key"". Important: This will automatically download a
private.keyfile. Save this file securely, as you will need its content. - Note the Application ID displayed on the page -> you'll need this.
- Enable the Messages capability. You'll see fields for ""Inbound URL"" and ""Status URL"". For sending only, these aren't strictly required, but Vonage might prompt you to fill them. You can enter placeholder URLs like
https://example.com/webhooks/inboundandhttps://example.com/webhooks/status. If you plan to receive messages or delivery receipts later, you'll need valid, publicly accessible URLs (potentially usingngrokfor local testing). - Click ""Generate new application"".
-
Link Your Vonage Number:
- Scroll down on the application details page to ""Link virtual numbers"".
- Find the Vonage virtual number you want to send SMS from and click ""Link"".
- Note: Ensure this number is SMS-capable in your region.
-
Set Messages API as Default (Crucial Check): Sometimes, accounts can be configured to use the older SMS API by default, which uses different authentication and webhook formats. Ensure the Messages API is the default for sending SMS.
- Go to your Vonage API Dashboard Settings.
- Under ""API keys"" -> ""Default SMS Setting"", ensure Messages API is selected. If not, change it and click ""Save changes"".
-
Configure Environment Variables: Open the
.envfile you created earlier. Copy the entire content of theprivate.keyfile you downloaded (including the-----BEGIN PRIVATE KEY-----and-----END PRIVATE KEY-----lines) and paste it as the value forVONAGE_PRIVATE_KEY_CONTENT. Add the other required variables:Code# Vonage Credentials (Messages API - Recommended) VONAGE_APPLICATION_ID=""YOUR_APPLICATION_ID"" # Paste the entire content of your private.key file below, ensuring newlines are preserved if needed by your OS/editor. # Example: VONAGE_PRIVATE_KEY_CONTENT=""-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"" # On some systems/shells, you might need to handle multi-line variables carefully or encode it. VONAGE_PRIVATE_KEY_CONTENT=""PASTE_YOUR_PRIVATE_KEY_CONTENT_HERE"" # Your Vonage virtual number (linked to the application) VONAGE_NUMBER=""YOUR_VONAGE_VIRTUAL_NUMBER"" # API Key & Secret (Optional for this tutorial's method) # VONAGE_API_KEY=""YOUR_API_KEY"" # VONAGE_API_SECRET=""YOUR_API_SECRET"" # Server Configuration PORT=3000VONAGE_APPLICATION_ID: The ID generated when you created the Vonage application.VONAGE_PRIVATE_KEY_CONTENT: The full text content of theprivate.keyfile. Ensure line breaks are handled correctly if pasting into certain environments.VONAGE_NUMBER: The Vonage virtual phone number (in E.164 format, e.g.,14155550100) linked to your application. This will be the ""from"" number.VONAGE_API_KEY/VONAGE_API_SECRET: Found at the top of your main Vonage Dashboard page. For the specific task of sending SMS via the Messages API using Application ID and Private Key authentication (as shown in this tutorial), the API Key and Secret are not strictly required and can be omitted from your.envfile. However, they might be needed if you use other Vonage APIs or SDK features that rely on key/secret authentication.PORT: The port your Express server will listen on.
-
Initialize Vonage SDK and Sending Logic: Open
index.jsand add the following code to load environment variables, initialize the Vonage SDK, and create a function to send SMS.javascript// index.js require('dotenv').config(); // Load environment variables from .env file const express = require('express'); const { Vonage } = require('@vonage/server-sdk'); // ---- Vonage Setup ---- // Ensure the private key content is loaded correctly, handling potential newline issues from .env const privateKeyContent = process.env.VONAGE_PRIVATE_KEY_CONTENT.replace(/\\n/g, '\n'); const vonage = new Vonage({ applicationId: process.env.VONAGE_APPLICATION_ID, privateKey: privateKeyContent // Use the key content directly from the environment variable }, { debug: false }); // Set debug: true for detailed SDK logging const vonageNumber = process.env.VONAGE_NUMBER; // ---- SMS Sending Function ---- async function sendSms(toNumber, messageText) { console.log(`Attempting to send SMS from ${vonageNumber} to ${toNumber}`); try { const resp = await vonage.messages.send({ message_type: ""text"", to: toNumber, // E.164 format recipient number (e.g., 14155550101) from: vonageNumber, // Your Vonage number linked to the application channel: ""sms"", text: messageText }); console.log(`SMS submitted successfully with Message UUID: ${resp.messageUuid}`); return { success: true, messageUuid: resp.messageUuid }; } catch (err) { console.error(""Error sending SMS:"", err); // Log the detailed error response if available if (err.response && err.response.data) { console.error(""Vonage Error Details:"", JSON.stringify(err.response.data, null, 2)); } // Rethrow or return a structured error throw new Error(`Failed to send SMS: ${err.message || 'Unknown error'}`); } } // ---- Express App Setup ---- (Continued in next section) // ... Express code will go here ...require('dotenv').config(): Loads the variables from.envintoprocess.env. Call this early.privateKeyContentprocessing: Added.replace(/\\n/g, '\n')to handle potential literal\ncharacters if the private key was pasted into.envas a single line with escaped newlines. Adjust if your method of storing the multi-line key in.envdiffers.new Vonage(...): Initializes the SDK using the Application ID and the content of the private key read directly from the environment variable.vonage.messages.send(...): The core method for sending messages via the Messages API.message_type: ""text"": Specifies a plain text SMS.to: Recipient number (must be in E.164 format).from: Your Vonage number.channel: ""sms"": Explicitly routes via SMS.text: The message content.
- Async/Await: Uses modern JavaScript promises for cleaner asynchronous code.
- Error Handling: Includes a
try...catchblock to handle potential errors during the API call and logs relevant information.
3. Building the API Layer
Let's create the Express server and the API endpoint to trigger the SMS sending function.
-
Set up Express Server: Add the following code to
index.jsbelow the Vonage setup andsendSmsfunction.javascript// index.js (continued) // ---- Express App Setup ---- const app = express(); const port = process.env.PORT || 3000; // Use port from .env or default to 3000 // Middleware app.use(express.json()); // Parse JSON request bodies app.use(express.urlencoded({ extended: true })); // Parse URL-encoded request bodies // ---- API Endpoint ---- app.post('/api/send-sms', async (req, res) => { const { to, message } = req.body; // Extract recipient number and message from request body // Basic Input Validation if (!to || !message) { console.warn('Validation Error: Missing "to" or "message" in request body'); return res.status(400).json({ success: false, error: 'Missing required fields: "to" (E.164 phone number) and "message".' }); } // Basic E.164 format check (adjust regex as needed for stricter validation) const phoneRegex = /^\+[1-9]\d{1,14}$/; if (!phoneRegex.test(to)) { console.warn(`Validation Error: Invalid phone number format for ${to}`); return res.status(400).json({ success: false, error: 'Invalid "to" phone number format. Use E.164 format (e.g., +14155550101).' }); } try { const result = await sendSms(to, message); console.log(`API call successful for sending SMS to ${to}`); res.status(200).json({ success: true, messageId: result.messageUuid }); } catch (error) { console.error(`API Error: Failed to process send SMS request for ${to}:`, error.message); // Send a generic server error message to the client res.status(500).json({ success: false, error: 'Failed to send SMS due to an internal server error.' }); } }); // ---- Simple Root Route ---- app.get('/', (req, res) => { res.send('Vonage SMS Sender API is running!'); }); // ---- Start Server ---- app.listen(port, () => { console.log(`Server listening on port ${port}`); console.log(`Vonage Application ID: ${process.env.VONAGE_APPLICATION_ID ? 'Loaded' : 'MISSING!'}`); console.log(`Vonage Private Key: ${process.env.VONAGE_PRIVATE_KEY_CONTENT ? 'Loaded' : 'MISSING!'}`); // Check if key content is loaded console.log(`Vonage Number: ${process.env.VONAGE_NUMBER ? process.env.VONAGE_NUMBER : 'MISSING!'}`); });- Middleware:
express.json()andexpress.urlencoded()parse incoming request bodies. - POST
/api/send-sms: Defines the endpoint. It expects a JSON body withtoandmessagefields. - Input Validation: Includes basic checks for the presence and format (simple E.164 regex) of the
tonumber and the presence of themessage. Returns a400 Bad Requestif validation fails. - Error Handling: Wraps the
sendSmscall in atry...catchblock. IfsendSmsthrows an error (e.g., Vonage API issues), it logs the error server-side and returns a generic500 Internal Server Errorto the client, preventing potential leakage of sensitive error details. - Success Response: On success, returns a
200 OKwith the VonagemessageUuid. - Server Start: Starts the Express server and logs confirmation, including checks for essential environment variables.
- Middleware:
4. Error Handling and Logging
We've implemented basic error handling, but let's refine it.
-
Consistent Strategy:
- Use
try...catchblocks for operations that can fail (API calls, potentially complex logic). - Log errors server-side with details (
console.error). Include context (e.g., recipient number, action being performed). - Return appropriate HTTP status codes (400 for client errors, 500 for server errors).
- Return user-friendly, non-sensitive error messages in API responses.
- Use
-
Logging:
- Current: Uses
console.logfor informational messages andconsole.errorfor errors. - Production Enhancement: Use a dedicated logging library (like
winstonorpino) for structured logging (JSON format), different log levels (debug, info, warn, error), and routing logs to files or external services (like Datadog, Splunk).
bash# Example: Install Winston npm install winstonjavascript// Example: Basic Winston setup (replace console logging) const winston = require('winston'); const logger = winston.createLogger({ level: 'info', // Log info and above format: winston.format.json(), transports: [ new winston.transports.Console({ format: winston.format.simple() }), // Add file transport for production // new winston.transports.File({ filename: 'error.log', level: 'error' }), // new winston.transports.File({ filename: 'combined.log' }), ], }); // Replace console.log with logger.info, console.warn with logger.warn, console.error with logger.error // Example: logger.error('Error sending SMS:', err); - Current: Uses
-
Retry Mechanisms:
- For transient network issues or temporary Vonage unavailability, implement retries with exponential backoff. Libraries like
async-retrycan simplify this. - Caution: Be careful not to retry errors caused by invalid input (e.g., bad phone number) or insufficient funds, as retrying won't help and may incur costs. Only retry potentially temporary issues (e.g., network timeouts, 5xx errors from Vonage).
bash# Example: Install async-retry npm install async-retryjavascript// Example: Wrap sendSms call with retry (in the API endpoint) const retry = require('async-retry'); app.post('/api/send-sms', async (req, res) => { // ... validation ... const { to, message } = req.body; // Ensure to and message are defined here try { const result = await retry(async bail => { // If Vonage returns certain errors (like 4xx), don't retry // Example: if (error.response && error.response.status >= 400 && error.response.status < 500) { // bail(new Error('Non-retryable Vonage error')); // bail stops retrying // return; // } return await sendSms(to, message); // Attempt to send }, { retries: 3, // Number of retries factor: 2, // Exponential backoff factor minTimeout: 1000, // Initial timeout onRetry: (error, attempt) => { // Replace console.warn with logger.warn if using Winston/Pino console.warn(`Retrying SMS send to ${to} (attempt ${attempt}) due to error: ${error.message}`); } }); // Replace console.log with logger.info if using Winston/Pino console.log(`API call successful for sending SMS to ${to}`); res.status(200).json({ success: true, messageId: result.messageUuid }); } catch (error) { // Replace console.error with logger.error if using Winston/Pino console.error(`API Error: Failed to process send SMS request for ${to} after retries:`, error.message); res.status(500).json({ success: false, error: 'Failed to send SMS due to an internal server error.' }); } }); - For transient network issues or temporary Vonage unavailability, implement retries with exponential backoff. Libraries like
5. Database Schema and Data Layer
For this basic SMS sending service, a database is not strictly required. However, if you wanted to log sent messages, track delivery status (requiring webhooks), or manage user data, you would add a database.
- If needed:
- Choose a database (e.g., PostgreSQL, MongoDB).
- Design a schema (e.g., a
messagestable withmessage_uuid,to_number,from_number,body,status,submitted_at,updated_at). - Use an ORM (like Prisma, Sequelize, Mongoose) or a query builder (like Knex.js) to interact with the database.
- Implement migrations to manage schema changes.
6. Security Features
Security is paramount, especially when dealing with APIs and external services.
- Input Validation and Sanitization:
- We implemented basic validation for
toandmessage. - Use robust validation libraries (like
joiorexpress-validator) for complex validation rules. - Sanitize input if it's ever stored or reflected back, to prevent XSS (though less relevant for an SMS API body unless storing/displaying).
- We implemented basic validation for
- Protecting Credentials:
- Use
.envfor all secrets (API keys, private key content, database URLs). - Ensure
.envis in.gitignore. - Use environment variables directly in deployment environments (do not commit
.envfiles). See Deployment section.
- Use
- Common Vulnerabilities:
- Rate Limiting: Protect against abuse and brute-force attempts. Use middleware like
express-rate-limit.bashnpm install express-rate-limitjavascript// index.js (add near the top middleware) 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' }); // Apply limiter specifically to the sensitive endpoint app.use('/api/send-sms', limiter); - Authentication/Authorization: Currently, the endpoint is open. In a real application, protect it with API keys, JWT tokens, or session authentication to ensure only authorized clients can send SMS.
- HTTPS: Always use HTTPS in production to encrypt data in transit. Deployment platforms often handle this, but ensure it's enforced.
- Dependency Updates: Regularly update dependencies (
npm audit,npm update) to patch known vulnerabilities.
- Rate Limiting: Protect against abuse and brute-force attempts. Use middleware like
7. Handling Special Cases
- Phone Number Formats: Strictly enforce E.164 format (
+followed by country code and number, no spaces or dashes) as required by Vonage. The validation regex can be improved for stricter checks based on country codes if needed. - Character Limits & Encoding: Standard SMS messages have character limits (160 for GSM-7, 70 for UCS-2/Unicode). Longer messages are split into multiple segments (concatenated SMS). Vonage handles segmentation, but be aware of potential costs for multi-part messages. Ensure message content doesn't contain characters incompatible with SMS if strict GSM-7 is needed, otherwise, Vonage will likely use UCS-2.
- Internationalization: The E.164 format handles international numbers. Ensure your Vonage account/number is enabled for sending to the target countries. Be mindful of international messaging costs and regulations (e.g., sender ID restrictions).
- Rate Limits (Vonage): Vonage applies its own rate limits (Messages Per Second). High-volume sending might require coordination with Vonage support or using specific high-throughput numbers. The SDK might return specific rate-limiting errors (often HTTP 429).
8. Performance Optimizations
For a simple service like this, performance bottlenecks are unlikely unless sending extremely high volumes.
- Async Operations: Node.js is inherently non-blocking. Using
async/awaitcorrectly ensures the server remains responsive while waiting for Vonage. - Connection Pooling (if using DB): Ensure your database client/ORM uses connection pooling.
- Caching: Not typically applicable for sending unique SMS messages. If retrieving reusable data (e.g., user preferences before sending), caching might apply.
- Load Testing: Use tools like
k6,Artillery, orApacheBench(ab) to simulate traffic and identify bottlenecks if high performance is critical. - Profiling: Use Node.js built-in profiler or tools like Clinic.js to analyze CPU usage and event loop delays under load.
9. Monitoring, Observability, and Analytics
Gaining insight into the service's health and behaviour is crucial.
- Health Checks: Add a simple endpoint (e.g.,
/health) that returns a 200 OK status if the server is running. Monitoring services can ping this.javascript// index.js (add before app.listen) app.get('/health', (req, res) => { res.status(200).send('OK'); }); - Metrics: Track key metrics:
- Request rate (requests per second/minute).
- Request duration (latency).
- Error rates (HTTP 4xx, 5xx).
- Vonage API call latency/errors.
- Node.js process metrics (CPU, memory, event loop lag).
- Use tools like Prometheus with
prom-clientor integrate with APM services (Datadog, New Relic).
- Error Tracking: Use services like Sentry or Bugsnag to capture, aggregate, and alert on application errors in real-time. They provide much more context than simple logging.
- Logging: As mentioned in Section 4, structured logging is essential for effective analysis and dashboarding in tools like Elasticsearch/Kibana (ELK stack), Datadog Logs, or Splunk.
- Vonage Dashboard: Utilize the Vonage Dashboard's analytics section to monitor SMS sending volumes, delivery rates (requires status webhooks), and costs.
10. Troubleshooting and Caveats
- Common Errors:
401 Unauthorized: Incorrect Application ID or private key content. Ensure theVONAGE_PRIVATE_KEY_CONTENTenvironment variable contains the exact, complete key content (including start/end markers and newlines handled correctly). Double-check the private key hasn't expired or been revoked. Ensure the Messages API is the default SMS setting in the Vonage Dashboard.Invalid 'to' number/Non-Whitelisted Destination: The recipient number format is incorrect (use E.164) or, if using a trial account, the recipient number must be added to the Vonage test numbers list (Dashboard -> Getting started -> Add test numbers).Invalid 'from' number/Illegal Sender Address: TheVONAGE_NUMBERin your.envis incorrect, not SMS-capable, or not linked to theVONAGE_APPLICATION_IDused for initialization.Delivery Failure - Generic/ Specific Carrier Error: May indicate issues with the recipient's carrier or number. Check Vonage logs for more details.Throughput capacity exceeded/429 Too Many Requests: Sending too many messages too quickly. Implement rate limiting on your side or contact Vonage for higher limits.- Private Key Format Error: If the SDK throws errors related to parsing the private key, ensure the
VONAGE_PRIVATE_KEY_CONTENTvariable contains the PEM format correctly, including the-----BEGIN PRIVATE KEY-----and-----END PRIVATE KEY-----lines and the base64 encoded content between them, with newlines preserved as needed. Check for extra characters or incorrect encoding. - TypeScript Compatibility: If adapting this guide for TypeScript, ensure you have the necessary
@typespackages installed (e.g.,@types/node,@types/express) and yourtsconfig.jsonis configured correctly. SDK or dependency updates might introduce type compatibility issues.
- Limitations:
- Trial Accounts: Limited funds and requirement to whitelist recipient numbers.
- Sender ID: May be overridden by carriers, especially internationally. Alphanumeric Sender IDs might require pre-registration.
- Delivery Receipts: Not implemented in this basic guide. Requires setting up a status webhook URL in the Vonage Application config and an endpoint in Express to receive POST requests from Vonage.
- Regional Regulations: Compliance with local laws (e.g., TCPA in the US, GDPR in Europe) regarding consent and opt-outs is the developer's responsibility.
11. Deployment and CI/CD
Deploying the application requires handling environment variables, especially the private key content, securely.
- Environment Configuration:
- DO NOT commit the
.envfile to Git. - Use the hosting platform's mechanism for setting environment variables (e.g., Heroku Config Vars, Vercel Environment Variables, AWS Systems Manager Parameter Store / Secrets Manager).
- Handling the Private Key: Store the entire content of the
private.keyfile in a secure environment variable (e.g.,VONAGE_PRIVATE_KEY_CONTENT) on your deployment platform. Ensure your platform handles multi-line environment variables correctly, or encode the key content if necessary (e.g., base64) and decode it in your application before passing it to the SDK (though direct pasting is often supported). Theindex.jscode already expects the key content directly fromprocess.env.VONAGE_PRIVATE_KEY_CONTENT.
- DO NOT commit the
- Deployment Platforms:
- PaaS (Heroku, Vercel, Render): Generally easier. Connect Git repository, configure environment variables (including the multi-line
VONAGE_PRIVATE_KEY_CONTENT) via dashboard/CLI, deploy. - IaaS (AWS EC2, Google Compute Engine): Requires setting up the server environment (Node.js runtime, process manager like
pm2), managing deployments (e.g., via SSH, Docker, CI/CD pipelines), securely setting environment variables, and configuring reverse proxies (like Nginx).
- PaaS (Heroku, Vercel, Render): Generally easier. Connect Git repository, configure environment variables (including the multi-line
- Process Manager: Use a process manager like
pm2to keep the Node.js application running, manage logs, and handle restarts.bashnpm install pm2 -g # Install globally or as dev dependency # Start app with pm2 pm2 start index.js --name vonage-sms-api - CI/CD Pipeline (e.g., GitHub Actions, GitLab CI, Jenkins):
- Automate testing, building (if needed), and deployment.
- Store secrets (like
VONAGE_APPLICATION_ID,VONAGE_NUMBER, andVONAGE_PRIVATE_KEY_CONTENT) securely within the CI/CD platform's secrets management system and inject them as environment variables during the deployment step. - Example steps: Checkout code -> Install dependencies -> Run tests -> Build (if applicable) -> Deploy to target environment (using platform CLI or other deployment tools).
- Rollback: Have a plan to revert to a previous stable version if a deployment introduces issues (e.g., redeploying the previous Git tag/commit, using platform rollback features).
12. Verification and Testing
Ensure the service works as expected.
-
Run Locally:
- Make sure your
.envfile is correctly populated with your Application ID, your Vonage number, and the full content of your private key. - Start the server:
bash
node index.js - You should see ""Server listening on port 3000"" and confirmation that environment variables are loaded.
- Make sure your
-
Test with cURL or Postman:
- Open a new terminal window (or use Postman).
- Send a POST request to your endpoint. Replace
+14155550101with a valid test number (whitelisted if on a trial account).
cURL Example:
bashcurl -X POST http://localhost:3000/api/send-sms \ -H ""Content-Type: application/json"" \ -d '{ ""to"": ""+14155550101"", ""message"": ""Hello from Node.js and Vonage! This is a test message."" }'Expected Success Response (JSON):
json{ ""success"": true, ""messageId"": ""aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"" }Expected Failure Response (e.g., missing field):
json{ ""success"": false, ""error"": ""Missing required fields: \""to\"" (E.164 phone number) and \""message\""."" } -
Check Phone: Verify that the SMS message is received on the target phone number.
-
Check Server Logs: Look at the terminal where
node index.jsis running. You should see logs indicating the attempt, success (with UUID), or any errors encountered. -
Check Vonage Dashboard: Log in to the Vonage Dashboard and check the logs/analytics section for records of the sent message and its status.
Frequently Asked Questions
how to send sms with node js and express
Use the Vonage Messages API with the @vonage/server-sdk library. Set up an Express.js server with a POST endpoint, initialize the Vonage SDK with your credentials, and call vonage.messages.send() with recipient number, sender number, and message text. Ensure E.164 formatting for phone numbers and proper private key handling.
what is vonage messages api used for
The Vonage Messages API enables sending messages programmatically over various channels, including SMS. It provides multi-channel capabilities and robust features for sending notifications, alerts, or implementing two-factor authentication.
why use dotenv in node js project
Dotenv keeps sensitive credentials like API keys and private keys out of your codebase. It loads environment variables from a .env file, enhancing security and simplifying configuration management.
when should I link vonage virtual number
Link a Vonage virtual number to your Vonage application before sending SMS messages. This number will be the "from" address for your outgoing SMS messages. Make sure this number is SMS-capable in your target region.
can I use api key and secret with messages api
While this tutorial uses Application ID and Private Key, the API Key and Secret are not strictly required for SMS via the Messages API. However, they are necessary for other Vonage APIs and some SDK features.
how to handle vonage private key securely
Store the entire content of your private.key file as the VONAGE_PRIVATE_KEY_CONTENT environment variable. Never commit the .env file to version control and use your deployment platform's secure environment variable storage for production.
what is E.164 phone number format
E.164 is an international standard for phone numbers, which includes a '+' followed by the country code and the subscriber number with no spaces or dashes. Example: +14155550100.
how to set up express server for sending sms
Install Express and create an app. Use middleware for JSON and URL-encoded body parsing (express.json(), express.urlencoded()). Define a POST route (e.g., /api/send-sms) that receives to and message data and calls the sendSms function.
why implement rate limiting for sms api
Rate limiting prevents abuse and protects your application and the Vonage API from excessive requests. Use middleware like express-rate-limit to restrict requests per IP or other criteria.
when to use a database for sms service
A database isn't strictly required for this basic SMS sending guide. However, it is essential for logging messages, tracking delivery status with webhooks, or managing user information.
how to check vonage sms delivery status
While not included in this basic guide, you'll need to set up status webhooks in your Vonage Application and implement a corresponding endpoint in your Express app to receive and store delivery receipts in a database.
what are common vonage api errors
401 Unauthorized indicates incorrect credentials, "Invalid 'to' number" often signals incorrect formatting or lack of whitelisting (for trial accounts), and 429 Too Many Requests indicates sending rate limits.
how to troubleshoot private key content errors
Ensure VONAGE_PRIVATE_KEY_CONTENT contains the *exact* key content (including "-----BEGIN..." and "-----END..." lines) and correct newline handling. Check for any extra characters or encoding issues in the .env file or environment variables.
how to deploy node js sms app to heroku
Connect your Git repository to Heroku. Set environment variables, including the multi-line private key content (VONAGE_PRIVATE_KEY_CONTENT), using the Heroku CLI or dashboard Config Vars section. Push your code to deploy.
how to test sms api locally with curl
Use a command like curl -X POST -H "Content-Type: application/json" -d '{"to": "+14155550101", "message": "Test message"}' http://localhost:3000/api/send-sms, replacing +14155550101 with a valid number.