Frequently Asked Questions
Use Node.js with Express and the Vonage Messages API to create a bulk SMS system. This involves setting up an API endpoint that accepts a list of numbers and a message, then uses the Vonage SDK to send the messages. Ensure proper rate limiting and error handling for reliability.
The Vonage Messages API is a unified API that allows you to send messages through different channels, including SMS. It's preferred over the older SMS API due to its modern design, wider channel support, and detailed status updates via webhooks.
Dotenv is a module used to load environment variables from a .env file. This helps keep sensitive information like Vonage API keys and secrets separate from your codebase, improving security.
Ngrok is used during development to create a publicly accessible URL for your local server. This allows Vonage to send webhooks to your application for testing purposes. In production, you'd use your actual server URL.
While the Vonage SMS API can still be used, the Messages API is recommended due to its versatility and features. The Messages API supports multiple communication channels and provides detailed status tracking through webhooks.
Vonage has rate limits to prevent abuse. A basic approach involves implementing delays between sending messages. However, more robust solutions are needed for production applications. Check Vonage documentation for your number type and registration status.
The status webhook provides updates on the delivery status of your messages. This allows real-time tracking. You must configure a status URL in your Vonage Application settings and implement a handler in your application.
You can install the Vonage Server SDK for Node.js using npm or yarn: 'npm install @vonage/server-sdk'. This gives you access to convenient methods for interacting with Vonage APIs.
The private key, along with your application ID, is essential for authenticating with the Vonage Messages API. This ensures secure communication and access to your account.
In the Vonage dashboard, create a new application, generate public and private keys (saving the private key securely), enable the 'Messages' capability, and link a Vonage virtual number. Set the inbound and status webhook URLs to your application endpoints.
Use try-catch blocks around API calls and webhook processing, validate input data, and log all relevant events and errors. Consider implementing retry mechanisms for transient errors and use robust logging libraries in production.
While basic regex is possible, use a library like 'libphonenumber-js' for robust validation, especially to ensure compliance with international number formats (E.164). This prevents invalid number submissions.
A database is recommended to track broadcast jobs, individual message statuses, and manage recipients effectively. This enables reporting, monitoring delivery statistics, and retrying failed messages if necessary.
The JSON payload should include two main fields: 'recipients', an array of phone numbers in E.164 format, and 'message', a string containing the text to send. Ensure correct number formatting.
Build a Bulk SMS Broadcast System with Vonage Messages API, Node.js, and Express
This guide provides a step-by-step walkthrough for building a robust bulk SMS broadcasting system using Node.js, Express, and the Vonage Messages API. You'll cover everything from project setup and core Vonage integration to essential production considerations like rate limiting, error handling, security, and deployment.
By the end of this guide, you'll have a functional Node.js application capable of sending SMS messages to a list of recipients via an API endpoint, incorporating best practices for reliability and scalability.
Project Overview and Goals
What You're Building:
You'll construct a Node.js application using the Express framework that exposes an API endpoint. This endpoint accepts a list of phone numbers and a message text, then uses the Vonage Messages API to broadcast the SMS message to all specified recipients efficiently and reliably.
Problem Solved:
This system addresses the need to send the same SMS message to multiple recipients simultaneously (e.g., notifications, alerts, marketing campaigns) while managing API rate limits, tracking message status, and ensuring secure handling of credentials.
Technologies Used:
dotenv: A zero-dependency module that loads environment variables from a.envfile intoprocess.env. Latest version: 17.2.3 (January 2025). Note: For Node.js v20.6.0+, native.envsupport via--env-fileflag is available. dotenv is suitable for development but not recommended for production secrets – use secrets managers like Infisical, AWS Secrets Manager, or similar.@vonage/server-sdk: The official Vonage Server SDK for Node.js (v3.24.1 as of January 2025), simplifying interaction with Vonage APIs.ngrok(for development): A tool to expose local servers to the internet, necessary for testing Vonage webhooks. Provides secure HTTPS tunneling, webhook inspection, and replay capabilities.System Architecture:
(A diagram illustrating the system architecture would typically be placed here, showing client, Node.js app, Vonage API, Mobile Network, and Recipient interactions, including the webhook flow.)
Prerequisites:
ngrokinstalled for local webhook testing (Download here).npx @vonage/cli [...]or install globally (npm install -g @vonage/cli), which may require administrator privileges.Final Outcome:
A Node.js Express application with:
/broadcast) to trigger bulk SMS sends.How Do You Set Up Your Node.js Project for Bulk SMS?
Initialize your Node.js project and install the necessary dependencies.
Step 1: Create Project Directory
Open your terminal and create a new directory for the project, then navigate into it.
Step 2: Initialize Node.js Project
Initialize the project using npm (or yarn). This creates a
package.jsonfile. The-yflag accepts the default settings.Step 3: Install Dependencies
Install Express for the web server, the Vonage Server SDK, and
dotenvfor environment variables. Version constraints ensure compatibility.Note on Express v5: Express v5 includes breaking changes from v4, including removal of deprecated methods and updated path-to-regexp@8.x for security (ReDoS mitigation). If migrating from Express v4, review the Express v5 migration guide.
Step 4: Set Up Project Structure
Create the basic files and folders for your application.
Your basic structure should look like this:
Step 5: Configure
.gitignoreAdd
node_modulesand.envto your.gitignorefile to prevent committing sensitive information and dependencies to version control.Step 6: Configure Environment Variables (
.env)Create a
.envfile in the root of your project. This file stores your Vonage credentials and other configuration securely. Fill in the actual values later.Security Note: dotenv is suitable for local development only. For production environments, use dedicated secrets management solutions (AWS Secrets Manager, Infisical, HashiCorp Vault, etc.) to avoid storing plaintext secrets in environment files. Over 1 million secrets from 58,000+ websites have been exposed through leaked .env files (Source: Security research, 2024).
Why This Setup?
npm init: Standard way to start a Node.js project, managing dependencies and scripts.@vonage/server-sdksimplifies Vonage interaction;dotenvis crucial for securely managing API keys outside of code..gitignore: Prevents accidental exposure of secrets (.env) and unnecessary bloat (node_modules) in Git..env: Isolates configuration and secrets from the codebase, making it easier to manage different environments (development, production) and enhancing security.How Do You Initialize the Vonage SDK and Send SMS?
Now, integrate the Vonage SDK and implement the logic to send SMS messages.
Step 1: Initialize Express and Vonage SDK
Open
index.jsand set up the basic Express server and initialize the Vonage SDK using the environment variables.require('dotenv').config();: Must be called early to load variables.express.json()/express.urlencoded(): Necessary middleware to parse incoming request bodies.Vonageclass from the SDK, providing credentials and the content of the private key file read usingfs.readFileSync. Using the Messages API requires an Application ID and Private Key for authentication.Step 2: Implement Single SMS Sending Function
Create a reusable function to send a single SMS message. This helps structure the code. (This version includes enhanced logging).
vonage.messages.send: The core method from the SDK for the Messages API.message_type,text,to,from, andchannelare required for SMS.async/await: Used for cleaner handling of the asynchronous API call.messageUuidfor tracking anderrorCodeon failure.Step 3: Implement Basic Rate Limiting (Delay)
Vonage imposes rate limits. The base limit is 30 API requests per second for all API keys. However, actual SMS throughput depends heavily on:
Critical: Exceeding your allowed rate will result in HTTP 429 errors and message blocking/queueing. The simple delay approach below is a basic starting point for low-volume testing only. Production systems must implement proper rate limiting based on your specific 10DLC campaign throughput.
(Source: Vonage API Support - "10 DLC Throughput Limits" and "What is the Throughput Limit for Outbound SMS?", January 2025)
Why this approach?
sendSmsfunction makes the code cleaner and reusable.sleepfunction provides a basic mechanism to avoid hitting simple per-second limits. Crucially, this is an oversimplification. Production systems sending moderate to high volume, especially in regulated markets like the US (A2P 10DLC), must account for specific throughput limits tied to number types and 10DLC campaign registration. A simple fixed delay is often inadequate. Consider concurrent sending within verified limits (see Section 5/6) or a background job queue for better management.How Do You Create a Bulk SMS Broadcast API Endpoint?
Create the
/broadcastendpoint to trigger the bulk sending process.Step 1: Define the
/broadcastRouteAdd a POST route in
index.jsthat accepts a list of numbers and a message.recipientsandmessage. Includes a very basic regex for phone numbers with a strong recommendation to use a proper library likelibphonenumber-jsfor production.recipientsarray.await sendSms(...): Calls our SMS sending function for each recipient.await sleep(...): Pauses execution between each send attempt, subject to the caveats mentioned earlier.200 OKstatus after attempting all submissions in the loop. Includes a summary and detailed results of the submission attempts.Step 2: Testing the Endpoint (Example using
curl)Make sure your server is running (
node index.js). Open another terminal and run the following command (replaceYOUR_TEST_PHONE_NUMBER_...with actual E.164 formatted numbers):Expected JSON Response (example):
(The actual
success,messageUuid,recipient, anderrorCodevalues will reflect the outcome of the submission attempts.)You should also see logs in your server console and receive the SMS messages on the test phones (after the specified delay).
How Do You Set Up Vonage Webhooks for SMS Delivery Status?
Proper configuration in the Vonage Dashboard and setting up webhooks are crucial for the Messages API.
Step 1: Obtain Vonage Credentials
.envfile.Step 2: Create a Vonage Application
The Messages API requires an Application to handle authentication (via private key) and webhooks.
private.keyfile that downloads. Place this file in your project's root directory (or updateVONAGE_PRIVATE_KEY_PATHin.envif you save it elsewhere). The public key is stored by Vonage.YOUR_NGROK_URLpart in Step 4):YOUR_NGROK_URL/webhooks/inbound.YOUR_NGROK_URL/webhooks/status..envfile.Step 3: Link a Vonage Number
FROMnumber.VONAGE_FROM_NUMBERfield in your.envfile (use E.164 format, e.g.,14155550100).Step 4: Set up
ngrokfor Local Webhook TestingVonage needs a publicly accessible URL to send webhooks.
ngrokcreates a secure tunnel to your local machine.ngrok(replace3000if your app uses a different port):ngrokwill display forwarding URLs (e.g.,https://random-subdomain.ngrok-free.app). Copy thehttpsURL. This isYOUR_NGROK_URL.YOUR_NGROK_URL/webhooks/inboundYOUR_NGROK_URL/webhooks/status.env: SetBASE_URL=YOUR_NGROK_URLin your.envfile. This helps keep track of the currently activengrokURL.node index.jsStep 5: Implement Webhook Handlers
Add routes in
index.jsto receive POST requests from Vonage at the URLs you configured./webhooks/status: Logs the received status data. You would typically parse this data (message_uuid,status,error,timestamp) to update the delivery status of your sent messages, perhaps in a database. Error field extraction is made slightly more robust. Added basictry...catch./webhooks/inbound: Logs incoming messages sent to your Vonage number. Added basictry...catch.res.status(200).send('OK'): Crucial! Vonage needs this acknowledgment.Verification: Send a test broadcast using the
/broadcastendpoint again. Watch your server logs. You should see:/broadcastinitiating the sends./webhooks/statusshowing updates likesubmitted,delivered, orfailedfor each message sent (these may arrive with some delay).How Do You Add Error Handling and Retry Logic for SMS?
Robust applications need solid error handling and logging.
Error Handling:
try...catchblock in thesendSmsfunction (updated in Section 2) handles errors during the API call. It now attempts to log more detailed error information.try...catch(as shown in Section 4) to prevent the server from crashing if processing fails. Ensure you still send200 OKunless it's a fundamental issue receiving the request./broadcastendpoint includes basic validation. Enhance this using libraries likejoiorexpress-validator, and especiallylibphonenumber-jsfor phone numbers.Logging:
console.log,console.warn,console.errorconsistently. The enhancedsendSmsprovides better context.message_uuid, recipient number, timestamps, and error details.winstonorpinofor structured logging (JSON), log levels, and transports (files, external services).Retry Mechanisms:
200 OKresponse. Ensure your webhook handlers are reliable and respond quickly.sendSmsfails due to potentially temporary issues (e.g., network timeout, rate limiting error429), you might implement a limited retry strategy.sendSmscall in a loop with delays.async-retrycan help.Example: Simple Retry Logic (Conceptual - Integrate into
/broadcastloop)This shows how you might add retry logic within the
/broadcasthandler's loop.429_5xx). Retrying permanent errors (400bad number) is wasteful. Ensure delays don't compound excessively. For large scale_ offload sending to a background queue system (like BullMQ) which handles retries more robustly. TheisRetryableErrorfunction now handles potentially non-numericerrorCodevalues.How Do You Track SMS Messages with a Database?
For tracking broadcast jobs_ individual message statuses_ and managing recipients effectively_ a database is highly recommended. Here's a conceptual example using Prisma (a popular Node.js ORM).
Step 1: Install Prisma
Prisma 6 Updates: Prisma 6.16.3 (January 2025) includes the completed migration from Rust to TypeScript for core logic_ a new ESM-first generator splitting Prisma Client into multiple files_ and enhanced full-text search capabilities. Minimum supported versions: Node.js 18.18.0+ and TypeScript 5.0+. (Source: Prisma Changelog_ January 2025)
This creates a
prismafolder withschema.prismaand updates.envwithDATABASE_URL.Step 2: Define Schema (
prisma/schema.prisma)Broadcast: Represents a single bulk sending job.Recipient: Represents each individual message within a broadcast_ tracking its specific status and VonagemessageUuid. Added index onvonageMessageUuid.BroadcastandRecipient.Step 3: Apply Schema Changes
Create and apply the first migration.
Step 4: Integrate Prisma Client
Instantiate the client and use it to interact with the database. Handle potential connection errors and ensure graceful shutdown.
Step 5: Modify API and Webhooks to Use Database
Broadcastrecord.Recipientrecords (statusPENDINGorQUEUED).202 Acceptedimmediately after creating records to indicate processing will happen asynchronously.sendSmsis called and returns successfully, update the correspondingRecipientrecord (status: 'SUBMITTED',vonageMessageUuid,submittedAt).sendSmsfails, update theRecipientrecord (status: 'FAILED',errorMessage,errorCode).Recipientrecord using thevonageMessageUuidfrom the webhook data.Recipient'sstatus,lastStatusUpdate, and potentiallyerrorMessage/errorCodebased on the webhook content (delivered,failed,rejected, etc.).messageUuidmight not be found (e.g., log an error).(Implementing these database interactions is left as an exercise but involves using
prisma.broadcast.create,prisma.recipient.createMany,prisma.recipient.update, andprisma.recipient.findUniquewithin the respective route handlers.)Frequently Asked Questions About Vonage Bulk SMS Broadcasting
How do you send bulk SMS messages with Vonage?
Send bulk SMS messages with Vonage by using the Vonage Messages API with Node.js and Express. Create an application with the Vonage Server SDK, authenticate with your API credentials and private key, then iterate through your recipient list calling the
vonage.messages.send()method for each phone number. Implement rate limiting based on your 10DLC campaign throughput to avoid HTTP 429 errors.What is the Vonage Messages API rate limit?
The Vonage Messages API has a base limit of 30 API requests per second. However, actual SMS throughput depends on your number type and US A2P 10DLC registration. Standard 10DLC campaigns typically allow 4,500 messages/minute (75 msg/sec on T-Mobile), while Low Volume campaigns are limited to 15 messages/minute. Exceeding your rate limit results in HTTP 429 errors and message queueing or blocking.
Why use the Vonage Messages API instead of the SMS API?
Use the Vonage Messages API over the older SMS API for modern features including multi-channel support (SMS, WhatsApp, Facebook Messenger, Viber), detailed status webhooks with delivery confirmations, better error reporting, and application-based authentication with private keys. The Messages API provides more robust tracking and supports future channel expansion.
What is US A2P 10DLC registration and why is it mandatory?
US A2P 10DLC (Application-to-Person 10 Digit Long Code) registration is mandatory for all SMS traffic to US recipients using standard long codes. The registration process involves brand and campaign vetting by Vonage and carriers, taking several days to weeks. Unregistered long codes are blocked or heavily filtered by carriers. Registration determines your throughput limits based on campaign type (Standard, Low Volume, or Sole Proprietor).
How do Vonage webhook callbacks work for message status?
Vonage sends webhook callbacks as HTTP POST requests to your configured Status URL whenever a message status changes (submitted, delivered, failed, rejected). Your webhook endpoint receives JSON data including
message_uuid,status,timestamp, and error details. Respond with HTTP 200 OK to acknowledge receipt. Vonage automatically retries if it doesn't receive a 200 response.What Node.js version do you need for Vonage bulk SMS?
Use Node.js v22 LTS (Active LTS through April 2027, recommended) or v20 LTS (Maintenance LTS through April 2026) for Vonage bulk SMS applications. Express v5.1.0 requires Node.js 18 or higher. Avoid Node.js v18 as it reaches end-of-life on April 30, 2025, and won't receive security updates.
How do you handle rate limiting in production?
Handle rate limiting in production by implementing delays between sends based on your 10DLC campaign throughput, using a background job queue (BullMQ, Bull) for asynchronous processing, implementing exponential backoff for HTTP 429 errors, and monitoring carrier-specific limits (AT&T applies per-minute limits, T-Mobile per-second). Track submission attempts in a database to avoid duplicate sends during retries.
What database should you use for tracking SMS broadcasts?
Use PostgreSQL with Prisma ORM (v6.16.3+) for tracking SMS broadcasts. Create tables for Broadcast jobs and Recipients with fields for
phoneNumber,status,vonageMessageUuid,submittedAt,lastStatusUpdate, anderrorCode. Index thevonageMessageUuidfield for fast webhook lookups. Alternative databases include MySQL, MongoDB, or SQLite for development.How do you secure Vonage API credentials?
Secure Vonage API credentials by storing them in environment variables using dotenv for development, never committing
.envfiles to version control, using secrets managers (AWS Secrets Manager, Infisical, HashiCorp Vault) for production, rotating API keys regularly, and restricting private key file permissions (chmod 600 private.key). Over 1 million secrets have been exposed through leaked .env files.What are the throughput limits for different 10DLC campaign types?
Throughput limits for 10DLC campaigns vary by type: Standard campaigns allow 4,500 messages/minute (75 msg/sec on T-Mobile), Low Volume Mixed campaigns limit to 1,000 messages/day and 15 messages/minute, Sole Proprietor campaigns allow 3,000 messages/day and 15 messages/minute, and sanctioned 10DLCs can send up to 30 messages/second. AT&T applies per-minute limits based on Trust Score; T-Mobile uses per-second limits.
How do you test Vonage webhooks locally?
Test Vonage webhooks locally using ngrok to create a secure HTTPS tunnel to your localhost. Run
ngrok http 3000to get a public URL, configure your Vonage Application's Status URL and Inbound URL with the ngrok URL plus your webhook paths (e.g.,https://abc123.ngrok-free.app/webhooks/status), and use ngrok's web interface to inspect and replay webhook requests for debugging.What is the difference between synchronous and asynchronous SMS sending?
Synchronous SMS sending processes recipients sequentially in the API request, blocking until all messages are submitted, resulting in long response times for large recipient lists. Asynchronous sending responds immediately with HTTP 202 Accepted, processes sends in background jobs or queues, allows better rate limiting and retry logic, and scales better for production workloads. Use background job queues like BullMQ for production systems.
How do you implement retry logic for failed SMS?
Implement retry logic by catching errors from
sendSms(), checking if the error is retryable (HTTP 429, 5xx status codes), using exponential backoff for delays between retries (1s, 2s, 4s, 8s), limiting maximum retry attempts (2-3 retries), and avoiding retries for permanent errors (HTTP 400 bad number format). Log all retry attempts with error codes for debugging and tracking delivery issues.What Express.js middleware do you need for Vonage?
Essential Express.js middleware for Vonage includes
express.json()to parse JSON request bodies,express.urlencoded({ extended: true })for form data, custom rate limiting middleware orexpress-rate-limitpackage, error handling middleware for catching async errors, and logging middleware likemorganorwinstonfor request/response tracking. Express v5+ natively handles promise rejections from middleware.How do you validate phone numbers before sending SMS?
Validate phone numbers using the
libphonenumber-jslibrary to check E.164 format (e.g., +14155550100), verify the number is valid for SMS, extract country code and national number, format numbers consistently, and check against carrier databases. Avoid basic regex validation in production as it doesn't handle international variations, special cases, or invalid number ranges accurately.