code examples

Sent logo
Sent TeamMar 8, 2026 / code examples / Article

Plivo Node.js Express Integration: Send WhatsApp & SMS Messages

Complete tutorial for Plivo SMS and WhatsApp API integration with Node.js and Express. Step-by-step setup, code examples, webhooks, and template messaging.

Build WhatsApp & SMS Integration with Plivo, Node.js & Express

Learn how to integrate Plivo's SMS and WhatsApp APIs into your Node.js Express application. This comprehensive tutorial covers authentication, sending messages, receiving webhooks, and handling WhatsApp Business templates with complete code examples.

By the end of this tutorial, you'll have a functional Express application with API endpoints capable of triggering SMS and WhatsApp messages using Plivo's Node.js SDK, along with foundational elements for error handling, security, and configuration management.

Project Overview and Goals

What You'll Build:

Create a simple Node.js web server using the Express framework. This server exposes specific API endpoints:

  1. /send-sms: Accepts a destination phone number and message text, then uses Plivo to send an SMS message.
  2. /send-whatsapp: Accepts a destination phone number and necessary template information, then uses Plivo to send a pre-approved WhatsApp template message.
  3. /receive-sms: (Optional) An endpoint configured as a Plivo webhook to log incoming SMS messages sent to your Plivo number.

Problem Solved:

This application provides a foundational backend service for integrating programmatic SMS and WhatsApp messaging capabilities into larger applications. It solves the need for reliable, API-driven communication for use cases like notifications, alerts, two-factor authentication (2FA), or customer service interactions via WhatsApp.

Technologies Used:

  • Node.js: A JavaScript runtime environment enabling server-side execution. Chosen for its event-driven, non-blocking I/O model, well-suited for handling API requests and network operations efficiently. (https://nodejs.org/)
  • Express.js: A minimal and flexible Node.js web application framework. Chosen for its simplicity, robustness, and widespread adoption, making it easy to define routes and handle HTTP requests. Includes built-in middleware for parsing JSON (express.json()) and URL-encoded (express.urlencoded()) request bodies (version 4.16.0+). (https://expressjs.com/)
  • Plivo: A cloud communications platform providing APIs for SMS, WhatsApp, Voice, and more. Chosen for its reliable service, developer-friendly SDKs, and comprehensive API offerings. (https://www.plivo.com/)
  • Plivo Node.js SDK: A library provided by Plivo to simplify interaction with their APIs from Node.js applications. (https://github.com/plivo/plivo-node)
  • dotenv: A module to load environment variables from a .env file into process.env, facilitating secure credential management. (https://www.npmjs.com/package/dotenv)

System Architecture Diagram:

text
+-------------+       +------------------------+       +-----------------+       +------------------+      +-------------+
| User/Client | ----> | Node.js/Express App    | ----> | Plivo API       | ----> | SMS/WhatsApp     | ---> | Recipient   |
| (e.g. curl) |       | (localhost or Server)  |       | (Cloud Service) |       | Network          |      | Phone       |
+-------------+       | - /send-sms endpoint   |       +-----------------+       +------------------+      +-------------+
                      | - /send-whatsapp endpoint|
                      | - /receive-sms webhook |
                      | - Plivo SDK            |
                      +------------------------+
                                ^
                                | (Webhook for incoming SMS)
                                +--------------------------+

Prerequisites:

  • Node.js and npm (or yarn): Install on your development machine. Download from https://nodejs.org/.
  • A Plivo Account: Sign up for free at https://console.plivo.com/accounts/register/.
  • Plivo Auth ID and Auth Token: Find these on your Plivo console dashboard after signing up.
  • A Plivo Phone Number:
    • SMS: An SMS-enabled Plivo phone number. Purchase one from the Phone NumbersBuy Numbers section of the Plivo console. Sending to US/Canada requires a Plivo number. Other regions might allow Alphanumeric Sender IDs (check Plivo coverage).
    • WhatsApp: A Plivo number enabled for WhatsApp. This requires specific activation steps, often involving linking a Facebook Business Manager account and undergoing an approval process via Plivo/Meta, which can take time. Ensure you understand these prerequisites and potential delays. You'll also need pre-approved WhatsApp message templates for business-initiated conversations.
  • Basic Command Line/Terminal Knowledge: Familiarity with navigating directories and running commands.
  • (Optional) ngrok: A tool to expose your local server to the internet for testing webhooks (like receiving SMS). Download from https://ngrok.com/.

Expected Outcome:

A running Node.js Express application capable of sending SMS and WhatsApp messages via API calls, configured securely using environment variables.

Setting Up Your Node.js Plivo Project

Initialize your Node.js project and install the necessary dependencies for Plivo SMS and WhatsApp integration.

  1. Create Project Directory: Open your terminal or command prompt and create a new directory for the project, then navigate into it.

    bash
    mkdir plivo-node-express-guide
    cd plivo-node-express-guide
  2. Initialize Node.js Project: This command creates a package.json file, which tracks your project's metadata and dependencies. The -y flag accepts default settings.

    bash
    npm init -y
  3. Install Dependencies: Install Express for the web server, the Plivo SDK to interact with the API, and dotenv to manage environment variables. Modern Express includes body parsing middleware.

    bash
    npm install express plivo dotenv
  4. Create Project Structure: Set up a basic file structure.

    bash
    touch server.js .env .gitignore
    • server.js: Contains your main application code (Express server, routes, Plivo integration).
    • .env: Stores sensitive credentials like your Plivo Auth ID, Auth Token, and Plivo phone number. Never commit this to version control.
    • .gitignore: Specifies files and directories that Git should ignore.
  5. Configure .gitignore: Open .gitignore and add the following lines to prevent committing sensitive information and local dependencies:

    text
    # Dependencies
    node_modules
    
    # Environment Variables
    .env
    
    # Logs
    *.log
    
    # OS generated files
    .DS_Store
    Thumbs.db
  6. Configure .env File: Open the .env file and add your Plivo credentials and number. Replace the placeholder values with your actual credentials found on the Plivo Console dashboard and the Plivo number you purchased.

    dotenv
    # Plivo Credentials – Found on your Plivo Console dashboard
    PLIVO_AUTH_ID=YOUR_PLIVO_AUTH_ID
    PLIVO_AUTH_TOKEN=YOUR_PLIVO_AUTH_TOKEN
    
    # Plivo Number – Must be SMS-enabled (and WhatsApp-enabled for WhatsApp)
    # Use E.164 format (e.g., +14155551234)
    PLIVO_SENDER_ID=YOUR_PLIVO_PHONE_NUMBER_OR_SENDER_ID
    
    # Server Port (Optional, defaults to 3000)
    PORT=3000
    • PLIVO_AUTH_ID, PLIVO_AUTH_TOKEN: Essential for authenticating API requests.
    • PLIVO_SENDER_ID: The source number (or Alphanumeric Sender ID where supported) for outgoing messages. Must be in E.164 format (+countrycode)(number) for US/Canada SMS and generally for WhatsApp.
    • PORT: The port your local server will listen on.
  7. Initial server.js Setup: Open server.js and add the basic Express server setup, including loading environment variables using dotenv.

    javascript
    // server.js
    'use strict';
    
    // Load environment variables from .env file
    require('dotenv').config();
    
    const express = require('express');
    const plivo = require('plivo');
    
    // Basic validation for essential environment variables
    if (!process.env.PLIVO_AUTH_ID || !process.env.PLIVO_AUTH_TOKEN || !process.env.PLIVO_SENDER_ID) {
        console.error("Error: Plivo credentials (AUTH_ID, AUTH_TOKEN, SENDER_ID) not found in .env file.");
        console.error("Ensure your .env file is correctly configured.");
        process.exit(1); // Exit if credentials are missing
    }
    
    const app = express();
    const port = process.env.PORT || 3000; // Use port from .env or default to 3000
    
    // Middleware to parse JSON bodies (built-in with Express 4.16+)
    app.use(express.json());
    // Middleware to parse URL-encoded bodies (built-in with Express 4.16+)
    app.use(express.urlencoded({ extended: true }));
    
    // --- Plivo Client Initialization --- (Done after middleware, before routes)
    let client;
    try {
        // The Plivo SDK automatically reads PLIVO_AUTH_ID and PLIVO_AUTH_TOKEN from environment variables
        // when initialized with no arguments, as documented in the official SDK:
        // https://github.com/plivo/plivo-node#authentication
        client = new plivo.Client();
        console.log("Plivo client initialized.");
        console.log(`Plivo Auth ID configured: ${process.env.PLIVO_AUTH_ID.substring(0, 4)}...`); // Log partial ID for confirmation
        console.log(`Plivo Sender ID configured: ${process.env.PLIVO_SENDER_ID}`);
    } catch (error) {
        console.error("Error initializing Plivo client:", error.message);
        console.error("Ensure Plivo credentials in .env are correct.");
        process.exit(1);
    }
    
    // --- API Routes will be added here ---
    
    // Basic root route
    app.get('/', (req, res) => {
      res.send('Plivo SMS/WhatsApp Integration Server is running!');
    });
    
    // Export the app instance for testing purposes *before* starting the server listen
    module.exports = app;
    
    // Start the server only if this script is run directly (not required by a test runner)
    if (require.main === module) {
        app.listen(port, () => {
            console.log(`Server listening on port ${port}`);
        });
    }
    
    // Graceful shutdown handler (optional but recommended)
    process.on('SIGINT', () => {
        console.log('\nGracefully shutting down from SIGINT (Ctrl+C)');
        // Perform cleanup here if needed
        process.exit(0);
    });

    Explanation:

    • 'use strict';: Enforces stricter parsing and error handling in JavaScript.
    • require('dotenv').config();: Loads variables from the .env file into process.env. Call this early.
    • Environment Variable Check: Ensures critical Plivo credentials are loaded before proceeding.
    • express(): Creates an Express application instance.
    • express.json() / express.urlencoded(): Built-in middleware to parse incoming request bodies, making req.body available in your route handlers.
    • new plivo.Client(): Initializes the Plivo client. It automatically picks up credentials from process.env.
    • module.exports = app;: Exports the Express app instance so testing frameworks can import it.
    • if (require.main === module) { app.listen(...) }: Ensures the server only starts listening when the script is executed directly (node server.js), not when it's required by another module (like a test file).
    • process.on('SIGINT', ...): Catches the interrupt signal (Ctrl+C) for a cleaner shutdown message.

You now have a basic Express server ready. Test it by running node server.js in your terminal and visiting http://localhost:3000 (or your configured port) in your browser. You should see the message "Plivo SMS/WhatsApp Integration Server is running!". Press Ctrl+C to stop the server.

How to Send SMS and WhatsApp Messages with Plivo

Add the API endpoints to send messages using the Plivo SDK. The Plivo client was already initialized in server.js.

  1. Implement /send-sms Endpoint: Add the following route handler within server.js, between the Plivo client initialization and the module.exports = app; line:

    javascript
    // server.js
    // ... (previous code including client init)
    
    // --- API Routes ---
    
    /**
     * POST /send-sms
     * Sends an SMS message using Plivo.
     * Request Body (JSON):
     * {
     *   "to": "+1XXXXXXXXXX",  // Destination number in E.164 format
     *   "text": "Your message content here"
     * }
     */
    app.post('/send-sms', async (req, res) => {
        const { to, text } = req.body;
    
        // Basic Input Validation
        if (!to || !text) {
            console.error("Send SMS Error: Missing 'to' or 'text' in request body.");
            return res.status(400).json({ error: "Missing 'to' or 'text' in request body" });
        }
    
        // Validate E.164 format roughly (starts with +, followed by digits)
        if (!/^\+\d+$/.test(to)) {
             console.error(`Send SMS Error: Invalid 'to' number format: ${to}. Must be E.164.`);
            return res.status(400).json({ error: "Invalid 'to' number format. Use E.164 (e.g., +12223334444)." });
        }
    
        console.log(`Attempting to send SMS to: ${to}, Text: "${text}"`);
    
        try {
            const response = await client.messages.create({
                src: process.env.PLIVO_SENDER_ID, // Sender ID from .env
                dst: to,                           // Destination number from request
                text: text,                        // Message text from request
                // Optional: Add 'url' for delivery status callbacks
                // url: 'https://your-callback-url.com/sms-status'
            });
    
            console.log('Plivo Send SMS API Response:', response);
            res.status(202).json({
                message: "SMS send request accepted by Plivo.",
                details: response // Includes message UUID
            });
    
        } catch (error) {
            console.error('Plivo Send SMS API Error:', error); // Log the full error server-side
            res.status(error.statusCode || 500).json({
                error: "Failed to send SMS via Plivo.",
                // Avoid sending detailed internal Plivo errors (like error.message) to the client in production.
                details: "Internal server error processing the request." // More generic client message
            });
        }
    });
    
    // ... (Root route, module.exports, app.listen etc.)

    Explanation:

    • async (req, res) => { ... }: Defines an asynchronous route handler, enabling the use of await for the Plivo API call.
    • Input Validation: Checks for the presence of to and text and performs a basic check for E.164 format.
    • client.messages.create({...}): Calls the Plivo SDK method to send an SMS.
      • src: Your Plivo number/Sender ID from .env.
      • dst: The recipient's number from the request body.
      • text: The message content from the request body.
    • await: Pauses execution until the client.messages.create promise resolves or rejects.
    • Success Response (res.status(202)): Returns a 202 Accepted status, indicating the request was received, along with the Plivo API response (which includes the unique message_uuid). Sending is asynchronous.
    • Error Handling (catch (error)): Catches errors during the API call. Logs the full error server-side (console.error) and returns an appropriate HTTP status code (using Plivo's status code if available, otherwise 500) and a generic error message to the client to avoid leaking internal details.
  2. Implement /send-whatsapp Endpoint: Add this route handler below the /send-sms endpoint. Note: Sending WhatsApp messages, especially business-initiated ones, requires using pre-approved templates. This example assumes you have a template approved in your Plivo account associated with your WhatsApp-enabled sender ID.

    javascript
    // server.js
    // ... (previous code including send-sms)
    
    /**
     * POST /send-whatsapp
     * Sends a WhatsApp message using a pre-approved Plivo template.
     * Request Body (JSON):
     * {
     *   "to": "+1XXXXXXXXXX",  // Destination number in E.164 format
     *   "templateName": "hello_world", // Name of the approved template
     *   "templateLanguage": "en_US", // Language code of the template (e.g., 'en_US', 'es', 'fr')
     *   "templateParams": [ // Optional: parameters for template placeholders
     *     { "type": "text", "text": "Value1" },
     *     { "type": "text", "text": "Value2" }
     *     // Add more parameters as needed by your template
     *   ]
     * }
     * Note: Template structure follows Plivo's WhatsApp messaging format documented at:
     *       https://github.com/plivo/plivo-node#whatsapp-messaging
     *       Templates support header, body, footer, and button components.
     */
    app.post('/send-whatsapp', async (req, res) => {
        const { to, templateName, templateLanguage, templateParams } = req.body;
    
        // Basic Input Validation
        if (!to || !templateName || !templateLanguage) {
            console.error("Send WhatsApp Error: Missing 'to', 'templateName', or 'templateLanguage' in request body.");
            return res.status(400).json({ error: "Missing 'to', 'templateName', or 'templateLanguage'" });
        }
        if (!/^\+\d+$/.test(to)) {
             console.error(`Send WhatsApp Error: Invalid 'to' number format: ${to}. Must be E.164.`);
            return res.status(400).json({ error: "Invalid 'to' number format. Use E.164." });
        }
    
        console.log(`Attempting to send WhatsApp template '${templateName}' (${templateLanguage}) to: ${to}`);
    
        // Construct the template object for the Plivo API
        // Format follows official Plivo Node SDK documentation
        const template = {
            name: templateName,
            language: templateLanguage // Accepts language code directly (e.g., "en_US")
        };
    
        // Add components if parameters are provided (this structure is common for body params)
        // For header media, buttons, or location parameters, refer to:
        // https://github.com/plivo/plivo-node#whatsapp-messaging
        if (templateParams && Array.isArray(templateParams) && templateParams.length > 0) {
            template.components = [{
                type: "body", // Assuming params are for the body. Adjust for header/buttons.
                parameters: templateParams
            }];
            console.log("Including template parameters:", JSON.stringify(templateParams));
        }
    
        try {
            const response = await client.messages.create({
                src: process.env.PLIVO_SENDER_ID, // Must be a WhatsApp-enabled Plivo number
                dst: to,
                type: 'whatsapp', // Specify message type as WhatsApp
                template: template // Pass the structured template object
                // Optional: Add 'url' for delivery status callbacks
                // url: 'https://your-callback-url.com/whatsapp-status'
            });
    
            console.log('Plivo Send WhatsApp API Response:', response);
            res.status(202).json({
                message: "WhatsApp send request accepted by Plivo.",
                details: response
            });
    
        } catch (error) {
            console.error('Plivo Send WhatsApp API Error:', error);
            // Log the detailed error structure from Plivo if available for debugging
            if (error.response && error.response.data) {
                 console.error('Plivo Error Details:', JSON.stringify(error.response.data, null, 2));
            }
            res.status(error.statusCode || 500).json({
                error: "Failed to send WhatsApp message via Plivo.",
                // Consider providing a less detailed/generic error message to the client in production
                details: error.message || "Internal server error processing the request.",
                plivoErrorHint: error.response?.data?.error // Send specific Plivo error hint if helpful, but be cautious
            });
        }
    });
    
    // ... (Root route, module.exports, app.listen etc.)

    Explanation:

    • Input Validation: Checks for required fields (to, templateName, templateLanguage).
    • Template Object: Constructs the template object following the official Plivo Node SDK documentation format.
    • client.messages.create({...}): Similar to SMS, but with type: 'whatsapp' and the template object.
    • src: Must be a Plivo number explicitly enabled for WhatsApp.
    • Error Handling: Similar to SMS, logs detailed errors server-side but advises caution about sending detailed Plivo errors back to the client.
  3. (Optional) Implement /receive-sms Webhook Endpoint: This endpoint receives calls from Plivo whenever an SMS is sent to your Plivo number. Add this route handler below the /send-whatsapp endpoint.

    javascript
    // server.js
    // ... (previous code, including send-whatsapp)
    
    /**
     * POST /receive-sms
     * Plivo Webhook Endpoint for Incoming SMS Messages.
     * Plivo sends data as URL-encoded form data by default.
     * Note: Check the official Plivo documentation for the exact field names and
     *       full payload structure for incoming message webhooks, as they may vary slightly
     *       or include additional useful fields.
     */
    app.post('/receive-sms', (req, res) => {
        // Plivo sends data typically as application/x-www-form-urlencoded
        // Common fields (verify with Plivo docs):
        const from_number = req.body.From;
        const to_number = req.body.To; // Your Plivo number
        const text = req.body.Text;
        const message_uuid = req.body.MessageUUID; // Unique ID for the incoming message
    
        if (!from_number || !to_number || !message_uuid) { // Text might be empty for MMS etc.
            console.warn("Receive SMS Webhook: Received incomplete essential data:", req.body);
            // Respond to Plivo that the request was bad
            return res.status(400).send("Incomplete essential data received.");
        }
    
        console.log(`--- Incoming SMS Received ---`);
        console.log(`From: ${from_number}`);
        console.log(`To: ${to_number}`);
        console.log(`Text: "${text || '(No Text Body)'}"`); // Handle potentially empty text
        console.log(`Message UUID: ${message_uuid}`);
        console.log(`Full Payload:`, req.body); // Log entire payload for inspection
        console.log(`-----------------------------`);
    
        // Add logic here: store message in DB, trigger auto-reply, etc.
    
        // Acknowledge receipt to Plivo. Sending an empty 200 OK is sufficient.
        // You could also respond with Plivo XML for actions like sending a reply.
        res.status(200).send("Message received.");
        // Example: Send a reply using Plivo XML (requires setting content type)
        // res.setHeader('Content-Type', 'application/xml');
        // const response = new plivo.Response();
        // response.addMessage("Thanks for your message!");
        // res.send(response.toXML());
    });
    
    // ... (Root route, module.exports, app.listen etc.)

    Explanation:

    • Webhook Nature: Designed to receive calls from Plivo.
    • req.body: Contains incoming SMS details. Note that express.urlencoded handles the typical format.
    • Documentation Note: Added a comment advising developers to check official Plivo docs for the exact payload structure and field names.
    • Logging: Logs key details and the full payload for easier debugging.
    • Acknowledgement: Sends 200 OK back to Plivo.

Building a Complete API Layer

Our core functionality established the API endpoints using Express. Let's refine this by adding documentation and testing examples.

API Endpoint Documentation:

  • POST /send-sms

    • Description: Sends a standard SMS message.
    • Request Body: application/json
      json
      {
        "to": "+1XXXXXXXXXX",  // E.164 format REQUIRED
        "text": "Your message content" // REQUIRED
      }
    • Success Response (202 Accepted): application/json
      json
      {
        "message": "SMS send request accepted by Plivo.",
        "details": {
          "message": "message(s) queued",
          "message_uuid": ["xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"],
          "api_id": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy"
        }
      }
    • Error Responses:
      • 400 Bad Request: Missing fields, invalid number format.
        json
        { "error": "Missing 'to' or 'text' in request body" }
        json
        { "error": "Invalid 'to' number format. Use E.164 (e.g., +12223334444)." }
      • 500 Internal Server Error (or other Plivo-specific code like 401, 404): Plivo API error or internal server issue.
        json
        {
          "error": "Failed to send SMS via Plivo.",
          "details": "Internal server error processing the request." // Generic message
        }
  • POST /send-whatsapp

    • Description: Sends a WhatsApp message using a pre-approved template. Consult Plivo docs for template structure details.
    • Request Body: application/json
      json
      {
        "to": "+1XXXXXXXXXX",           // E.164 format REQUIRED
        "templateName": "your_template_name", // REQUIRED
        "templateLanguage": "en_US",    // REQUIRED (e.g., 'en_US', 'es', 'fr')
        "templateParams": [             // OPTIONAL - Array matching placeholders
          { "type": "text", "text": "Dynamic Value 1" },
          { "type": "text", "text": "Another Value" }
          // Use appropriate types ('media', 'location', etc.) if needed per Plivo docs
        ]
      }
    • Success Response (202 Accepted): application/json
      json
      {
        "message": "WhatsApp send request accepted by Plivo.",
        "details": {
          "message": "message(s) queued",
          "message_uuid": ["xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"],
          "api_id": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy"
        }
      }
    • Error Responses:
      • 400 Bad Request: Missing fields, invalid number format.
        json
        { "error": "Missing 'to', 'templateName', or 'templateLanguage'" }
      • 500 Internal Server Error (or other Plivo code): Plivo API error (e.g., template not found, number not WhatsApp enabled, parameter mismatch).
        json
        {
          "error": "Failed to send WhatsApp message via Plivo.",
          "details": "Internal server error processing the request." // Generic message
          "plivoErrorHint": { /* Potential sanitized hint from Plivo, use cautiously */ }
        }
  • POST /receive-sms (Webhook)

    • Description: Endpoint for Plivo to send data about incoming SMS messages. Expects application/x-www-form-urlencoded data from Plivo. Check Plivo docs for exact payload.
    • Expected Request Body from Plivo: (Form data, common keys - verify with docs)
      • From: Sender's number
      • To: Your Plivo number
      • Text: Message content (can be empty)
      • Type: sms
      • MessageUUID: Unique ID
      • ... (other potential fields like TotalRate, Units, MediaContentTypes, MediaUrls)
    • Success Response: 200 OK (Text or XML response possible for actions)
    • Error Response: 400 Bad Request (Text, if essential data is incomplete/invalid)

Testing with curl:

Replace placeholders (YOUR_SERVER_URL, +1RECIPIENTNUMBER, YOUR_TEMPLATE_NAME, etc.) with actual values. Ensure your server is running (node server.js).

  1. Test Sending SMS:

    bash
    curl -X POST YOUR_SERVER_URL/send-sms \
         -H "Content-Type: application/json" \
         -d '{
               "to": "+1RECIPIENTNUMBER",
               "text": "Hello from Node.js and Plivo via curl!"
             }'
  2. Test Sending WhatsApp (Template without parameters): (Requires an approved template like hello_world)

    bash
    curl -X POST YOUR_SERVER_URL/send-whatsapp \
         -H "Content-Type: application/json" \
         -d '{
               "to": "+1RECIPIENTNUMBER",
               "templateName": "hello_world",
               "templateLanguage": "en_US"
             }'
  3. Test Sending WhatsApp (Template with parameters): (Requires an approved template with placeholders, e.g., order_confirmation with body Your order {{1}} is confirmed. Estimated delivery: {{2}}.)

    bash
    curl -X POST YOUR_SERVER_URL/send-whatsapp \
         -H "Content-Type: application/json" \
         -d '{
               "to": "+1RECIPIENTNUMBER",
               "templateName": "order_confirmation",
               "templateLanguage": "en_US",
               "templateParams": [
                 { "type": "text", "text": "#12345" },
                 { "type": "text", "text": "April 25, 2025" }
               ]
             }'

Testing Receiving SMS (Webhook):

Testing webhooks requires exposing your local server to the public internet.

  1. Start your server: node server.js
  2. Start ngrok: Expose the port your server is running on (e.g., 3000).
    bash
    ngrok http 3000
  3. Copy the ngrok HTTPS URL: It will look like https://<random_string>.ngrok.io.
  4. Configure Plivo Message URL:
    • Go to your Plivo Console -> Phone Numbers -> Your Numbers.
    • Select the Plivo number you are using (PLIVO_SENDER_ID).
    • Under "Messaging Application", choose "XML Application".
    • In the "Message URL" field, paste your ngrok HTTPS URL followed by /receive-sms. Example: https://<random_string>.ngrok.io/receive-sms.
    • Ensure the HTTP Method is set to POST.
    • Click "Update Number".
  5. Send an SMS: From your personal phone (or another service), send an SMS message to your Plivo number.
  6. Check ngrok and Server Logs:
    • The ngrok terminal window should show a POST /receive-sms request with a 200 OK response.
    • Your node server.js terminal should show the logs from the /receive-sms handler, displaying the message details.

Remember to stop ngrok (Ctrl+C) when finished testing. The ngrok URL is temporary. For production, you'll use your server's public URL.

Integrating with Third-Party Services (Plivo)

This section consolidates the specific steps for Plivo integration.

Configuration Steps:

  1. Sign Up/Log In: Access the Plivo Console: https://console.plivo.com/
  2. Obtain Credentials:
    • Navigate to the main Dashboard (the homepage after login).
    • Locate the Auth ID and Auth Token under the "Account" section.
    • Action: Copy these values and paste them into your .env file as PLIVO_AUTH_ID and PLIVO_AUTH_TOKEN.
  3. Purchase/Configure Phone Number:
    • Navigate to Phone Numbers -> Buy Numbers.
    • Search for numbers based on country, capabilities (SMS, MMS, Voice, WhatsApp), and type (Local, Toll-Free, Mobile).
    • Select a number with SMS capabilities. If you need WhatsApp, ensure it also lists WhatsApp or can be enabled for it.
    • Complete the purchase process.
    • Action: Copy the purchased number (in E.164 format, e.g., +14155551234) and paste it into your .env file as PLIVO_SENDER_ID.
  4. Enable WhatsApp (If Needed):
    • WhatsApp enablement often involves an additional setup process. Navigate to Messaging -> WhatsApp in the Plivo Console.
    • Follow the onboarding instructions, which typically involve linking your Facebook Business Manager account and submitting your Plivo number for approval by WhatsApp/Meta. This process can take time.
    • Action: Ensure the number set in PLIVO_SENDER_ID is successfully activated for WhatsApp before attempting to use the /send-whatsapp endpoint.

FAQ: Plivo WhatsApp & SMS Integration

How do I initialize the Plivo Node.js SDK with environment variables?

Initialize the Plivo client with new plivo.Client() without arguments. The SDK automatically reads PLIVO_AUTH_ID and PLIVO_AUTH_TOKEN from environment variables when initialized this way, as documented in the official Plivo Node SDK. Store these credentials in a .env file and load them using the dotenv package before initializing the client.

What format do phone numbers need to be in for Plivo SMS and WhatsApp?

Plivo requires phone numbers in E.164 format for both SMS and WhatsApp messaging. This format includes a plus sign (+) followed by the country code and phone number without spaces or special characters. For example: +14155551234 for a US number. The article includes regex validation (/^\+\d+$/) to ensure proper formatting before sending messages.

How do I send WhatsApp template messages with Plivo?

Send WhatsApp template messages using the client.messages.create() method with type: 'whatsapp' and a template object. The template must be pre-approved in your Plivo account. The basic structure is:

javascript
const template = {
  name: "template_name",
  language: "en_US",  // Language code
  components: [{      // Optional: for dynamic parameters
    type: "body",
    parameters: [{ type: "text", text: "value" }]
  }]
};

Refer to Plivo's WhatsApp messaging documentation for header, button, and media parameters.

Can I receive incoming SMS messages with Plivo webhooks?

Yes, configure a webhook endpoint to receive incoming SMS messages. In the Plivo Console, navigate to your phone number settings and set the Message URL to your publicly accessible endpoint (e.g., https://yourdomain.com/receive-sms). Plivo sends incoming message data as application/x-www-form-urlencoded with fields like From, To, Text, and MessageUUID. Use ngrok for local testing to expose your development server.

What HTTP status code does Plivo return for successful message requests?

Plivo returns HTTP 202 Accepted for successful message send requests. This indicates the message has been accepted for delivery but hasn't been sent yet, as message delivery is asynchronous. The response includes a message_uuid that you can use to track delivery status. For errors, Plivo returns appropriate HTTP status codes (400 for bad requests, 401 for authentication errors, 500 for server errors).

How do I handle Plivo API errors in Node.js Express applications?

Wrap Plivo API calls in try-catch blocks and log detailed errors server-side using console.error(). Return generic error messages to clients to avoid leaking sensitive information. Access Plivo-specific error details via error.statusCode, error.message, and error.response.data. For production, implement proper error monitoring and return user-friendly messages while logging full error details for debugging.

What are the prerequisites for enabling WhatsApp on a Plivo number?

Enabling WhatsApp on a Plivo number requires linking a Facebook Business Manager account and submitting your number for approval through the Plivo Console (Messaging → WhatsApp section). This approval process is managed by Meta/WhatsApp and can take several days. You'll also need pre-approved WhatsApp message templates before you can send business-initiated messages. Test thoroughly using approved templates before deploying to production.