code examples

Sent logo
Sent TeamMay 3, 2025 / code examples / Article

How to Send SMS with Plivo in Node.js: Step-by-Step Tutorial (2025)

Learn how to integrate Plivo SMS API with Node.js Express. Step-by-step tutorial covering authentication, phone number validation, error handling, and deployment. Includes Express 4.x and Plivo SDK 4.x code examples.

Send SMS with Plivo and Node.js Express: Complete Tutorial

This guide provides a step-by-step walkthrough for building a simple yet robust Node.js application using the Express framework to send SMS messages via the Plivo API. We'll cover everything from project setup and configuration to implementing the core sending logic, handling errors, and testing the endpoint.

Learn how to send SMS programmatically using Plivo's messaging API with Node.js and Express. This tutorial demonstrates SMS integration for authentication codes, notifications, alerts, and marketing campaigns.

Estimated Time: 20-30 minutes for complete setup and testing. Add 10-15 minutes if this is your first time working with Plivo or configuring environment variables.

Common Use Cases:

  • OTP (One-Time Password) delivery for user authentication
  • Appointment reminders and notifications
  • Order confirmations and shipping updates
  • Alert systems and emergency notifications
  • Marketing campaigns and promotional messages

By the end of this tutorial, you will have a functional Express API endpoint capable of accepting requests to send SMS messages. This forms a foundational building block for integrating SMS notifications, alerts, or communication features into larger applications.

Technologies Used:

  • Node.js: A JavaScript runtime environment for building server-side applications.
  • Express.js: A minimal and flexible Node.js web application framework.
  • Plivo: A cloud communications platform providing APIs for SMS, voice, and more.
  • dotenv: A module to load environment variables from a .env file into process.env.

Version Compatibility Matrix:

ComponentTested VersionMin VersionNotes
Node.jsv20.x, v22.xv18.xv18.x minimum for async/await and ES6+ features
Express4.18.x4.17.0Express 5.x in beta; use 4.x for production
Plivo SDK4.14.x4.0.0Major API changes in v4.x vs v3.x
dotenv16.3.x16.0.0Stable across 16.x versions

Prerequisites:

Before you start integrating Plivo SMS API with Node.js, ensure you have:

  • Node.js and npm (or yarn): Installed on your development machine. You can download them from nodejs.org.
    • Recommended: Node.js v20.x (Maintenance LTS - Iron) or v22.x (Active LTS - Jod) as of January 2025
    • Minimum: Node.js v18.x or higher for ES6+ support and modern async/await features
    • Verify your installation:
      bash
      node --version  # Should output v18.x or higher
      npm --version   # Should output 8.x or higher
    • Package Manager Choice: This tutorial uses npm (bundled with Node.js). Yarn is an alternative with faster installs and better dependency resolution. Use npm for simplicity; switch to Yarn if you need workspaces or prefer its lockfile format.
  • Plivo Account: Sign up for a free Plivo account at plivo.com. For pricing details, see our Plivo SMS pricing guide.
  • Plivo Auth ID and Auth Token: Found on your Plivo console dashboard upon logging in at console.plivo.com/dashboard.
    • Navigate to: DashboardAccount section → Copy Auth ID and Auth Token
  • A Plivo Phone Number: You need an SMS-enabled Plivo phone number to act as the sender (src). You can purchase one from the Phone NumbersBuy Numbers section of the Plivo console.
    • Important: Sending SMS to the US and Canada requires using a Plivo phone number as the sender ID. Other countries may support alphanumeric sender IDs (check Plivo documentation and local regulations).
    • Trial Account Limitation: If using a Plivo trial account, you can only send SMS messages to phone numbers verified in your Plivo console under Phone NumbersSandbox Numbers.
    • Pricing (as of January 2025, source: Plivo Pricing):
      • Phone Number Rental: US local/mobile numbers: $0.50/month; US toll-free: $1.00/month
      • SMS Rates (US): Outbound long code: starts at $0.0070/SMS; Toll-free: $0.0072/SMS
      • Global rates vary by country: Check Plivo SMS Pricing for specific regions
      • Note: Trial accounts receive initial credits; paid accounts use pay-as-you-go billing

Setting Up Your Node.js Project for SMS Integration

Estimated Time: 5-7 minutes

Let's start by creating our project directory and initializing it with npm.

  1. Create Project Directory: Open your terminal or command prompt and run:

    bash
    mkdir node-plivo-sms
    cd node-plivo-sms
  2. Initialize Node.js Project: This creates a package.json file to manage dependencies and project metadata.

    bash
    npm init -y
    • The -y flag accepts all default prompts automatically. Omit -y for interactive mode where you can customize project name, version, description, entry point, etc.
  3. Install Dependencies: We need Express for the web server, the Plivo Node.js SDK to interact with the API, and dotenv to manage environment variables securely.

    bash
    npm install express@4.18.2 plivo@4.14.0 dotenv@16.3.1
    • Pinned vs Latest Versions: This tutorial pins specific versions for reproducibility. For new projects, consider using latest versions: npm install express plivo dotenv. However, pinned versions ensure compatibility with this guide's code examples and prevent breaking changes from automatic updates.
    • Why these versions? Express 4.18.2 and Plivo 4.14.0 are stable production releases with extensive documentation. Plivo SDK 4.x introduced async/await support (v3.x used callbacks).
  4. Project Structure: Create the basic files and directories. Your structure should look like this:

    node-plivo-sms/ ├── node_modules/ ├── .env ├── .gitignore ├── package.json ├── package-lock.json └── server.js

    Quick setup commands:

    bash
    touch .env .gitignore server.js
  5. Configure .gitignore: Create a file named .gitignore in the project root and add the following lines to prevent committing sensitive information and unnecessary files:

    plaintext
    # .gitignore
    
    # Node dependencies
    node_modules/
    
    # Environment variables
    .env
    
    # Logs (Optional but good practice)
    logs/
    *.log
    npm-debug.log*
    yarn-debug.log*
    yarn-error.log*
    
    # Optional editor directories
    .idea/
    .vscode/
    *.swp
    • Why? The .env file will contain your secret API credentials, which should never be committed to version control. node_modules contains installed dependencies, which can be reinstalled using npm install.

Configure Plivo API Credentials and Environment Variables

Securely storing your Plivo credentials is crucial. We'll use environment variables managed by the dotenv package.

  1. Create .env file: In the root of your project, create a file named .env.

  2. Add Plivo Credentials: Open the .env file and add your Plivo Auth ID, Auth Token, and your Plivo phone number. Obtain these from your Plivo Console:

    dotenv
    # Plivo Credentials - Get from https://console.plivo.com/dashboard/
    PLIVO_AUTH_ID=YOUR_PLIVO_AUTH_ID
    PLIVO_AUTH_TOKEN=YOUR_PLIVO_AUTH_TOKEN
    
    # Your Plivo phone number (must be SMS enabled)
    # Use E.164 format (e.g., +14155551234)
    PLIVO_SENDER_NUMBER=YOUR_PLIVO_PHONE_NUMBER
    • Replace YOUR_PLIVO_AUTH_ID, YOUR_PLIVO_AUTH_TOKEN, and YOUR_PLIVO_PHONE_NUMBER with your actual credentials and number.
    • Important: Ensure the phone number is in E.164 format (includes the + and country code).
    • E.164 Format Specification: The E.164 format is the international telephone numbering standard (ITU-T Recommendation E.164). Learn more about E.164 phone number formatting. It consists of:
      • A + prefix
      • Country code (1-3 digits)
      • Subscriber number (up to 12 digits)
      • Maximum total length: 15 digits (excluding the + symbol)
      • Examples: +14155551234 (US), +442071234567 (UK), +919876543210 (India)

Production Security Best Practices:

  • Never commit .env files: Always add .env to .gitignore
  • Use platform-specific secret management:
    • AWS: AWS Secrets Manager or Systems Manager Parameter Store
    • Heroku: heroku config:set PLIVO_AUTH_ID=xxx
    • Google Cloud: Secret Manager
    • Azure: Key Vault
    • Docker: Use --env-file flag or Docker secrets for swarm mode
  • Rotate credentials regularly: Change Auth Token every 90 days minimum
  • Principle of least privilege: Create separate Plivo sub-accounts for different environments (dev, staging, prod)
  • Audit access: Monitor API usage in Plivo console for suspicious activity

Implement SMS Sending with Plivo API in Express

What this code accomplishes:

  1. Loads environment variables and validates Plivo credentials
  2. Initializes an Express web server with JSON parsing middleware
  3. Creates a /send-sms POST endpoint that accepts to and text parameters
  4. Validates phone number format (E.164) and required fields
  5. Sends SMS via Plivo API with comprehensive error handling
  6. Returns success/failure responses with detailed error information

Now, let's write the code in server.js to set up the Express server and integrate the Plivo client.

javascript
// server.js
'use strict'; // Enforce stricter parsing and error handling

// 1. Load Environment Variables
require('dotenv').config(); // Load variables from .env file into process.env

// 2. Import Dependencies
const express = require('express');
const plivo = require('plivo');

// 3. Initialize Express App
const app = express();
app.use(express.json()); // Middleware to parse JSON request bodies

// 4. Validate Essential Environment Variables
const { PLIVO_AUTH_ID, PLIVO_AUTH_TOKEN, PLIVO_SENDER_NUMBER } = process.env;

if (!PLIVO_AUTH_ID || !PLIVO_AUTH_TOKEN || !PLIVO_SENDER_NUMBER) {
    console.error(
        'Error: Plivo environment variables (PLIVO_AUTH_ID, PLIVO_AUTH_TOKEN, PLIVO_SENDER_NUMBER) are missing or empty in .env file.'
    );
    process.exit(1); // Exit if essential config is missing
}

// 5. Initialize Plivo Client
// Ensure you handle potential errors during client initialization if necessary,
// though the SDK typically doesn't throw errors here unless inputs are malformed.
const plivoClient = new plivo.Client(PLIVO_AUTH_ID, PLIVO_AUTH_TOKEN);

// 6. Define the SMS Sending Route
app.post('/send-sms', async (req, res) => {
    // --- Basic Input Validation ---
    const { to, text } = req.body; // Get destination number and message text from request body

    if (!to || !text) {
        // Use 400 Bad Request for missing client input
        return res.status(400).json({
            success: false,
            error: 'Missing required fields: `to` and `text` in request body.',
        });
    }

    // Basic validation for 'to' number format (E.164)
    // Note: This regex is a basic check. Full E.164 validation is more complex
    // and might involve library lookups or more sophisticated patterns.
    if (!/^\+[1-9]\d{1,14}$/.test(to)) {
         return res.status(400).json({
            success: false,
            error: 'Invalid `to` phone number format. Use E.164 format (e.g., +14155551234).',
        });
    }

    // --- Send SMS using Plivo ---
    console.log(`Attempting to send SMS to: ${to}, Text: ""${text}""`);

    try {
        const response = await plivoClient.messages.create({
            src: PLIVO_SENDER_NUMBER, // Sender ID (Your Plivo Number)
            dst: to,                  // Destination Number (From request)
            text: text,               // Message Text (From request)
        });

        console.log('Plivo API Response:', response);

        // Check if message was successfully queued (basic check based on presence of message_uuid)
        // The exact structure might vary slightly based on SDK version or specific scenarios.
        // Refer to Plivo Node SDK documentation for definitive response structure.
        if (response && response.message_uuid) {
             res.status(200).json({
                success: true,
                message: 'SMS sent successfully queued.',
                message_uuid: response.message_uuid, // Return the message UUID (string expected)
                api_id: response.api_id,           // Return the API ID
            });
        } else {
             // This case might indicate an issue not caught by an exception (unlikely but possible)
             console.error('Plivo response indicates message queuing failed or missing expected fields:', response);
             res.status(500).json({
                success: false,
                error: 'Failed to queue SMS via Plivo (unexpected response structure).',
                details: response, // Include Plivo response for debugging
            });
        }

    } catch (error) {
        console.error('Error sending SMS via Plivo:', error);

        // Provide more specific feedback based on Plivo error if possible
        // Plivo errors often have status codes and detailed messages
        const statusCode = error.statusCode || 500; // Default to 500 Internal Server Error
        const errorMessage = error.message || 'An unexpected error occurred.';
        // Plivo error details might be in error.error or nested differently.
        // Check Plivo Node SDK documentation for the specific error object structure.
        const errorDetails = error.error || {};

        res.status(statusCode).json({
            success: false,
            error: `Plivo API Error: ${errorMessage}`,
            details: errorDetails,
        });
    }
});

// 7. Start the Server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
    console.log(`Server running on port ${PORT}`);
    console.log(`Plivo Sender Number: ${PLIVO_SENDER_NUMBER}`);
    console.log('API Endpoint: POST /send-sms');
    console.log('Required Body: { ""to"": ""+1XXXXXXXXXX"", ""text"": ""Your message"" }');
});

Code Explanation:

  1. Load Environment Variables: require('dotenv').config() loads the variables defined in your .env file into process.env. This must happen before you access these variables.
  2. Import Dependencies: Imports the express framework and the plivo SDK.
  3. Initialize Express App: Creates an instance of the Express application and uses express.json() middleware to automatically parse incoming requests with JSON payloads (like the one we'll send).
    • Request Size Limit: By default, express.json() has a limit of 100kb for request bodies (Express documentation). For larger payloads, configure explicitly: app.use(express.json({ limit: '10mb' })). SMS messages are typically under 5kb, so the default is sufficient.
  4. Validate Environment Variables: Checks if the essential Plivo credentials are loaded. If not, it logs an error and exits, preventing the server from starting without proper configuration.
  5. Initialize Plivo Client: Creates an instance of the Plivo client using your Auth ID and Auth Token from the environment variables.
  6. Define /send-sms Route:
    • Sets up a POST endpoint at /send-sms.
    • Uses async/await for handling the asynchronous Plivo API call cleanly.
    • Input Validation: Extracts to (destination number) and text (message content) from the request body (req.body). It performs basic checks to ensure both fields are present and the to number roughly matches the E.164 format.
    • Phone Number Validation: The regex /^\+[1-9]\d{1,14}$/ is a basic structural check. For production applications, use libphonenumber-js for comprehensive validation:
      javascript
      const { parsePhoneNumber } = require('libphonenumber-js');
      try {
          const phoneNumber = parsePhoneNumber(to);
          if (!phoneNumber.isValid()) {
              return res.status(400).json({ error: 'Invalid phone number' });
          }
      } catch (error) {
          return res.status(400).json({ error: 'Cannot parse phone number' });
      }
    • Plivo API Call: Uses plivoClient.messages.create() to send the SMS.
      • src: The sender number (your Plivo number from .env).
      • dst: The destination number (from the request).
      • text: The message content (from the request).
      • Optional Parameters:
        • url: Webhook URL for delivery status callbacks
        • method: HTTP method for webhook (GET or POST)
        • log: Set to true to log message on Plivo console
        • powerpack_uuid: Use Powerpack for number pools
        • Example: url: 'https://example.com/sms-status', method: 'POST', log: true
    • Success Response: If the API call is successful (doesn't throw an error and returns expected fields like message_uuid), it logs the Plivo response and sends a 200 OK response back to the client with the message_uuid and api_id.
    • Error Handling: If the Plivo API call fails (e.g., invalid credentials, insufficient funds, invalid number), the catch block executes. It logs the detailed error and sends an appropriate HTTP status code (using error.statusCode if available, otherwise 500) and an error message back to the client, potentially including details from error.error.
  7. Start Server: Starts the Express server, listening for incoming requests on the port specified by the PORT environment variable, or defaulting to 3000.

Common Plivo Error Codes

Source: Plivo Error Codes Documentation

Error CodeError NameDescriptionResolution
10Invalid MessageMessage rejected by downstream carrierContact Plivo support if frequent
20Network ErrorCarrier network issuesTemporary; retry later
30Spam DetectedCarrier spam filter blocked messageUse short codes for bulk; review content
40Invalid Source NumberSource number incorrectly formatted or not SMS-enabledVerify src in E.164 format and SMS capability
50Invalid Destination NumberDestination not SMS-enabled or incorrect formatVerify dst in E.164 format
70Destination Permanently UnavailablePhone number inactiveVerify number with user
80Destination Temporarily UnavailableHandset off or out of coverageRetry later
110Message Too LongExceeds 1,600 chars (GSM) or 737 (UCS-2)Split message or reduce length
200STOP Opt-outUser opted out via STOP keywordRemove from campaign; honor opt-out
300Failed to DispatchInternal Plivo errorNot charged; retry or contact support
420Message ExpiredQueued >3 hoursEnsure 10DLC registration for US traffic
450Country DisabledDestination country blockedEnable in console Geo Permissions
900Insufficient CreditAccount balance too lowAdd credits to account
95010DLC Daily LimitT-Mobile daily brand limit reachedResets midnight PT; increase brand limits
1000Unknown ErrorUnspecified failureContact support with message UUIDs

Authentication Error (401): Invalid PLIVO_AUTH_ID or PLIVO_AUTH_TOKEN. Verify credentials in console.

Test Your SMS Integration Locally

Before starting the server, verify prerequisites:

bash
# Check Node.js and npm versions
node --version  # Should be v18.x or higher
npm --version   # Should be 8.x or higher

# Verify dependencies are installed
ls node_modules | grep -E "(express|plivo|dotenv)"

# Verify .env file exists and contains credentials
cat .env | grep -E "(PLIVO_AUTH_ID|PLIVO_AUTH_TOKEN|PLIVO_SENDER_NUMBER)"

Now, let's run the server and test the endpoint.

  1. Start the Server: Open your terminal in the project directory (node-plivo-sms) and run:

    bash
    node server.js

    You should see output like:

    Server running on port 3000 Plivo Sender Number: +1XXXXXXXXXX API Endpoint: POST /send-sms Required Body: { ""to"": ""+1YYYYYYYYYY"", ""text"": ""Your message"" }

    If server fails to start:

    • "Cannot find module": Run npm install to reinstall dependencies
    • "Environment variables missing": Verify .env file exists and contains all three required variables
    • "EADDRINUSE" (port already in use): Another process is using port 3000. Either:
      • Kill the process: lsof -ti:3000 | xargs kill (Mac/Linux)
      • Use a different port: PORT=3001 node server.js
    • "Auth ID/Token invalid": Verify credentials are correct in .env (no extra spaces or quotes)
  2. Test with curl: Open a new terminal window (leaving the server running) and use curl (or a tool like Postman) to send a POST request to your endpoint.

    • Replace +1YYYYYYYYYY with a valid destination phone number (remember the trial account restrictions: use a verified sandbox number if applicable).
    • Replace ""Hello from Node and Plivo!"" with your desired message text.
    bash
    curl -X POST http://localhost:3000/send-sms \
    -H ""Content-Type: application/json"" \
    -d '{
      ""to"": ""+1YYYYYYYYYY"",
      ""text"": ""Hello from Node and Plivo!""
    }'
  3. Check Response:

    • Successful Request: If everything works, curl should output something like (UUIDs and IDs will vary):

      json
      {
        ""success"": true,
        ""message"": ""SMS sent successfully queued."",
        ""message_uuid"": ""some-unique-message-uuid-string"",
        ""api_id"": ""some-unique-api-id-string""
      }

      Typical Delivery Time: SMS messages are typically delivered within 3-10 seconds for domestic routes (e.g., US to US). International messages may take 10-60 seconds depending on carrier routing. Messages queued during carrier maintenance may take longer.

      Check the server logs for the Plivo API Response. You should also receive the SMS on the destination phone shortly after.

    • Failed Request (e.g., Validation Error): If you send an invalid request (e.g., missing to field):

      json
      {
        ""success"": false,
        ""error"": ""Missing required fields: `to` and `text` in request body.""
      }
    • Failed Request (e.g., Plivo API Error): If Plivo rejects the request (e.g., invalid Auth ID):

      json
      {
        ""success"": false,
        ""error"": ""Plivo API Error: Authentication credentials invalid. Check your Auth ID and Auth Token."",
        ""details"": {} // Plivo might provide more details here depending on the error
      }

      Check the server logs for the detailed Error sending SMS via Plivo.

  4. Verify SMS Delivery: Check the destination phone for the incoming SMS message. You can also check delivery status in the Plivo console:

    • Navigate to MessagingLogsSMS Logs
    • Filter by time range and view detailed status (queued, sent, delivered, failed)
    • Click on a message UUID to see full delivery report including carrier responses

Troubleshooting Common Plivo SMS API Issues

Diagnostic Checklist

Step 1: Verify Environment

  • Node.js version ≥ v18.x (node --version)
  • All dependencies installed (npm list --depth=0)
  • .env file exists with all three variables
  • No syntax errors in server.js (node --check server.js)

Step 2: Test Connectivity

  • Server starts without errors
  • Can reach http://localhost:3000 (or configured port)
  • Network allows outbound HTTPS to api.plivo.com

Step 3: Verify Credentials

  • Auth ID and Auth Token match Plivo console exactly
  • Sender number is SMS-enabled and owned by your account
  • Sender number is in E.164 format with + prefix

Step 4: Check Plivo Account

  • Account has sufficient credits (check console dashboard)
  • Destination country is enabled in Geo Permissions
  • For trial accounts: destination number is added to Sandbox Numbers
  • No rate limit warnings in console

Common Issues and Solutions

  • Authentication Errors (401 Unauthorized): Double-check your PLIVO_AUTH_ID and PLIVO_AUTH_TOKEN in the .env file. Ensure they are copied correctly from the Plivo console and that the .env file is being loaded (no typos in require('dotenv').config()).

  • Invalid Sender ID: Ensure PLIVO_SENDER_NUMBER is a valid, SMS-enabled Plivo number you own, formatted in E.164. If sending outside the US/Canada, you might need to register an Alphanumeric Sender ID with Plivo support depending on the destination country's regulations. Check Plivo's SMS API coverage page for country-specific rules.

  • Invalid Destination Number (to): Ensure the to number in your request body is in E.164 format (+ followed by country code and number).

  • Trial Account Restrictions: Remember you can only send to verified sandbox numbers on a trial account. Add numbers under Phone NumbersSandbox Numbers in the Plivo console.

  • Insufficient Funds: If you're using a paid account, ensure you have enough credits.

    • Check balance via console: Navigate to AccountOverviewAccount Balance
    • Check balance programmatically:
      javascript
      const balance = await plivoClient.account.getBalance();
      console.log(`Current balance: ${balance.cashCredits} credits`);
    • Low balance alerts: Configure in AccountAlerts to receive notifications at custom thresholds
  • Rate Limiting: Plivo enforces rate limits on API requests. For high-volume sending, implement proper queuing and potentially exponential backoff in your application logic (beyond the scope of this basic guide).

    • API Rate Limits (source: Plivo Account Limits):
      • Non-call APIs (including SMS): 300 requests per 5 seconds (default)
      • MMS APIs: 100 simultaneous requests
      • Exceeded limit response: HTTP 429 "Too Many Requests"
      • Request limit increase: Contact Plivo sales; requires minimum commitment
    • Best practice: Implement exponential backoff when receiving 429 errors
  • Encoding: Plivo handles GSM and Unicode characters (including emojis). Be aware that messages with Unicode characters have a lower character limit per SMS segment (70 vs. 160 for GSM). Long messages are automatically concatenated. See Plivo's Encoding and Concatenation guide.

    • GSM-7 Encoding: Single segment = 160 characters, concatenated segments = 153 characters each
    • Unicode (UCS-2/UTF-16): Single segment = 70 characters, concatenated segments = 67 characters each
    • Character Types: GSM-7 supports basic Latin characters; Unicode required for emojis, non-Latin scripts, and special symbols
    • Message limits: Maximum 1,600 characters (GSM) or 737 characters (Unicode) total length
  • Network Issues: Ensure your server can reach Plivo's API endpoints (api.plivo.com). Firewalls or network configurations could block outgoing connections.

    • Test API connectivity without sending SMS:
      javascript
      // Add this test endpoint to server.js
      app.get('/test-plivo', async (req, res) => {
          try {
              const balance = await plivoClient.account.getBalance();
              res.json({ success: true, connection: 'OK', balance: balance.cashCredits });
          } catch (error) {
              res.status(500).json({ success: false, error: error.message });
          }
      });
      Then test with: curl http://localhost:3000/test-plivo
  • SDK Response/Error Structure: The exact fields returned by the Plivo SDK upon success (response.message_uuid, response.api_id) or the structure of the error object in the catch block might change between SDK versions. Always refer to the official Plivo Node SDK documentation for the version you are using.

Deploy Your Node.js SMS Application to Production

While this guide focuses on local development, here are key points for deploying this application:

  • Environment Variables: Never commit your .env file. Production environments provide mechanisms to securely set environment variables directly on the platform. Configure PLIVO_AUTH_ID, PLIVO_AUTH_TOKEN, and PLIVO_SENDER_NUMBER in your hosting provider's settings.

    Platform-specific examples:

    bash
    # Heroku
    heroku config:set PLIVO_AUTH_ID=MA... PLIVO_AUTH_TOKEN=xxx... PLIVO_SENDER_NUMBER=+1...
    
    # AWS Elastic Beanstalk
    eb setenv PLIVO_AUTH_ID=MA... PLIVO_AUTH_TOKEN=xxx... PLIVO_SENDER_NUMBER=+1...
    
    # Google Cloud Run
    gcloud run services update SERVICE_NAME \
      --set-env-vars PLIVO_AUTH_ID=MA...,PLIVO_AUTH_TOKEN=xxx...,PLIVO_SENDER_NUMBER=+1...
    
    # Docker
    docker run -e PLIVO_AUTH_ID=MA... -e PLIVO_AUTH_TOKEN=xxx... -e PLIVO_SENDER_NUMBER=+1... my-app
  • PORT Variable: Most hosting platforms automatically assign a PORT environment variable. The code const PORT = process.env.PORT || 3000; correctly uses the assigned port or falls back to 3000.

  • Process Management: Use a process manager like pm2 or rely on your platform's tools (e.g., Heroku Dynos, Docker containers) to keep your Node.js application running reliably and restart it if it crashes.

    PM2 Example:

    bash
    # Install PM2
    npm install -g pm2
    
    # Start application
    pm2 start server.js --name plivo-sms
    
    # Configure auto-restart on reboot
    pm2 startup
    pm2 save
    
    # Create ecosystem.config.js for advanced configuration:
    module.exports = {
      apps: [{
        name: 'plivo-sms',
        script: 'server.js',
        instances: 2,  // Use 2 CPU cores
        exec_mode: 'cluster',
        env: {
          NODE_ENV: 'production'
        }
      }]
    };
    
    # Start with config
    pm2 start ecosystem.config.js

    Source: PM2 Documentation

  • Logging: Implement more robust logging (e.g., using Winston or Pino) to capture detailed information in production, especially errors, and potentially send logs to a centralized logging service.

  • Security: Add rate limiting (e.g., using express-rate-limit) to your API endpoint to prevent abuse. Consider adding API key authentication if this endpoint will be exposed publicly or used by multiple clients.

    CORS Configuration for Frontend Integration:

    javascript
    // Install: npm install cors
    const cors = require('cors');
    
    // Allow specific origin
    app.use(cors({
      origin: 'https://yourdomain.com',
      methods: ['POST'],
      credentials: true
    }));
    
    // Or allow all origins (development only)
    app.use(cors());

    HTTPS/SSL Requirements:

    • Production applications must use HTTPS to encrypt API credentials in transit
    • Webhook URLs for delivery callbacks must be HTTPS (HTTP will be rejected)
    • Certificate options:
      • Free: Let's Encrypt with automated renewal
      • Cloud platforms: AWS ACM, Google-managed certs (included with Cloud Run/App Engine)
      • Heroku: Automatic SSL for custom domains on paid dynos
    • Local HTTPS testing: Use mkcert or self-signed certificates for development

Conclusion and Next Steps

You have successfully built a basic Node.js Express application capable of sending SMS messages using the Plivo API. You learned how to set up the project, manage credentials securely, implement the sending logic with error handling, and test the API endpoint.

Further Enhancements:

  • Receiving SMS: Implement a webhook endpoint using Express to receive incoming SMS messages sent to your Plivo number. For two-way messaging, see our Plivo inbound messaging tutorial.
  • Status Callbacks: Configure a url or log parameter in the messages.create call or Plivo Application settings to receive status updates (e.g., delivered, failed) for sent messages.
  • More Robust Validation: Implement more comprehensive validation for phone numbers (potentially using a dedicated library like libphonenumber-js) and message content.
  • Web Interface: Build a simple frontend (using HTML, CSS, and JavaScript or a framework like React/Vue/Angular) to interact with your API.
  • Database Integration: Store message logs, user data, or application state in a database.
  • Bulk Sending: Adapt the logic to handle sending messages to multiple recipients efficiently, potentially using Promise.all for better concurrency while respecting Plivo rate limits.

Monitoring and Analytics:

  • Plivo Console Analytics: View message volume, delivery rates, and error trends at MessagingAnalytics
  • Custom Monitoring: Implement application-level tracking with tools like:
    • DataDog, New Relic, or Application Insights for APM
    • Prometheus + Grafana for self-hosted metrics
    • CloudWatch (AWS), Stackdriver (GCP), or Azure Monitor for cloud-native monitoring
  • Key Metrics to Track:
    • Message success rate (delivered / total sent)
    • Average delivery time
    • Error code distribution
    • API response times
    • Account balance trends

This foundation enables you to integrate powerful SMS communication features into your Node.js applications effectively and securely.

Frequently Asked Questions

How to send SMS with Node.js and Express?

This guide provides a step-by-step process for sending SMS messages from a Node.js application using the Express framework and Plivo API. It involves setting up a project, installing dependencies like Express and Plivo, configuring environment variables, and implementing the send SMS logic within an Express route. You'll create an endpoint that accepts the destination number and message text to trigger SMS sending via Plivo.

What is Plivo used for in this tutorial?

Plivo is a cloud communications platform that provides APIs for various communication services including sending and receiving SMS messages. In this tutorial, Plivo's SMS API is utilized to send text messages from your Node.js application. You'll need a Plivo account, Auth ID, Auth Token, and a Plivo phone number to use the API.

Why use dotenv for Plivo credentials?

Dotenv helps manage environment variables securely, loading credentials from a .env file into process.env. This prevents your sensitive API keys from being exposed in your codebase or committed to version control. It is crucial for keeping your Plivo Auth ID and Auth Token secret.

When should I validate Plivo environment variables?

Environment variables should be validated at the start of your application, before using them. In the server.js file, the code checks for PLIVO_AUTH_ID, PLIVO_AUTH_TOKEN, and PLIVO_SENDER_NUMBER right after loading the .env file. If these are not present, the server exits with an error.

How to set up Plivo sender number in Node.js?

Your Plivo sender number is configured using an environment variable. Set a PLIVO_SENDER_NUMBER variable in your .env file with your Plivo phone number (in E.164 format). This number must be an SMS-enabled number purchased through your Plivo account.

What is the format for the /send-sms endpoint request?

The /send-sms endpoint expects a POST request with a JSON body containing two fields: 'to' and 'text'. The 'to' field should contain the recipient's phone number in E.164 format (e.g., +14155551234). The 'text' field should contain the SMS message content as a string.

How to handle errors when sending SMS with Plivo?

The example code includes comprehensive error handling. It validates input parameters and catches errors during the Plivo API call. If an error occurs, it logs the error details and returns an appropriate error response to the client, including the HTTP status code and error message from Plivo.

Can I use an alphanumeric sender ID with Plivo?

Alphanumeric sender IDs are supported by Plivo but primarily for sending outside the US and Canada. Using one depends on local regulations for the recipient's country, and might involve registration with Plivo. For US/Canada SMS, you need a Plivo phone number as the sender ID.

How to test Plivo SMS integration locally?

After starting your Node server, use a tool like curl or Postman to send POST requests to http://localhost:3000/send-sms. Replace placeholders in the example request with the recipient's phone number and your desired message. Check your server logs and the recipient's phone to confirm message delivery.

What are Plivo trial account limitations?

With a Plivo trial account, you can only send messages to phone numbers verified as sandbox numbers in your Plivo console under Phone Numbers -> Sandbox Numbers. This is important for testing and verifying your integration.

How to handle SMS character limits with Plivo?

Plivo supports GSM and Unicode. GSM allows 160 characters, but Unicode messages (including emojis) have a lower limit of 70 characters per segment. Plivo automatically concatenates longer messages into multiple segments.

How to set up environment variables in production?

When deploying to production environments like Heroku or AWS, do not commit your .env file. Instead, utilize the platform's specific mechanisms to set your PLIVO_AUTH_ID, PLIVO_AUTH_TOKEN, and PLIVO_SENDER_NUMBER directly within the environment.

Why use a process manager with Node.js and Plivo?

A process manager like PM2 helps ensure your Node.js application runs continuously and restarts automatically in case of failures. This is essential for the reliability of your SMS sending service in production.