Frequently Asked Questions
Use the provided Node.js/Express application and the Plivo Node.js SDK. The application interacts with the Plivo API to send messages efficiently to large recipient lists via an API endpoint. Make sure to configure your Plivo credentials, sender ID, and API key in the .env file and install the necessary npm dependencies.
Plivo's documented limit for destination numbers per API call is 1000. The provided Node.js code handles lists larger than this limit by implementing intelligent batching within the sendBulkSms function.
Promise.allSettled is used to handle concurrent batch sending. It ensures that the application waits for all batch sending promises to resolve or reject, providing a robust way to track the success or failure of each batch regardless of individual outcomes.
For very large recipient lists (e.g., 10,000+), processing sendBulkSms directly in the API request handler can lead to timeouts. A background job queue like BullMQ or RabbitMQ is recommended to handle these large lists asynchronously and prevent blocking the main thread.
Yes, using Plivo's delivery report webhooks. The Node.js application includes a webhook endpoint (/api/webhooks/plivo/delivery-report) to receive and process these updates. You'll need to implement database integration to persist and track the status updates effectively.
Create a .env file in the project root and add your PLIVO_AUTH_ID, PLIVO_AUTH_TOKEN, and PLIVO_SENDER_ID. Obtain these from your Plivo account dashboard. Never commit this file to version control.
The API_KEY is crucial for securing the /api/bulk-sms endpoint. The provided auth.js middleware ensures that only requests with the correct API key can access this endpoint, preventing unauthorized use.
Use the validateWebhookSignature function in plivoService.js. This function handles the signature verification process, ensuring that incoming webhooks are indeed from Plivo and haven't been tampered with.
Only set PLIVO_WEBHOOK_SECRET if you've configured a separate webhook secret in your Plivo application settings. If you're using the default (your Plivo Auth Token), you don't need to set this variable, and the code will default to using PLIVO_AUTH_TOKEN.
The 'url' parameter specifies the webhook URL where Plivo will send delivery report updates. Ensure this URL is publicly accessible (e.g., using ngrok for local development). The provided code dynamically constructs the URL using API_BASE_URL.
The sendBulkSms function automatically splits the recipient list into batches of 1000 (Plivo's limit) and sends each batch concurrently using sendBulkSmsBatch.
A 207 Multi-Status response from the /api/bulk-sms endpoint indicates that the request was processed, but some batches failed during submission to Plivo. Check the server logs for details on the failed batches.
Robust validation of recipient phone numbers (using E.164 format checking) is essential to prevent sending messages to incorrect numbers, improve deliverability, and avoid wasting resources on invalid numbers.
Last Updated: October 5, 2025
Sending SMS messages to a large list of recipients – often called bulk messaging or broadcast messaging – is a common requirement for notifications, marketing campaigns, alerts, and more. Doing this efficiently, reliably, and in a way that handles errors and tracks delivery is crucial for production applications.
This guide provides a comprehensive walkthrough for building a robust bulk SMS sending system using Node.js, the Express framework, and the Plivo Communications Platform. We'll cover everything from project setup and core sending logic to API design, security, error handling, delivery tracking, and deployment.
Project Goals:
Technologies Used:
.env
file intoprocess.env
express.json()
/express.urlencoded()
System Architecture:
Prerequisites:
API Endpoint Reference:
https://api.plivo.com/v1/Account/{auth_id}/Message/
Source: Plivo Messaging API Documentation (plivo.com/docs/messaging/api/message), Plivo Node.js SDK (npmjs.com/package/plivo)
Final Outcome:
By the end of this guide, you will have a functional Express API endpoint that accepts bulk SMS requests, sends messages via Plivo using appropriate batching, handles delivery reports, incorporates basic security and logging, and is structured for further enhancement (like database integration and background jobs) and deployment.
1. Setting Up the Project
Let's initialize our Node.js project and install the necessary dependencies.
1. Create Project Directory
Open your terminal and run:
2. Initialize npm
This creates a
package.json
file to manage dependencies and project metadata.3. Install Dependencies
express
: The web framework (v4.18.x or later)plivo
: The official Plivo Node.js SDK (v4.x or later)dotenv
: To load environment variables from a.env
file (v16.x or later)body-parser
: Middleware to parse incoming request bodies (JSON, URL-encoded). While Express 4.16+ includesexpress.json()
andexpress.urlencoded()
,body-parser
is explicitly included here for clarity and historical context. The setup inapp.js
usesbody-parser
.express-rate-limit
: To prevent abuse of the API (v6.x or later)winston
: For structured logging (v3.x or later)4. Create Project Structure
A simple structure to start:
5. Configure Environment Variables (
.env
)Create a file named
.env
in the project root. Never commit this file to version control.YOUR_...
placeholders with your actual Plivo credentials, sender ID, and a secure, randomly generated API key. TheAPI_KEY
is mandatory for the API security middleware.PLIVO_SENDER_ID
: This is the 'From' number or Alphanumeric Sender ID used to send messages. Ensure it's registered and approved in your Plivo account for the destination countries. Use E.164 format for phone numbers (e.g.,+14155551212
). Format:+[country code][number]
without spaces or special characters.API_BASE_URL
: The public-facing URL where your application will be accessible. Needed for configuring Plivo webhooks. If testing locally with ngrok, use the ngrok forwarding URL.PLIVO_WEBHOOK_SECRET
: As noted, this is optional. The validation code will default to usingPLIVO_AUTH_TOKEN
if this specific variable is not set, which matches Plivo's default V3 signature validation behavior.SMS Character Limits (October 2025):
6. Create
.gitignore
Create a
.gitignore
file in the project root to prevent committing sensitive files and unnecessary folders.7. Configure Logger (
src/config/logger.js
)Set up a basic Winston logger.
logs/error.log
,logs/combined.log
) and to the console during development. It also creates thelogs/
directory if it doesn't exist.2. Implementing Core Functionality (Plivo Service)
This service will contain the logic for interacting with the Plivo API, including sending bulk messages and handling batching.
src/services/plivoService.js
Explanation:
API_BASE_URL
is missing.PLIVO_DST_LIMIT
: Defines the max recipients per API call (1,000 as of October 2025, verified from Plivo documentation).sendBulkSmsBatch
: Sends a single batch, joins recipients with<
delimiter (Plivo's bulk SMS format)_ constructs the webhook URL_ callsclient.messages.create
_ logs success/failure_ and clarifies the role ofmessageUuid
vs. DLRs for tracking. Added E.164 format requirements in documentation.sendBulkSms
: Takes the full recipient list_ iterates creating batches_ pushessendBulkSmsBatch
promises_ usesPromise.allSettled
for concurrent execution and robust results_ logs outcomes.validateWebhookSignature
: Retrieves necessary components (signature_ nonce_ URL_ raw body)_ determines the correct secret (PLIVO_WEBHOOK_SECRET
or fallback toPLIVO_AUTH_TOKEN
)_ uses the SDK'splivo.validateV3Signature
method (HMAC-SHA256 based)_ logs errors/failures_ returns boolean. Added source citation.3. Building the API Layer (Express Routes)
Now_ let's create the Express application and define the API endpoint for sending bulk messages and the webhook endpoint for receiving delivery reports.
src/middleware/auth.js
API_KEY
environment variable to be set. If it's missing, it logs a critical error and returns a 500 status to prevent accidental unsecured deployment. It checks for thex-api-key
header and validates it.src/middleware/validateWebhook.js
captureRawBody
: Usesexpress.raw
to capture the raw body before JSON parsing. Added logging and basic error handling during capture. Changed type to*/*
to be more robust.validatePlivoWebhook
: UsesplivoService.validateWebhookSignature
. Reconstructs the URL, retrieves headers and the raw body. Returns appropriate error codes (400
for missing headers,403
for invalid signature,500
if body capture failed).src/routes/api.js
Explanation:
/api/bulk-sms
(POST):apiKeyAuth
.recipients
andmessage
.// PRODUCTION TODO:
comment emphasizing the need for robust E.164 and message length validation.plivoService.sendBulkSms
.Promise.allSettled
results to determine success/partial failure/total failure during the submission phase.202 Accepted
(all batches submitted) or207 Multi-Status
(some batches failed submission).try...catch
for unexpected errors./api/webhooks/plivo/delivery-report
(POST):validatePlivoWebhook
(which relies oncaptureRawBody
running first - seeapp.js
).express.json()
after validation to parse the body.// PRODUCTION TODO:
section outlining the necessary database/storage update logic (Find, Update, Idempotency, Logging, Retry considerations). This logic is essential for production but not implemented in this guide.Frequently Asked Questions (FAQ)
How many SMS messages can Plivo send per API request?
Plivo supports sending bulk SMS to up to 1,000 recipients in a single API call. For larger recipient lists, you need to implement batching logic to split your list into chunks of 1,000 or fewer recipients. The code in this guide automatically handles batch processing for any list size.
What phone number format does Plivo require for SMS?
Plivo requires all phone numbers to be in E.164 format. This international standard includes a plus sign (+), country code, and phone number without spaces or special characters. For example, a US number would be formatted as +14155552671, not (415) 555-2671.
How do I track SMS delivery status with Plivo?
Plivo sends delivery status updates to your webhook endpoint configured in the API call. Each delivery report includes the message UUID, recipient number, delivery status (delivered, failed, queued), error codes, and billing information. Store these updates in your database to track message delivery for each recipient.
How can I validate Plivo webhooks for security?
Plivo signs all webhooks using V3 signature validation with HMAC-SHA256. Your webhook endpoint should verify the
X-Plivo-Signature-V3
header by comparing it against a signature you compute using the Plivo Auth Token, nonce, request URL, and raw body. The Plivo Node.js SDK provides thevalidateV3Signature
method for this purpose.What are the SMS character limits for Plivo messages?
SMS character limits depend on encoding. GSM-7 encoding allows 160 characters per message segment, while UCS-2 encoding (used for Unicode characters and emojis) allows 70 characters per segment. Longer messages are automatically split into multiple segments, with 153 characters (GSM-7) or 67 characters (UCS-2) per segment for concatenated messages.
How do I handle failed SMS deliveries with Plivo?
When a message fails, Plivo's delivery report webhook includes an
ErrorCode
field indicating the failure reason. Common causes include invalid phone numbers, carrier rejections, or blocked content. Implement retry logic for transient errors, remove invalid numbers from your list, and log all failures for analysis. Store error codes in your database to identify patterns.Can I send SMS messages asynchronously with large recipient lists?
Yes, for lists with thousands or tens of thousands of recipients, implement a background job queue using BullMQ (Redis-based) or RabbitMQ. Your API endpoint accepts the request, adds a job to the queue with recipient data, and immediately returns a 202 Accepted status with a job ID. A separate worker process picks up jobs from the queue and processes them, preventing API timeouts.
What Node.js and Express versions work with Plivo SDK?
The Plivo Node.js SDK v4.x requires Node.js v18.x or later. Use Express.js v4.18.x or later for the web framework. These versions provide the necessary JavaScript features, security updates, and performance improvements for production SMS applications.
Conclusion
You've built a production-ready bulk SMS system using Node.js, Express, and the Plivo API. This implementation includes intelligent batch processing for unlimited recipient lists, secure webhook validation for delivery tracking, API key authentication, structured logging, and rate limiting.
Key takeaways:
Next steps for production:
The architecture you've built provides a solid foundation for reliable SMS communications at scale. Whether you're sending marketing campaigns, transactional notifications, or critical alerts, this system can grow with your needs while maintaining security and delivery tracking.
Related Resources:
Start testing your bulk SMS system in Plivo's sandbox environment, then move to production once you've verified webhook handling, batch processing, and error management work correctly for your use case.