Frequently Asked Questions
Use the Vonage Messages API and the @vonage/server-sdk, along with a Fastify POST route. The route should handle requests containing the recipient's number and the message text, then use the Vonage SDK to submit the SMS. Remember to handle errors and log responses appropriately for monitoring and debugging.
The Vonage Messages API is a versatile communication platform that enables you to send and receive messages through different channels, including SMS. It provides a unified approach for managing messages, allowing developers to integrate SMS functionality into their applications easily and reliably.
Fastify is a high-performance Node.js web framework known for its speed and developer-friendly features. It offers built-in validation, logging, and extensibility, making it a suitable choice for building robust and efficient SMS applications.
ngrok is crucial during local development for testing Vonage webhooks. Because webhooks require a public URL, ngrok provides a secure tunnel to your local server, enabling Vonage to communicate with your application during testing.
First, obtain API Key and Secret from your Vonage Dashboard. Buy a Vonage virtual number with SMS capability and link it to the application. Next, create a Vonage Application, download the private.key file, and enable the 'Messages' capability, configuring inbound and status URLs. Configure the Messages API as the default SMS API in the API settings of the dashboard.
The private.key file contains security credentials unique to your Vonage application. It is generated alongside a public key stored by Vonage during the Vonage Application setup and is used to authenticate and authorize access to Vonage APIs, particularly with the recommended method for the Messages API, which is the Application ID and private key.
Set up webhook routes in your Fastify application that correspond to the Inbound and Status URLs configured in your Vonage application. The inbound webhook receives incoming messages, and the status webhook receives delivery receipts (DLRs). Always acknowledge webhook receipts with a 200 OK response immediately.
Dotenv loads environment variables from a .env file into process.env. This is crucial for managing sensitive credentials (API keys, secrets) securely, keeping them out of your codebase and allowing for different configurations per environment.
In the inbound webhook handler, implement logic to detect keywords like 'STOP' or 'UNSUBSCRIBE' in the incoming message text. When an opt-out is detected, update your database to mark the sender's number as opted out to ensure compliance with regulations.
The E.164 format is an international standard for phone numbers. It ensures consistent formatting, including the '+' sign and country code, for example, +14155550100. Using E.164 is essential for reliable SMS delivery with Vonage.
Validating environment variables ensures that your application has all the necessary configurations to run correctly. By checking for required variables at startup, you prevent unexpected errors and ensure proper functionality.
Use ngrok to create a public URL that tunnels requests to your local server. Configure your Vonage application's inbound and status webhook URLs to point to your ngrok URL. Then, you can send SMS messages to your Vonage number and observe the webhook requests in your local development environment.
The provided /send-campaign endpoint demonstrates a simplified approach. However, for production systems, sending messages individually in a loop is highly inefficient. Consider using Promise.allSettled with rate limiting or a message queue (e.g., BullMQ, RabbitMQ) for background processing and improved performance.
Implement authentication mechanisms to protect your API routes. A simple method is to use API keys via request headers like 'x-api-key'. For more robust security, consider industry-standard methods like JWT (JSON Web Tokens).
Build a robust Node.js application using Fastify and the Vonage Messages API to send and receive SMS messages for marketing campaigns. This guide covers project setup, Vonage configuration, core features, error handling, security, and deployment.
You'll build a functional backend system capable of sending targeted SMS messages and processing inbound replies – the foundation of an SMS marketing platform. This guide prioritizes production readiness with secure configuration, comprehensive error handling, and deployment considerations.
Legal Compliance and Regulations
Before building SMS marketing campaigns, understand the legal requirements that govern commercial text messaging.
TCPA Compliance (US)
The Telephone Consumer Protection Act (TCPA), with updates effective April 11, 2025, requires:
International Regulations
10DLC Registration (US)
For US marketing campaigns using standard phone numbers:
Without 10DLC registration, carriers may filter or block your messages.
Use Cases and Business Value
SMS marketing campaigns deliver measurable results:
Common Use Cases:
Key Benefits:
Project Overview and Goals
What You're Building:
You are building a Node.js backend service using the Fastify framework. This service will:
Problem Solved:
This system provides the core infrastructure needed to programmatically send SMS messages (e.g., for marketing alerts, notifications, promotions) and handle potential replies from recipients, enabling two-way SMS communication within a larger application or marketing workflow.
Technologies Used:
@vonage/server-sdk: The official Vonage Node.js SDK (v3.24.1 as of January 2025) for easy integration with Vonage APIsdotenv: A module to load environment variables from a.envfile intoprocess.envngrok(for development): A tool to expose local servers to the internet, necessary for testing Vonage webhooksSystem Architecture:
Prerequisites:
Estimated Costs:
Vonage SMS pricing varies by country:
A marketing campaign to 10_000 recipients costs approximately $75 – $100 (US).
1. Setting Up the Project
Initialize your Node.js project and install the necessary dependencies.
Create Project Directory: Open your terminal and create a new directory for the project_ then navigate into it.
Initialize npm Project: This creates a
package.jsonfile to manage project dependencies and scripts.Install Dependencies: Install Fastify for the web server_ the Vonage SDK_ and
dotenvfor environment variables.Create Project Structure: Create directories and files for better maintainability.
src/server.js: Contains your Fastify application logic.env: Stores sensitive credentials and configuration (API keys_ phone numbers). Never commit this file to version control.gitignore: Specifies intentionally untracked files that Git should ignoreConfigure
.gitignore: Add the following lines to your.gitignorefile to prevent committing sensitive information and unnecessary files:Set up Environment Variables (
.env): Open the.envfile and add the following placeholders. Populate these values in the next section.2. Vonage Configuration
Before writing code_ configure your Vonage account and application.
Get API Key and Secret:
.envfile forVONAGE_API_KEYandVONAGE_API_SECRETBuy a Vonage Number: You need a virtual number capable of sending and receiving SMS.
Choosing the Right Number Type:
For marketing campaigns_ use a 10DLC-registered long code or toll-free number.
14155550100) and paste it into your.envfile forVONAGE_NUMBER10DLC Registration (Required for US Marketing):
After purchasing a US long code for marketing:
Create a Vonage Application: Vonage Applications act as containers for your communication configurations_ including webhooks and security keys.
private.key. Save this file securely in the root directory of your project (the same level aspackage.json). The path./private.keyin your.envfile assumes it's here. Vonage stores the public keyhttp://localhost:3000/webhooks/inbound(will be updated)http://localhost:3000/webhooks/status(will be updated).envfile forVONAGE_APPLICATION_IDSet Default SMS API (Important): Vonage has older and newer APIs. Ensure the Messages API is the default for SMS.
Set up ngrok and Update Webhook URLs: Webhooks allow Vonage to send data (like incoming messages) to your application. Since your app runs locally during development_
ngrokcreates a public URL that tunnels requests to your local machine.Open a new terminal window (keep the first one for running the app later)
Run ngrok_ telling it to forward to the port your Fastify app will run on (defined in
.envasPORT=3000)ngrok will display forwarding URLs (e.g._
https://randomstring.ngrok.io). Copy the HTTPS URL. This is yourDEV_WEBHOOK_BASE_URLPaste the HTTPS ngrok URL into your
.envfile forDEV_WEBHOOK_BASE_URL. Ensure it includeshttps://Go back to your Vonage Application settings (Applications → Your App Name → Edit)
Update the Messages capability URLs:
YOUR_NGROK_HTTPS_URL/webhooks/inbound(e.g._https://randomstring.ngrok.io/webhooks/inbound)YOUR_NGROK_HTTPS_URL/webhooks/status(e.g._https://randomstring.ngrok.io/webhooks/status)Click Save changes
Why HTTPS? Vonage requires secure HTTPS URLs for webhooks in production and it's best practice even in development. ngrok provides this automatically
Why Status URL? This webhook receives delivery receipts (DLRs) indicating if a message was successfully delivered to the handset. Essential for tracking campaign success
3. Implementing Core Functionality: Sending SMS
Write the code to initialize Fastify and the Vonage SDK_ and create an endpoint to send SMS messages.
File:
src/server.jsExplanation:
.envusingrequire('dotenv').config(). Validate that critical variables existprivate.keyusingpath.resolve. This makes path resolution more robust regardless of where you run the scriptlogger: trueto enable automatic request logging via Pino/healthRoute: A simple endpoint to check if the server is running/send-smsRoute (POST):to(string) andtext(non-empty string). If validation fails, Fastify automatically returns a 400 Bad Request errorrequest.log.info. Fastify injects the logger into the request objectvonage.messages.send(): This is the core SDK method. Specify:channel: 'sms'message_type: 'text'to: Recipient number from the request body. Must be in E.164 formatfrom: Your Vonage virtual number from.envtext: Message content from the request bodyasync/awaitmessage_uuid. Log success and send a 200 OK response with the UUIDtry...catchblock handles potential errors from the Vonage API (e.g., invalid number, insufficient funds). Log the error usingrequest.log.errorand return a 500 Internal Server Error with details from the Vonage error if available (error?.response?.data)startfunction listens on the configuredPORTand0.0.0.0(to be accessible outside localhost, e.g., by ngrok). It logs key configuration details on startupCommon Vonage API Error Codes:
Run the Application:
In your first terminal window (where you ran
npm install), start the server:You should see log output indicating the server is listening and showing your configuration. Keep this running.
4. Implementing Core Functionality: Receiving SMS (Webhooks)
Add the webhook endpoints configured in Vonage to handle incoming messages and status updates.
Add the following routes to
src/server.js(before the// --- Start Server ---section):Explanation:
/webhooks/inbound:request.log.info: Logs the entire incoming payload. Study this structure to see available fields (senderfrom, recipientto,text,message_uuid, etc.)reply.status(200).send();: This is CRITICAL. Vonage expects a quick confirmation (within a few seconds) that you received the webhook. If it doesn't get a 200 OK, it will retry sending, potentially multiple times. Send the response before doing any heavy processingMessage Status Values:
submitteddeliveredfailedrejectedundeliverableexpired/webhooks/status:statusfield (delivered,failed,submitted,rejected, etc.) andmessage_uuid. Use the UUID to correlate this status update with the message you sent earlier (likely stored in your database). Handlingfailedorrejectedstatuses is crucial for campaign analysis and potentially retryingDatabase Schema for Opt-Out Tracking:
Restart the Application:
Stop the running server (Ctrl+C) and restart it to load the new webhook routes:
Ensure your
ngroktunnel is still running in the other terminal window.5. Building a Complete API Layer
Refine the API for production-ready marketing campaigns.
Refining
/send-sms(Enhanced Validation):Enhance the schema validation in
src/server.js:SMS Message Segmentation and Costs:
Standard SMS messages are limited to 160 characters (GSM-7 encoding) or 70 characters (Unicode/UCS-2). The Vonage Messages API automatically splits longer messages into multiple segments and reassembles them on the recipient's device according to carrier specifications. Messages up to 1,600 characters are accepted, but will be billed as multiple message segments.
Message Length and Segment Calculation:
Cost Optimization Tips:
Adding a Production-Ready
/send-campaignEndpoint:Use a message queue for scalable campaign sending:
Vonage API Rate Limits:
Authentication (Production-Ready API Key):
Protect your API endpoints with API key authentication.
.env:src/server.jsbefore defining your protected routes:Note on Authentication: For high-security production environments, implement JWT tokens or OAuth2 instead of simple API keys. API keys in headers can be intercepted if not using HTTPS or if the key is exposed in client-side code.
API Endpoint Testing (cURL):
node src/server.jsterminal output for logs from the/webhooks/inboundhandler.node src/server.jsterminal output for logs from the/webhooks/statushandler showing the delivery status.6. Implementing Proper Error Handling, Logging, and Retry Mechanisms
Error Handling Strategy:
try...catchblocks around external calls (Vonage SDK){ "error": "message", "details": {...} })request.log.errorLogging:
Fastify's default logger (Pino) is production-ready. It logs requests, responses, and errors in JSON format, which integrates well with log aggregation tools (Datadog, Splunk, ELK).
request.log.info()for general flow,request.log.warn()for potential issues,request.log.error()for failuresmessage_uuid,tonumber,campaignId)Retry Mechanisms with p-retry:
Implement exponential backoff for transient failures:
Error Classification:
Monitoring and Alerting:
Set up alerts for:
Popular monitoring tools:
7. Security Best Practices
Webhook Signature Verification:
Verify that webhook requests actually come from Vonage:
Input Sanitization:
Prevent injection attacks:
Rate Limiting:
Protect against API abuse:
8. Database Integration
Store contacts, campaigns, and message history:
9. Deployment
Deploy your application to production:
Environment Setup:
Environment Variables: Set production environment variables in your hosting platform (Heroku, AWS, DigitalOcean, etc.):
Update Webhook URLs: In the Vonage Dashboard, update your application's webhook URLs to your production domain:
https://yourdomain.com/webhooks/inboundhttps://yourdomain.com/webhooks/statusHosting Options:
Docker Deployment:
Create
Dockerfile:Build and deploy:
Scaling Considerations:
10. Troubleshooting
Common Issues:
.envDebug Checklist:
Testing Webhooks Locally:
Use the Vonage CLI to forward webhooks:
11. Campaign Analytics and Metrics
Track campaign performance:
Key Metrics to Track:
12. Cost Optimization
Strategies to Reduce Costs:
Message Length Optimization:
Segment Management:
Send Time Optimization:
Carrier Selection:
Summary
You've built a production-ready SMS marketing campaign system with:
Next Steps: