Frequently Asked Questions
Create a Fastify API endpoint that accepts an array of destination phone numbers and a message body. This endpoint uses the Plivo Node.js SDK to send a single API request to Plivo, broadcasting the SMS to all recipients simultaneously. This method improves efficiency compared to sending individual messages.
Plivo's bulk messaging API allows sending a single message to thousands of recipients with one API call, reducing latency and overhead compared to looping through individual messages. This approach is crucial for efficient and scalable SMS broadcasting.
Fastify is a high-performance Node.js web framework known for its speed and extensibility. Its efficiency minimizes overhead, making it ideal for handling the demands of a high-throughput SMS broadcasting service.
Use bulk SMS when sending the same message to many recipients. This method is significantly more efficient and prevents hitting API rate limits, especially when dealing with thousands of numbers. Individual messages are better for personalized communications.
Use `npm install fastify plivo dotenv fastify-env` to install the required packages. For development, add `npm install --save-dev nodemon pino-pretty` for automatic server restarts and readable logs. Remember to replace placeholders with your actual Plivo Auth ID, Token, and phone number.
`dotenv` loads environment variables from a `.env` file, which stores sensitive credentials like your Plivo Auth ID and Token. `fastify-env` adds schema-based validation for these environment variables, ensuring required values are present and correctly formatted.
Create directories for routes (`src/routes`), services (`src/services`), and a main server file (`src/server.js`). The routes define API endpoints, the services encapsulate interaction with Plivo, and the server file sets up the application. Add a `.env` file for credentials and a `.gitignore` for security best practices.
You need Node.js v18 or later, npm or yarn, a Plivo account, a Plivo phone number enabled for SMS, and your Plivo Auth ID and Auth Token. Remember to keep these credentials secure and never commit them to version control.
Implement detailed logging at both the service and route layers, including specific error messages from Plivo. For enhanced resilience, integrate retry mechanisms with exponential backoff for transient errors like network issues or rate limiting, using libraries like `async-retry`.
Create a `.env` file in your project root. Add your `PLIVO_AUTH_ID`, `PLIVO_AUTH_TOKEN`, and `PLIVO_SOURCE_NUMBER` (in E.164 format). Never commit this file to version control. Use environment variable management tools provided by your hosting platform for production environments.
The `sendBulkSms` function uses a `Set` to automatically remove duplicate phone numbers from the provided list before sending the bulk message, ensuring that each recipient receives the SMS only once. This prevents sending unnecessary duplicates and is handled internally.
The `PLIVO_SOURCE_NUMBER` is your Plivo phone number that will be used to send the bulk SMS messages. You can find it in your Plivo console under Messaging -> Phone Numbers. Ensure this number is enabled for SMS and is in E.164 format (e.g. +14155552671).
Yes, Plivo supports sending SMS to international numbers, but ensure your Plivo phone number is set up to send to your target regions. When adding numbers to your list, make sure they are in international E.164 formatting. Consider checking Plivo's documentation for regional regulations and number formatting.
The .env file stores sensitive credentials like API keys and tokens. Committing it to Git poses a security risk, as it could expose those credentials to unauthorized users, including if your repository is public or shared. It is crucial for security to add .env to your .gitignore.
Leverage the power of Fastify's performance and Plivo's efficient bulk messaging API to build a scalable service capable of sending a single SMS message to thousands of recipients with a single API request. This guide provides a complete walkthrough, from project setup to deployment and monitoring.
We'll build a simple but robust API endpoint that accepts a list of phone numbers and a message, then utilizes Plivo to broadcast the SMS. This approach is significantly more efficient than sending individual messages in a loop, reducing latency and API call overhead.
Project Overview and Goals
Problem: Sending the same SMS message to numerous recipients individually is slow, inefficient, and can easily hit API rate limits.
Solution: Create a Fastify API endpoint (
POST /broadcast
) that accepts a list of destination phone numbers and a message body. This endpoint will use the Plivo Node.js SDK to send the message to all recipients via Plivo's bulk messaging feature (a single API call).Technologies:
dotenv
&fastify-env
: For managing environment variables securely and reliably.Architecture:
Outcome: A functional Fastify application with a single endpoint (
/broadcast
) capable of accepting bulk SMS requests and dispatching them via Plivo.Prerequisites:
1. Setting up the Project
Let's initialize our Node.js project and install the necessary dependencies. These instructions are OS-agnostic.
Create Project Directory:
Initialize npm Project:
This creates a
package.json
file.Install Dependencies:
fastify
: The core web framework.plivo
: The official Plivo Node.js SDK.dotenv
: Loads environment variables from a.env
file.fastify-env
: Schema-based environment variable validation for Fastify.Install Development Dependencies (Optional but Recommended):
nodemon
: Automatically restarts the server on file changes during development.pino-pretty
: Formats Pino logs for readability during development.Configure
package.json
Scripts: Openpackage.json
and add/modify thescripts
section:(Note: The
dev
script pipes output topino-pretty
for readable logs during development).Create Project Structure: Organize your code for clarity and maintainability.
src/
: Contains all source code.src/routes/
: Holds route definitions.src/services/
: Contains business logic interacting with external services (like Plivo).src/server.js
: The main application entry point..env
: Stores sensitive credentials and configuration (DO NOT commit this file)..gitignore
: Specifies files/directories to be ignored by Git.Configure
.gitignore
: Add the following lines to your.gitignore
file to prevent committing sensitive information and unnecessary files:Set Up Environment Variables (
.env
): Open the.env
file and add your Plivo credentials and server configuration.PLIVO_AUTH_ID
: Your Plivo Account Auth ID. Find this on the overview page of your Plivo Console.PLIVO_AUTH_TOKEN
: Your Plivo Account Auth Token. Also on the overview page.PLIVO_SOURCE_NUMBER
: A Plivo phone number you own (in E.164 format, e.g.,+14155552671
) enabled for SMS. Find this under Phone Numbers -> Your Numbers in the console.HOST
: The host address the server should listen on (e.g.,0.0.0.0
to listen on all available network interfaces, or127.0.0.1
for localhost only).PORT
: The port number for the server (e.g.,3000
).LOG_LEVEL
: Controls logging verbosity (e.g.,info
,debug
,warn
,error
). Fastify uses Pino logger.Replace the placeholder values with your actual Plivo credentials and desired settings.
Initialize Basic Fastify Server (
src/server.js
): Set up the basic server structure and configurefastify-env
to load and validate our environment variables.dotenv
to load the.env
file before Fastify initializes fully.fastify-env
validates the loaded environment variables againstenvSchema
. This ensures critical configuration is present and correctly formatted (like the E.164 pattern for the phone number).fastify
instance withplivoConfig
to make credentials easily accessible in services/routes without explicit passing./health
endpoint is added for monitoring./api/v1
prefix for better API versioning.pino-pretty
is conditionally used only whenNODE_ENV
is notproduction
, ensuring readable logs in development and efficient JSON logs in production.Run the Server (Development):
You should see pretty-printed output indicating the server is listening on the configured host and port (e.g.,
http://0.0.0.0:3000
). Iffastify-env
encounters missing or invalid variables, it will throw an error. To run in production mode (for JSON logs):NODE_ENV=production npm start
.2. Implementing Core Functionality (Plivo Service)
Now, let's create the service responsible for interacting with the Plivo API.
Create Plivo Service (
src/services/plivoService.js
): This service initializes the Plivo client and exposes a function to send bulk messages.plivoClient
to act as a singleton – the client is initialized only once.initializePlivoClient
function handles the creation_ taking config and logger from Fastify.sendBulkSms
performs input validation (non-empty destinations array_ non-empty message).new Set()
. Crucially_ it joins the unique destination numbers with the<
delimiter as required by Plivo's bulk API.MAX_RECIPIENTS_PER_REQUEST
constant. Note: The warning message now explicitly states that automatic batching is not implemented in this code.plivoClient.messages.create
with the source number_ the<
-separated destination string_ and the message text.url
parameter for status callbacks – implementing webhooks is a vital next step for production monitoring but beyond this initial setup scope.3. Building the API Layer (Broadcast Route)
Let's create the Fastify route that exposes our bulk sending functionality.
Define Route and Schema (
src/routes/broadcast.js
): This file defines thePOST /broadcast
endpoint_ validates the incoming request body_ and calls the Plivo service.broadcastSchema
using Fastify's schema validation capabilities. This automatically validates therequest.body
against the defined structure, types, and constraints (likeminItems
,minLength
, and the E.164pattern
). If validation fails, Fastify automatically sends a 400 Bad Request response.destinations
andmessage
from the validatedrequest.body
.sendBulkSms
service function, passing the necessary data, the Plivo configuration (fastify.plivoConfig
), and the request-specific logger (request.log
) for contextual logging.Register Route in Server: Ensure the route is registered in
src/server.js
(already done in Step 1.9). The linefastify.register(broadcastRoutes, { prefix: '/api/v1' });
handles this.Test the Endpoint: Restart your server (
npm run dev
). You can now test the endpoint usingcurl
or a tool like Postman.Using
curl
: Replace placeholders with your actual server address, valid E.164 numbers (use your own test numbers!), and a message.Expected Success Response (Example):
(Note: Plivo's actual response structure for
message_uuid
might vary slightly; consult their documentation. The service filters duplicates before sending, so only 2 unique numbers are sent here).Example Error Response (Validation Failure): If you send invalid data (e.g., missing
message
or invalid phone number format):Example Error Response (Server/Plivo Error): If Plivo credentials are wrong or the API call fails:
4. Integrating with Plivo (Credentials & Setup)
We've already integrated the SDK, but let's explicitly cover obtaining and securing credentials.
Obtain Plivo Auth ID and Auth Token:
Obtain Plivo Source Number:
+14155552671
).Secure Storage:
.env
file:.env
is listed in your.gitignore
file to prevent accidentally committing secrets to version control.Fallback Mechanisms:
5. Error Handling, Logging, and Retry Mechanisms
We've built basic error handling and logging. Let's enhance it.
Consistent Error Handling:
plivoService.js
): Catches specific Plivo API errors, logs detailed information (including Plivo error messages/codes if available), and throws a standardizedError
object.broadcast.js
): Catches errors propagated from the service layer. Logs the error with request context (request.id
,request.log
). Sends an appropriate HTTP status code (4xx for client errors it can detect, 5xx for server/dependency errors) and a generic error message to the client, avoiding leaking internal details. Fastify's schema validation automatically handles 400 errors for invalid input.fastify.setErrorHandler((error, request, reply) => { ... })
. This can catch unexpected errors and ensure a consistent error response format.Logging:
LOG_LEVEL
env var (info
,debug
,warn
,error
,fatal
) to control verbosity.info
is good for production,debug
for development.reqId
into logs. We passrequest.log
to the service layer (sendBulkSms
) so service-level logs also contain the request ID, making it easy to trace a single request's lifecycle through logs.pino-pretty
is used for development readability. In production (NODE_ENV=production
), output defaults to JSON logs for easier parsing by log aggregation systems (e.g., ELK stack, Datadog, Loki).info
)warn
orinfo
, Fastify handles response)info
/debug
)info
)error
)error
)debug
)Retry Mechanisms:
plivoClient.messages.create
. Libraries likeasync-retry
orp-retry
are excellent for this.Example using
async-retry
(Conceptual):First, install the library:
Then, modify the service conceptually: