Tech Stack: Node.js, Express, Vonage Messages API, dotenv
This guide provides a comprehensive walkthrough for building a robust Node.js application capable of sending SMS marketing campaigns using the Vonage Messages API. We will cover project setup, sending individual and bulk messages, handling delivery status updates, implementing basic error handling and security, and preparing for deployment.
Project Overview and Goals
What We're Building:
We will create a Node.js Express server application that can:
- Send individual SMS messages via an API endpoint.
- Send bulk SMS messages (a basic campaign) to a list of recipients via an API endpoint.
- Receive delivery status updates from Vonage via webhooks.
- Utilize best practices for API key management, basic error handling, and logging.
Problem Solved:
This application provides a foundational backend for businesses needing to programmatically send targeted SMS messages for marketing, notifications, or alerts, leveraging the global reach and reliability of Vonage's network.
Technologies Used:
- Node.js: A JavaScript runtime built on Chrome's V8 engine, ideal for building fast, scalable network applications.
- Express: A minimal and flexible Node.js web application framework, providing a robust set of features for web and mobile applications.
- Vonage Messages API: A powerful API enabling communication across multiple channels (SMS, MMS, WhatsApp, etc.). We will focus on its SMS capabilities.
@vonage/server-sdk
: The official Vonage Node.js SDK for interacting with Vonage APIs.dotenv
: A zero-dependency module that loads environment variables from a.env
file intoprocess.env
.ngrok
: A tool to expose local servers behind NATs and firewalls to the public internet over secure tunnels (essential for local webhook testing).
System Architecture:
+-----------------+ +---------------------+ +-----------------+ +-------------------+
| User / Client |----->| Node.js Express App |----->| Vonage Cloud |----->| Mobile Recipient |
| (e.g., Postman) | | (API Endpoints) | | (Messages API) | | (Receives SMS) |
+-----------------+ +----------^----------+ +--------v--------+ +-------------------+
| | (Status Update)
| (Webhook Handler) |
+-----------------------+
- A client (like Postman or another application) sends a request to our Node.js Express app's API endpoint (e.g.,
/send-sms
,/send-campaign
). - The Express app uses the Vonage Node.js SDK to securely send the message details (recipient, sender ID, message content) to the Vonage Messages API.
- Vonage processes the request and delivers the SMS message to the recipient's mobile device.
- Vonage sends status updates (e.g.,
delivered
,failed
) back to a pre-configured webhook URL handled by our Express app.
Prerequisites:
- Node.js and npm (or yarn): Installed on your development machine. Download from nodejs.org.
- Vonage API Account: Create a free account at vonage.com.
- Vonage API Key and Secret: Found on your Vonage API Dashboard.
- Vonage Virtual Number: Purchase an SMS-capable number from the Vonage Dashboard.
ngrok
: Installed and authenticated (a free account is sufficient). Download from ngrok.com.- Text Editor or IDE: Such as VS Code.
- Basic understanding of JavaScript, Node.js, Express, and REST APIs.
1. Vonage Account Setup and Configuration
Before writing code, ensure your Vonage account is correctly configured.
- Sign Up/Log In: Access your Vonage API Dashboard.
- Get API Key and Secret:
- Navigate to the API Settings page.
- Your API key and API secret are displayed at the top. Keep these secure — they grant access to your account.
- Purpose: These credentials authenticate your application's requests to the Vonage API.
- Purchase a Vonage Number:
- Navigate to Numbers > Buy numbers.
- Search for numbers using country, features (ensure SMS is selected), and type (Mobile, Landline, Toll-Free).
- Purchase a number suitable for your campaign needs (consider local regulations and throughput requirements — see Section 8).
- Note down the purchased number (e.g.,
12015550123
). This will be yourFROM_NUMBER
. - Purpose: This is the phone number recipients will see as the sender of your SMS messages.
- Set Default SMS API to Messages API:
- Navigate back to API Settings.
- Scroll down to SMS settings.
- Ensure Messages API is selected as the ""Default SMS Setting"". Vonage has two SMS APIs; the Messages API is newer and supports multiple channels. Using the wrong default will cause unexpected webhook formats or errors.
- Click Save changes.
- Create a Vonage Application (for Webhooks): Even though we'll use API Key/Secret for sending, an Application is needed to configure webhook URLs for status updates.
- Navigate to Applications > Create a new application.
- Give it a name (e.g.,
Node SMS Campaign App
). - Click Generate public and private key. Save the
private.key
file securely (this key is required by the Vonage platform to create an Application entity, even if not used for authentication in this specific guide). - Enable the Messages capability.
- You'll see fields for Inbound URL and Status URL. Leave these blank for now. We'll fill the Status URL later using
ngrok
. - Click Generate new application.
- Note the Application ID generated for this application.
- Link Your Number to the Application:
- Go back to the Applications list, find your new application, and click its name.
- Scroll down to the Linked numbers section.
- Click Link next to the Vonage number you purchased earlier.
- Purpose: This tells Vonage which application's webhooks should handle messages sent to this number (Inbound URL) or status updates about messages sent from this number (Status URL).
2. Setting Up the Node.js Project
Let's initialize our Node.js project and install dependencies.
-
Create Project Directory:
mkdir vonage-sms-campaigns cd vonage-sms-campaigns
-
Initialize npm Project:
npm init -y
- This creates a
package.json
file with default settings.
- This creates a
-
Install Dependencies:
npm install express @vonage/server-sdk dotenv
express
: The web framework.@vonage/server-sdk
: The official Vonage SDK.dotenv
: For managing environment variables.
-
Create Core Files:
touch index.js .env .gitignore
-
Configure
.gitignore
: Add standard Node.js ignores to prevent committing sensitive information or unnecessary files.# .gitignore # Dependencies node_modules/ # Environment Variables .env # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* # Optional Editor directories .vscode/ .idea/ # Optional Operating System files .DS_Store Thumbs.db
-
Configure Environment Variables (
.env
): Create a.env
file in the project root. Never commit this file to version control.# .env # Vonage API Credentials VONAGE_API_KEY=YOUR_API_KEY VONAGE_API_SECRET=YOUR_API_SECRET # Vonage Number (Sender ID) VONAGE_NUMBER=YOUR_VONAGE_NUMBER_INCLUDING_COUNTRY_CODE # Application Settings PORT=3000 # Or any port you prefer
- Replace
YOUR_API_KEY
,YOUR_API_SECRET
, andYOUR_VONAGE_NUMBER
with the actual values from your Vonage dashboard (Step 1). - Purpose: Using environment variables keeps sensitive credentials out of your codebase, making it more secure and configurable across different environments (development, staging, production).
- Replace
-
Basic Server Setup (
index.js
):// index.js require('dotenv').config(); // Load environment variables from .env file const express = require('express'); const { Vonage } = require('@vonage/server-sdk'); // --- Basic Configuration --- const app = express(); const port = process.env.PORT || 3000; // --- Middleware --- // Enable parsing of JSON request bodies app.use(express.json()); // Enable parsing of URL-encoded request bodies app.use(express.urlencoded({ extended: true })); // --- Vonage Client Initialization --- // Use API Key and Secret for authentication const vonage = new Vonage({ apiKey: process.env.VONAGE_API_KEY, apiSecret: process.env.VONAGE_API_SECRET }); // --- Basic Routes --- app.get('/', (req, res) => { res.send('SMS Campaign Server is running!'); }); // --- Start Server --- app.listen(port, () => { console.log(`Server listening on port ${port}`); });
- This sets up a basic Express server, loads environment variables, and initializes the Vonage SDK using your API Key and Secret.
3. Implementing Core Functionality: Sending SMS
Let's create API endpoints to send messages.
A. Sending a Single SMS
-
Add the following route handler to
index.js
(beforeapp.listen
):// index.js (add this section) // --- API Endpoints --- /** * @route POST /send-sms * @description Sends a single SMS message. * @param {string} to - Recipient phone number (E.164 format, e.g., 14155552671) * @param {string} text - The message content * @access Public (Add Auth in production!) */ app.post('/send-sms', async (req, res) => { const { to, text } = req.body; const from = process.env.VONAGE_NUMBER; // Basic validation if (!to || !text) { return res.status(400).json({ error: 'Missing required fields: to, text' }); } if (!from) { return res.status(500).json({ error: 'VONAGE_NUMBER environment variable not set.' }); } console.log(`Attempting to send SMS from ${from} to ${to}: ""${text}""`); try { const resp = await vonage.messages.send({ message_type: ""text"", text: text, to: to, from: from, channel: ""sms"" }); console.log(""Message sent successfully:"", resp); // { message_uuid: '...' } res.status(200).json({ success: true, message_uuid: resp.message_uuid }); } catch (err) { console.error(""Error sending SMS:"", err); // Provide more specific error feedback if possible let statusCode = 500; let errorMessage = ""Failed to send SMS.""; if (err.response) { // Error from Vonage API statusCode = err.response.status || 500; // Use title or detail from Vonage's structured error response if available errorMessage = err.response.data?.title || err.response.data?.detail || err.message || errorMessage; console.error(""Vonage API Error:"", statusCode, err.response.data || err.message); } else if (err.request) { // Request was made but no response received errorMessage = ""No response received from Vonage API.""; console.error(""Vonage Request Error:"", err.request); } else { // Error setting up the request errorMessage = err.message || ""An unknown error occurred during SMS sending setup.""; console.error(""SMS Sending Setup Error:"", err.message); } res.status(statusCode).json({ success: false, error: errorMessage }); } });
-
Explanation:
- The route listens for
POST
requests on/send-sms
. - It expects
to
(recipient number) andtext
(message content) in the JSON request body. - It retrieves the
from
number from environment variables. - Basic validation checks if required fields are present.
vonage.messages.send()
is called asynchronously (async
/await
).message_type: ""text""
: Specifies a plain text message.text
: The content of the SMS.to
: The recipient's phone number (ideally in E.164 format, e.g.,14155552671
).from
: Your Vonage virtual number.channel: ""sms""
: Explicitly specifies the SMS channel.
- A successful response from Vonage includes a
message_uuid
, which is returned in the JSON response. - The
catch
block handles potential errors during the API call, logs them, attempts to extract a meaningful error message from the Vonage response if available, and returns an appropriate error response.
- The route listens for
-
Testing with
curl
:- Start your server:
node index.js
- Open another terminal and run (replace placeholders):
curl -X POST http://localhost:3000/send-sms \ -H ""Content-Type: application/json"" \ -d '{ ""to"": ""RECIPIENT_PHONE_NUMBER"", ""text"": ""Hello from Vonage via Node.js!"" }'
- Replace
RECIPIENT_PHONE_NUMBER
with a real phone number (including country code, e.g.,12125551234
). - You should receive an SMS, and the terminal running the server should log success messages. The
curl
command should receive a JSON response like{""success"":true,""message_uuid"":""...""}
.
- Start your server:
B. Sending a Basic Bulk Campaign
This endpoint sends the same message to multiple recipients. Caution: Simple loops are not suitable for large campaigns due to rate limits. See Section 8 for details.
-
Add the following route handler to
index.js
:// index.js (add this section within // --- API Endpoints ---) /** * @route POST /send-campaign * @description Sends the same SMS message to multiple recipients. * @param {string[]} recipients - Array of phone numbers (E.164 format) * @param {string} text - The message content * @access Public (Add Auth in production!) */ app.post('/send-campaign', async (req, res) => { const { recipients, text } = req.body; const from = process.env.VONAGE_NUMBER; // Basic validation if (!recipients || !Array.isArray(recipients) || recipients.length === 0) { return res.status(400).json({ error: 'Missing or invalid required field: recipients (must be a non-empty array)' }); } if (!text) { return res.status(400).json({ error: 'Missing required field: text' }); } if (!from) { return res.status(500).json({ error: 'VONAGE_NUMBER environment variable not set.' }); } console.log(`Starting campaign from ${from} to ${recipients.length} recipients: ""${text}""`); const results = []; let successCount = 0; let failureCount = 0; // --- WARNING: Rate Limit Consideration --- // This simple loop can easily hit Vonage rate limits for large lists. // Production systems MUST implement proper queuing and rate limiting. // See Section 8: Rate Limiting and Throughput. // For demonstration, we add a small delay. DO NOT rely on this for production scale. const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms)); const INTER_MESSAGE_DELAY_MS = 1100; // Slightly over 1 sec for default 1/sec long code limit for (const to of recipients) { try { console.log(` - Sending to ${to}...`); const resp = await vonage.messages.send({ message_type: ""text"", text: text, to: to, from: from, channel: ""sms"" }); console.log(` - Success (UUID: ${resp.message_uuid})`); results.push({ to: to, success: true, message_uuid: resp.message_uuid }); successCount++; } catch (err) { console.error(` - Error sending to ${to}:`, err); // Log the full error for debugging let errorMessage = `Failed to send SMS to ${to}.`; let statusCode = 500; // Default status code for errors in the loop // Try to get specific error details, similar to single send if (err.response) { statusCode = err.response.status || 500; errorMessage = err.response.data?.title || err.response.data?.detail || err.message || errorMessage; console.error(` - Vonage API Error for ${to}:`, statusCode, err.response.data || err.message); } else if (err.request) { errorMessage = `No response received from Vonage API for ${to}.`; console.error(` - Vonage Request Error for ${to}:`, err.request); } else { errorMessage = err.message || `An unknown error occurred sending to ${to}.`; console.error(` - SMS Sending Setup Error for ${to}:`, err.message); } // We report individual failures but continue the campaign results.push({ to: to, success: false, error: errorMessage }); failureCount++; } // Apply delay *after* each attempt (success or fail) // Remove or adjust significantly if using short codes or higher throughput numbers await delay(INTER_MESSAGE_DELAY_MS); } console.log(`Campaign finished. Success: ${successCount}, Failures: ${failureCount}`); // Respond after the loop finishes res.status(200).json({ campaign_summary: { total_recipients: recipients.length, success_count: successCount, failure_count: failureCount, }, results: results // Detailed results for each recipient }); });
-
Explanation:
- Listens for
POST
on/send-campaign
. - Expects
recipients
(an array of phone numbers) andtext
. - Iterates through the
recipients
array. - Calls
vonage.messages.send()
for each recipient. - Crucially: Includes a basic
delay
usingsetTimeout
to demonstrate the need for pacing. This is NOT a robust production solution. Real applications need job queues (e.g., BullMQ, Kue) and intelligent rate limiting based on the Vonage number's throughput (see Section 8). - Error handling within the loop logs the specific error for each failed recipient and records the failure, but allows the campaign to continue for other recipients.
- Tracks success/failure counts and individual results.
- Returns a summary and detailed results after attempting all recipients.
- Listens for
-
Testing with
curl
:- Restart your server:
Ctrl+C
andnode index.js
- Run (replace placeholders):
curl -X POST http://localhost:3000/send-campaign \ -H ""Content-Type: application/json"" \ -d '{ ""recipients"": [""RECIPIENT_1"", ""RECIPIENT_2""], ""text"": ""Node.js Campaign Test!"" }'
- Replace
RECIPIENT_1
,RECIPIENT_2
with real phone numbers. - Observe the server logs — you'll see the delay between sends. Check if the SMS messages arrive. The
curl
response will summarize the outcome.
- Restart your server:
4. Handling Status Updates (Webhooks)
Vonage sends delivery status information to a webhook URL you configure.
-
Start
ngrok
: Expose your local server to the internet.# Make sure your Node server is running on port 3000 first! ngrok http 3000
ngrok
will display aForwarding
URL (e.g.,https://abcdef123456.ngrok.io
). Copy thehttps
URL. This URL is temporary and changes each time you restartngrok
.
-
Configure Status Webhook in Vonage Dashboard:
- Go to Applications > Click your application name (
Node SMS Campaign App
). - In the Capabilities section, find the Messages capability.
- Paste your
ngrok
HTTPS Forwarding URL into the Status URL field, appending a path like/webhooks/status
. Example:https://abcdef123456.ngrok.io/webhooks/status
- Click Save changes at the bottom of the page.
- Purpose: This tells Vonage where to send
POST
requests containing status updates for messages sent by this application.
- Go to Applications > Click your application name (
-
Create Webhook Handler in
index.js
: Add this route beforeapp.listen
:// index.js (add this section) // --- Webhook Handler --- /** * @route POST /webhooks/status * @description Receives message status updates from Vonage. * @access Public (Vonage needs to reach this) */ app.post('/webhooks/status', (req, res) => { console.log("--- Vonage Status Webhook Received ---"); console.log("Timestamp:", new Date().toISOString()); console.log("Body:", JSON.stringify(req.body, null, 2)); // Log the full payload const { message_uuid, status, timestamp, error, usage } = req.body; // Process the status update (e.g., update database, log analytics) // Example: Log key information console.log(`Status Update for UUID ${message_uuid}: ${status} at ${timestamp}`); if (error) { console.error(`Error Code: ${error.code}, Reason: ${error.reason}`); } if (usage && usage.price) { console.log(`Message Cost: ${usage.price} ${usage.currency}`); } // Vonage expects a 200 OK response to acknowledge receipt. // Failure to send 200 OK will cause Vonage to retry the webhook. res.status(200).end(); });
-
Explanation:
- Listens for
POST
requests on/webhooks/status
(matching the path configured in Vonage). - Logs the received request body. The body contains valuable information like the
message_uuid
(linking it back to the sent message), thestatus
(submitted
,delivered
,rejected
,failed
,accepted
),timestamp
, potentialerror
details, andusage
(cost). - Crucially: Sends a
200 OK
response back to Vonage immediately to acknowledge receipt. If Vonage doesn't receive a200 OK
, it will retry sending the webhook, potentially leading to duplicate processing. - In a real application, you would parse this data and update your database, trigger alerts, or feed analytics systems.
- Listens for
-
Testing Webhooks:
- Ensure your Node server is running (
node index.js
). - Ensure
ngrok
is running and the Status URL in Vonage points to yourngrok
URL. - Send a test SMS using the
/send-sms
endpoint (from Step 3A). - Watch the terminal running your Node server. Within a few seconds to minutes, you should see logs appearing from the
/webhooks/status
endpoint as Vonage sends updates (e.g.,submitted
,delivered
). - You can also inspect requests in the
ngrok
web interface (usuallyhttp://127.0.0.1:4040
).
- Ensure your Node server is running (
5. Error Handling and Logging
Robust error handling and logging are vital for production systems.
- Consistent Error Handling:
- Our route handlers include
try...catch
blocks for API calls. - Parse Vonage API error responses (as shown in the
/send-sms
and/send-campaign
examples) to provide more specific feedback than generic ""Failed"" messages. Checkerr.response.data
for Vonage's structured error details liketitle
anddetail
. - Implement centralized error handling middleware in Express for uncaught errors (beyond the scope of this basic guide, but recommended for production).
- Our route handlers include
- Logging:
- Use
console.log
for informational messages (e.g., ""Sending SMS..."", ""Webhook received""). - Use
console.error
for actual errors or failures. - Include relevant context in logs (timestamps, message UUIDs, recipient numbers where appropriate — be mindful of privacy).
- Production Logging: For production, replace
console.log/error
with a dedicated logging library like Winston or Pino. These offer:- Log levels (debug, info, warn, error).
- Structured logging (JSON format for easier parsing by log analysis tools).
- Multiple transports (writing to files, databases, log management services like Datadog, Logstash).
- Example (Conceptual - Winston):
// // Example: Setting up Winston (conceptual) // const winston = require('winston'); // const logger = winston.createLogger({ // level: 'info', // format: winston.format.json(), // defaultMeta: { service: 'sms-campaign-service' }, // transports: [ // new winston.transports.Console({ format: winston.format.simple() }), // new winston.transports.File({ filename: 'error.log', level: 'error' }), // new winston.transports.File({ filename: 'combined.log' }), // ], // }); // // Replace console.log with logger.info, console.error with logger.error
- Use
- Retry Mechanisms (Vonage Side):
- Vonage automatically retries sending SMS messages if temporary network issues occur.
- Vonage retries sending webhooks if your endpoint doesn't respond with
200 OK
. Ensure your webhook handler is reliable and responds quickly. - Client-Side Retries: For critical messages, your application might implement retries (with exponential backoff) if the initial
vonage.messages.send()
call fails due to network issues or temporary Vonage API unavailability (e.g., 5xx errors). Use libraries likeasync-retry
for this. However, be careful not to retry errors that indicate permanent failure (e.g., invalid number, insufficient funds).
6. Database Schema and Data Layer (Conceptual)
While this guide doesn't implement a database, a production system would require one.
- Purpose: Store campaign details, recipient lists, message status, costs, and potentially user data.
- Example Schema (Relational - e.g., PostgreSQL):
campaigns
:campaign_id (PK)
,name
,message_text
,sender_id
,created_at
,scheduled_at
,status
(e.g., 'draft', 'sending', 'completed', 'failed')recipients
:recipient_id (PK)
,phone_number (UNIQUE)
,first_name
,last_name
,subscribed
,created_at
campaign_recipients
:campaign_id (FK)
,recipient_id (FK)
,message_uuid (UNIQUE)
,status
(e.g., 'pending', 'submitted', 'delivered', 'failed'),status_timestamp
,error_code
,cost
,currency
(Updated by webhook handler)
- Data Access: Use an ORM (Object-Relational Mapper) like Sequelize or Prisma to interact with the database, handle migrations, and define models.
- Webhook Integration: The
/webhooks/status
handler would parse the incoming status update, find the corresponding record incampaign_recipients
using themessage_uuid
, and update itsstatus
,status_timestamp
,error_code
,cost
, etc.
7. Adding Security Features
Security is paramount, especially when handling user data and API keys.
- API Key Security:
- NEVER hardcode API keys or secrets in your source code.
- Use environment variables (
.env
locally, secure configuration management in deployment). - Ensure
.env
is in your.gitignore
. - Rotate API keys periodically.
- Input Validation:
- Sanitize and validate all input coming from clients (request bodies, query parameters).
- Use libraries like
express-validator
orjoi
to define schemas and validate data types, formats (e.g., E.164 for phone numbers), lengths, etc. - Example (
express-validator
- conceptual):npm install express-validator
// // Example Validation for /send-sms // const { body, validationResult } = require('express-validator'); // app.post('/send-sms', // body('to').isMobilePhone('any', { strictMode: true }).withMessage('Invalid phone number format (E.164 required)'), // body('text').notEmpty().trim().escape().withMessage('Text cannot be empty'), // (req, res) => { // const errors = validationResult(req); // if (!errors.isEmpty()) { // return res.status(400).json({ errors: errors.array() }); // } // // ... proceed with sending SMS ... // } // );
- Authentication & Authorization:
- Protect your API endpoints. Do not expose
/send-sms
or/send-campaign
publicly without authentication. - Implement strategies like API Keys (for server-to-server communication), JWT (JSON Web Tokens for user sessions), or OAuth.
- Protect your API endpoints. Do not expose
- Rate Limiting (Your API):
- Protect your server from abuse and brute-force attacks by limiting the number of requests a client can make to your API endpoints.
- Use libraries like
express-rate-limit
. - Example (
express-rate-limit
- conceptual):npm install express-rate-limit
// // Example: Basic rate limiting // const rateLimit = require('express-rate-limit'); // const apiLimiter = 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 to specific routes or globally // app.use('/send-sms', apiLimiter); // app.use('/send-campaign', apiLimiter);
- Webhook Security:
- Vonage supports Signed Webhooks using JWT or signature verification. This ensures that incoming requests to your webhook handler genuinely originate from Vonage. Implementing this is highly recommended for production. Consult the official Vonage documentation on webhook security for implementation details.
8. Rate Limiting and Throughput (Vonage Specific)
Vonage imposes limits on how fast you can send messages. Ignoring these will lead to rejected messages and potential account issues.
- Default Limits:
- Long Codes (Standard US/Canada Numbers): Typically 1 message per second (MPS) per number.
- Toll-Free Numbers (US/Canada): Higher throughput, often around 30 MPS per number (check specific limits).
- Short Codes (US/Canada): Highest throughput (often 100+ MPS), but require a separate, lengthy, and costly application process.
- International Numbers: Limits vary significantly by country and number type. Check Vonage documentation or country-specific regulations.
- API Concurrency Limit: Vonage generally allows 30 concurrent API requests per account by default. Sending faster than your number's MPS limit or exceeding the concurrent request limit will result in errors (often a
429 Too Many Requests
response). - US A2P 10DLC Registration:
- For sending Application-to-Person (A2P) SMS traffic to US numbers using standard 10-digit long codes (10DLC), registration of your brand and campaigns is mandatory. This process is done via The Campaign Registry (TCR), facilitated through the Vonage dashboard.
- Sending any significant volume before successful registration will result in very low throughput and eventual blocking by US carriers.
- Registration involves providing business details and campaign use case information. Throughput is assigned based on vetting scores and use case.
- Process: Navigate to the Brands and Campaigns section in your Vonage Dashboard and follow the registration steps. This process requires time and has associated fees, so plan accordingly.
- Handling Limits in Code:
- Simple loops are inadequate. The
setTimeout
delay in our/send-campaign
example is fragile and inefficient for production. - Use a Job Queue: Implement a robust job queue system (e.g., BullMQ, Kue, Celery if using Python) with workers that process messages.
- Rate Limit Workers: Configure your queue workers to respect the MPS limit of your Vonage number(s). Libraries like
bottleneck
can help manage rate limiting within your workers. - Monitor API Responses: Check for
429
errors and implement exponential backoff and retry logic in your workers. - Distribute Load: If using multiple Vonage numbers, distribute the sending load across them.
- Simple loops are inadequate. The