Frequently Asked Questions
Use Node.js with Express and the Vonage Messages API to create an API endpoint that accepts recipient numbers and a message. The application iterates through recipients, sending individual SMS messages via the Vonage API, incorporating delays to manage rate limits and ensure deliverability. This setup enables programmatic bulk SMS broadcasting without manual intervention.
The Vonage Messages API is a versatile tool for sending and receiving messages across multiple channels, including SMS. Its reliability and extensive features make it ideal for applications requiring robust messaging capabilities, including bulk SMS broadcasting as described in the article.
Rate limiting is essential to avoid overwhelming SMS providers and carriers, preventing your messages from being blocked or filtered. It involves introducing delays between sending individual messages to adhere to API limits and ensure reliable delivery. In this Node.js application, rate limiting is managed using setTimeout with a configurable delay.
For high-volume bulk SMS sending, a message queue like BullMQ or RabbitMQ is recommended. It handles jobs asynchronously, manages rate limiting, and improves scalability. While the tutorial uses sequential sending for simplicity, a queue is ideal for robust production systems handling large recipient lists.
While the tutorial provides a functional foundation, enhancements are needed for full production readiness. These include robust authentication, error handling with retries, and a database for tracking and persistence. The tutorial code provides guidance on how to expand on these areas. Additional considerations are 10DLC registration for US numbers and handling special cases like opt-outs.
The libphonenumber-js
library is used for robust phone number validation, ensuring numbers are in the correct format (ideally E.164) before sending SMS messages. This validation prevents unnecessary API calls and improves deliverability by reducing errors related to incorrect formatting. This is crucial for reliable and efficient SMS broadcasts
Create a Vonage application in the Vonage API Dashboard, enable "Messages," and set inbound/status webhook URLs (even if handlers aren't fully implemented yet). Generate and securely store private keys, copy the Application ID, and link your purchased SMS-capable Vonage virtual number to the application.
The dotenv
module loads environment variables from a .env
file into process.env
. This allows storing sensitive credentials (API keys, secrets) securely outside of the source code, following security best practices.
The private key, generated when creating a Vonage application, authenticates your application to the Vonage APIs. It's crucial for secure communication and must be stored securely (never commit to version control). The path to this key is configured in the .env file.
The tutorial handles rate limits using setTimeout
to introduce a delay (SEND_DELAY_MS) between sending each SMS. The delay should be adjusted based on your Vonage number type (long code, short code, toll-free), 10DLC registration status (if applicable), and account limits with Vonage.
The delay (SEND_DELAY_MS) between SMS messages is crucial and depends on several factors. For long codes, starting with a delay of 1100ms (slightly over 1 SMS/sec) is a good starting point. This value should be adjusted based on account limits, the type of number used, and whether or not you've registered with The Campaign Registry (TCR)
The code utilizes the libphonenumber-js
library to parse and validate phone numbers, converting them to E.164 format. This ensures numbers are in a consistent, internationally recognized format before attempting to send SMS messages.
The sendSms
function includes a try...catch block with enhanced logging. For production, using a dedicated logging library like Winston or Pino for structured logging, levels, and transport is recommended. The provided code also demonstrates a conceptual retry mechanism for transient errors (e.g., network issues).
Asynchronous processing, used in the /send-bulk endpoint, prevents HTTP timeouts for large recipient lists. The server immediately responds with a 202 Accepted status while the sendBulkSms function processes in the background.
Production bulk SMS applications require secure authentication (JWT, OAuth), input validation and sanitization, HTTPS, rate limiting at the API endpoint level, and secure credential storage (using platform secret management). The simple API key example shown in the tutorial is insufficient for production.
IMPORTANT NOTE: This article uses the Vonage Messages API and
@vonage/server-sdk
. If you're looking for Twilio-specific implementation, adapt the code examples and API calls in this guide to use the Twilio Node.js Helper Library (twilio
npm package) andclient.messages.create()
method instead.Build a production-ready bulk SMS broadcasting application using Node.js, Express, and the Vonage Messages API. Learn everything from initial project setup to deployment and verification, focusing on production considerations like API rate limiting, error handling, phone number validation, 10DLC registration for US traffic, and security best practices.
By the end, you'll have a functional Express application that accepts a list of phone numbers and a message, then reliably sends that message to each recipient via Vonage while respecting API limits and handling errors gracefully.
Project Overview and Goals: Building a Production-Ready Bulk SMS System
What We're Building:
Construct a Node.js application using the Express framework that exposes an API endpoint. This endpoint accepts a list of recipient phone numbers and a message body. The application then iterates through the recipients and uses the Vonage Messages API to send the SMS message to each number individually, incorporating delays to manage rate limits.
Problem Solved:
Send SMS messages to multiple recipients programmatically (bulk broadcasting) without manually sending each one. The application tackles the crucial challenge of handling API rate limits imposed by SMS providers and carriers to ensure reliable delivery without getting blocked.
Technologies Used:
@vonage/server-sdk
: Official Vonage Node.js SDK (v3+) for interacting with the Vonage APIs. Version 3 is fully written in TypeScript with monorepo architecture, providing better IDE support and allowing use of specific packages rather than the entire suite. Functions use parameter objects for better maintainability.dotenv
: Module to load environment variables from a.env
file intoprocess.env
.libphonenumber-js
: Library for robust phone number validation (E.164 format).ngrok
(for local development): Tool to expose local servers to the internet. Useful for testing Vonage webhook reachability to your local machine, though this guide doesn't fully implement webhook handlers.System Architecture:
The system follows this flow:
/send-bulk
endpoint on the Express API Server..env
file (containing Vonage credentials), and initiates the sending process.Expected Outcome:
Run a Node.js Express server with a
/send-bulk
endpoint that reliably sends SMS messages to a list of provided phone numbers using Vonage, incorporating phone number validation and basic rate limit handling.Prerequisites:
ngrok
: Install and configure ngrok if you plan to test Vonage webhook reachability to your local development server. Download ngrok1. Setting up the Project
Initialize your Node.js project and install the necessary dependencies.
Environment Setup:
This guide assumes you have Node.js and npm installed. Verify installation by opening your terminal or command prompt and running:
If these commands return version numbers, you're good to go. If not, download and install Node.js from the official website.
Important for Testing: If using Vonage Messages API sandbox credentials for development/testing, be aware of significantly lower rate limits: 1 message per second and 100 messages per month. Switch to production credentials before load testing or deploying to production.
Project Initialization:
Create Project Directory:
Initialize npm: This creates a
package.json
file to manage dependencies and project metadata.The
-y
flag accepts default settings.Install Dependencies:
express
: The web framework.@vonage/server-sdk
: The Vonage Node.js library.dotenv
: To manage environment variables securely.libphonenumber-js
: For phone number validation.Project Structure:
Create the following basic structure within your
vonage-bulk-sms
directory:Configuration:
Create
.env
file: This file stores sensitive credentials. Add the following lines, leaving the values blank for now:Create
.gitignore
file: Essential for preventing accidental commits of sensitive data and unnecessary files.Architectural Decisions & Purpose:
dotenv
: Keeps sensitive API keys and configurations out of the source code, adhering to security best practices. Environment variables are the standard way to configure applications in different environments (development, staging, production)..gitignore
: Essential for security and clean version control.libphonenumber-js
: Integrated early for robust phone number validation, crucial for deliverability and avoiding unnecessary API calls.2. Implementing Core Functionality: Bulk Sending Logic with Rate Limiting
Write the core logic to send SMS messages using the Vonage SDK, handle multiple recipients with validation, and implement rate limiting to respect API constraints.
index.js
– Initial Setup:Explanation:
dotenv
,express
,vonage/server-sdk
, andlibphonenumber-js
. Initializes Express and loads environment variables..env
. Includes checks for required variables and resolves the private key path.sendSms
Function: Anasync
function to send a single SMS viavonage.messages.send
. Includes enhanced error logging.sendBulkSms
Function:recipients
array andmessage
.for...of
.libphonenumber-js
to validate each recipient number. Skips invalid numbers and logs a warning. Uses the E.164 formatted number (formattedNumber
) for sending.sendSms
for each valid recipient.setTimeout
andSEND_DELAY_MS
. This delay is critical and should be tuned. It's now read from environment variables with a default.Design Patterns & Alternatives:
p-limit
for concurrent sends, but carefully manage both concurrency and per-second rate limits. The sequential approach is safer initially.3. Building a REST API Endpoint for Bulk SMS
Create an Express endpoint to trigger the bulk sending process and handle incoming requests.
Add to
index.js
(beforeapp.listen
):Explanation:
POST /send-bulk
.recipients
andmessage
.X-API-Key
header, comparing againstprocess.env.API_KEY
. Crucially emphasizes this needs proper implementation and secure key management in production. Includes warnings if the key isn't set or doesn't match.sendBulkSms
withoutawait
before responding.202 Accepted
immediately.sendBulkSms
runs in the background..then()
and.catch()
handle logging after completion/failure./health
endpoint for monitoring.Testing with
curl
:Start your server (
node index.js
). Open another terminal. (SetAPI_KEY
in.env
if you enable the auth check).Expected
curl
Response (JSON):Expected Server Console Output (example):
(Replace
+1555...
numbers with real, testable phone numbers. Message UUIDs will be actual UUIDs.)4. Integrating with Vonage (Credentials & Configuration)
Ensure Vonage is configured correctly in the dashboard and your application uses the credentials properly.
1. Obtain API Key and Secret:
VONAGE_API_KEY
andVONAGE_API_SECRET
in your.env
file.2. Create a Vonage Application:
https://example.com/webhooks/inbound
) or your ngrok URL +/webhooks/inbound
if testing locally. Vonage requires this URL even if the handler isn't implemented in this tutorial./webhooks/status
(e.g.,https://YOUR_NGROK_ID.ngrok.io/webhooks/status
). This is where Vonage sends delivery receipts (DLRs). Again, the handler isn't built here, but the URL is needed for setup.private.key
file securely. Do not commit it.VONAGE_APPLICATION_ID
in.env
.VONAGE_APPLICATION_PRIVATE_KEY_PATH
in.env
points correctly to your savedprivate.key
file.3. Link Your Vonage Number:
+14155550100
) intoVONAGE_NUMBER
in.env
.4. Set Default SMS API (Crucial):
Environment Variable Summary (
.env
):Security:
.env
orprivate.key
. Use.gitignore
.5. Implementing Error Handling, Logging, and Retry Mechanisms for Production
Robust applications need solid error handling, structured logging, and retry logic for transient failures.
Error Handling (Enhanced in
sendSms
):The
sendSms
function already includes atry...catch
with detailed logging of Vonage errors (err?.response?.data
).Logging:
console.log/warn/error
. Acceptable for development.Example using Pino (Conceptual – requires
npm install pino
):Retry Mechanisms (Conceptual):
The current code doesn't retry failed sends. For production, implement retries for transient errors (network issues,
5xx
status codes).sendSms
catch
block.async-retry
.Example: Simple Retry Logic (Conceptual within
sendSms
– Illustrative Purposes Only)Testing Error Scenarios:
.env
.6. Creating a Database Schema for Job Tracking and Message Persistence (Optional but Recommended)
For production systems, add persistence to track bulk send jobs, individual message delivery status, and enable retry management.
Why a Database?
delivered
,failed
based on DLRs) requires implementing the Status Webhook handler (Section 4), which is outside the scope of this tutorial's core code.Example Database Schema (Conceptual – SQL):
Data Access Layer Implementation:
Use an ORM (Sequelize, Prisma) or query builder (Knex.js).
Integration Steps (High-Level):
sendSms
. Update recipient record (status 'sent'/'failed', UUID, attempt count). Implement delays/retries. Update job status.Implementing a database layer adds complexity but is vital for robust production systems.
7. Implementing Security: API Authentication, Rate Limiting, and HTTPS
Secure your application with these essential measures for production deployment.
Input Validation and Sanitization:
/send-bulk
endpoint validates input types.sendBulkSms
useslibphonenumber-js
for robust phone number validation (E.164 format).Authentication & Authorization:
Rate Limiting (API Endpoint):
express-rate-limit
.Add this near the top of
index.js
:HTTPS:
Helmet Middleware:
Add this near the top of
index.js
:Dependency Management:
npm update
).npm audit
or Snyk to find vulnerabilities.Secure Credential Storage:
.env
and.gitignore
.Testing Security:
curl -v
).8. Understanding A2P 10DLC Registration and US SMS Compliance Requirements
SMS sending to US numbers involves several critical compliance requirements, particularly for Application-to-Person (A2P) messaging.
SEND_DELAY_MS
to 100–200ms for US numbers to leverage higher approved throughput.Throughput Management Strategies:
Vonage API Rate Limit (2025): All Vonage API keys have a default throughput restriction of 30 API requests per second. This translates to approximately 2,592,000 SMS per day for standard accounts. If you exceed this limit, Vonage will reject API requests with status code 1 (Throttled). Implement exponential backoff to handle throttling responses gracefully. For higher throughput requirements (resellers, large campaigns), contact your Vonage account manager for case-by-case review and limit increases.
Frequently Asked Questions About Bulk SMS with Vonage and Node.js
What is the Vonage API rate limit for sending SMS?
Vonage enforces a default rate limit of 30 API requests per second for all API keys, translating to approximately 2,592,000 SMS messages per day for standard accounts. If you exceed this limit, Vonage will reject requests with status code 1 (Throttled). Implement exponential backoff to handle throttling responses gracefully. For higher throughput needs, contact your Vonage account manager for custom rate limit increases.
How do I handle rate limiting when sending bulk SMS with Vonage?
Implement a delay between each SMS send operation using
setTimeout()
in your Node.js code. The default Vonage limit is 30 requests/second (~33ms between sends), but use a conservative delay like 1,100ms (~0.9 SMS/sec) to avoid hitting limits during network latency. After 10DLC registration with high trust scores, you can decrease the delay to 100–200ms for US numbers to leverage higher approved throughput.What is A2P 10DLC registration and why is it required?
A2P (Application-to-Person) 10DLC registration is mandatory for sending SMS to US numbers using 10-digit long codes. US carriers require registration through The Campaign Registry (TCR) via Vonage to combat spam. Unregistered traffic faces severe filtering, blocking, and throughput throttling. T-Mobile allocates throughput based on brand trust scores, while other carriers enforce a shared 600 TPM (10 messages/second per number) limit.
How do I validate phone numbers before sending SMS with Vonage?
Use the
libphonenumber-js
library to validate phone numbers in E.164 format before sending. Install it withnpm install libphonenumber-js
, then useparsePhoneNumberFromString()
to validate and format numbers. This prevents wasted API calls on invalid numbers and improves deliverability by ensuring proper international formatting.What is the difference between Vonage Messages API and SMS API?
Vonage Messages API is the newer, unified API supporting multiple channels (SMS, MMS, WhatsApp, Viber) with a single interface. The older SMS API only handles SMS/MMS. Messages API requires creating a Vonage Application with Application ID and private key authentication, while SMS API uses only API Key and Secret. Vonage recommends Messages API for new projects due to its flexibility and future channel support.
How do I send SMS messages asynchronously in Node.js with Express?
Call your bulk send function without
await
before responding to the client with a 202 Accepted status. This prevents HTTP timeouts for large recipient lists. Use.then()
and.catch()
to handle completion and errors after the response is sent. For production, implement a proper queue system (BullMQ, RabbitMQ) to process messages in background workers with retry logic and status tracking.What sandbox rate limits does Vonage Messages API have?
Vonage Messages API sandbox credentials enforce strict limits: 1 message per second and 100 messages per month total. These limits are significantly lower than production limits (30 req/sec, 2.59M messages/day). Switch to production API credentials before load testing or deploying to production to avoid hitting sandbox restrictions during development.
How do I implement retry logic for failed SMS sends?
Add retry logic in your
sendSms
function'scatch
block. Only retry transient errors (5xx status codes, network errors), not permanent failures (invalid numbers, insufficient funds). Implement exponential backoff (1s, 2s, 4s delays) between retries using libraries likeasync-retry
. For production, use queue systems with built-in retry features (BullMQ) to handle failed messages robustly.What security measures should I implement for bulk SMS APIs?
Implement these security measures: (1) Use API key authentication with strong, unique keys stored in environment variables; (2) Apply rate limiting with
express-rate-limit
to prevent endpoint abuse; (3) Always use HTTPS in production with SSL termination via reverse proxy; (4) Add Helmet middleware for security headers; (5) Validate and sanitize all inputs including phone numbers and message content; (6) Keep dependencies updated withnpm audit
.How much does it cost to send bulk SMS with Vonage?
Vonage SMS pricing varies by destination country. US SMS typically costs $0.0075–$0.0120 per message depending on number type (long code vs toll-free). Volume discounts are available for high-volume senders. Additional costs include: Vonage phone number rental ($1.00/month for US numbers), 10DLC brand registration (
$4 one-time), and campaign registration ($15 one-time). Check Vonage's pricing page for current rates by destination.Can I send SMS to international numbers with Vonage?
Yes, Vonage supports SMS delivery to 200+ countries. Use E.164 format with country code prefix (e.g., +44 for UK, +61 for Australia). Pricing and deliverability vary by destination – some countries have higher costs or carrier restrictions. Check Vonage's coverage and pricing documentation for specific countries before sending international messages. Ensure compliance with local regulations (GDPR, PDPA, etc.) for international SMS campaigns.
How do I track SMS delivery status with Vonage?
Vonage sends delivery receipts (DLRs) to your configured Status Webhook URL. Implement a webhook endpoint in Express to receive POST requests with delivery status updates (
delivered
,failed
,rejected
). Extract themessage_uuid
from the webhook payload to match with your sent messages. Store delivery status in your database for reporting. Note: Not all carriers provide delivery receipts – some only confirm message handoff, not final delivery.