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.
Production-Ready Bulk SMS with Node.js, Express, and Plivo
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:
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.plivo
: The official Plivo Node.js SDK.dotenv
: To load environment variables from a.env
file.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.winston
: For structured logging.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
).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 behavior.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.sendBulkSmsBatch
: Sends a single batch, joins recipients with<
_ constructs the webhook URL_ callsclient.messages.create
_ logs success/failure_ and clarifies the role ofmessageUuid
vs. DLRs for tracking.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
_ logs errors/failures_ returns boolean.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.