messaging channels
messaging channels
How to Send SMS with Plivo in NestJS: Complete TypeScript Integration Guide
Step-by-step guide to integrate Plivo SMS API with NestJS using TypeScript. Learn to send SMS messages, handle validation, manage errors, and deploy production-ready Node.js messaging features with the Plivo SDK.
This comprehensive guide shows you how to send SMS messages using Plivo's API integrated with NestJS. You'll build a production-ready REST API endpoint that sends text messages programmatically using the Plivo Node.js SDK and TypeScript. Perfect for adding SMS notifications, alerts, two-factor authentication (2FA), or verification codes to your NestJS applications.
Whether you're building user authentication flows, automated alerts, or customer engagement features, this tutorial covers everything from initial setup through production deployment with proper error handling and security best practices.
Technologies Used:
- NestJS: A progressive Node.js framework for building efficient, reliable, and scalable server-side applications. Its modular architecture and built-in features (like configuration management and validation pipes) make integration straightforward.
- Plivo: A cloud communications platform providing APIs for SMS, voice, and more. We'll use their Node.js SDK (specifically v3, as indicated by the API usage in this guide).
- Node.js: The underlying JavaScript runtime environment.
- TypeScript: Superset of JavaScript used by NestJS for strong typing.
- dotenv: For managing environment variables locally.
System Architecture:
+-------------+ +---------------------+ +-----------------+ +--------------+
| Client |------>| NestJS API |------>| Plivo Service |------>| Plivo API |
| (e.g., curl,| | (Controller) | | (NestJS Service| | (SMS Gateway)|
| Postman) | | - POST /sms/send | | Wrapper) | +--------------+
| | | - Request Validation | | - Plivo SDK |
+-------------+ +---------------------+ +-----------------+
| Uses ConfigService |
+---------------------+
| Reads .env vars |
+---------------------+(Note: Ensure the ASCII diagram renders correctly in your Markdown viewer; fixed-width fonts are required.)
What You'll Learn:
By the end of this guide, you will have a running NestJS application with a single API endpoint (POST /sms/send) capable of sending SMS messages via Plivo. You'll understand how to configure Plivo credentials, structure the integration within NestJS, handle basic requests, and manage essential configurations securely.
Prerequisites:
- Node.js and npm/yarn: Ensure you have Node.js (LTS version recommended) and a package manager installed. (Node.js Downloads)
- NestJS CLI: Install the NestJS command-line tool globally:
npm install -g @nestjs/cli - Plivo Account: Sign up for a Plivo account. (Plivo Signup)
- Basic TypeScript/JavaScript Knowledge: Familiarity with modern JavaScript (ES6+) and TypeScript basics.
- Terminal/Command Line Access: Comfortable using the command line for project setup and running commands.
How to Set Up Your NestJS Project for Plivo SMS Integration
Let's start by creating a new NestJS project and installing necessary dependencies for Plivo SMS functionality.
-
Create a New NestJS Project: Open your terminal and run the NestJS CLI command to generate a new project. We'll call it
plivo-sms-app.bashnest new plivo-sms-appChoose your preferred package manager (npm or yarn) when prompted.
-
Navigate into Project Directory: Change into the newly created project folder.
bashcd plivo-sms-app -
Install Plivo Node.js SDK: Add the official Plivo Node.js helper library to your project. This guide assumes usage compatible with Plivo Node SDK v3.x.
bashnpm install plivo # or yarn add plivo -
Install Configuration Module: NestJS provides a dedicated module for handling environment variables and configuration, which is crucial for managing API keys securely.
bashnpm install @nestjs/config # or yarn add @nestjs/config -
Install Validation Dependencies: We'll use
class-validatorandclass-transformerfor request body validation.bashnpm install class-validator class-transformer # or yarn add class-validator class-transformer
Project Structure Explanation:
src/: Contains your application's core TypeScript code.app.module.ts: The root module of the application.main.ts: The entry point file that bootstraps the application.- Other modules, controllers, services will reside here.
.env: (We will create this) Stores environment variables locally (DO NOT commit this file to version control).package.json: Lists project dependencies and scripts.tsconfig.json: TypeScript compiler configuration.
Configuration Choices:
- Using
@nestjs/configallows us to load environment variables from a.envfile during development and directly from the environment in production, providing a consistent way to access configuration values like API keys. - Using
class-validatorandclass-transformerintegrates seamlessly with NestJS'sValidationPipefor automatic request payload validation based on Data Transfer Objects (DTOs).
How to Get Plivo API Credentials and Phone Numbers
Before writing code, you need your Plivo API credentials and an SMS-enabled phone number.
-
Find Auth ID and Auth Token:
- Log in to your Plivo Console.
- On the main dashboard homepage, you'll find your Auth ID and Auth Token. These are like your username and password for the Plivo API. Keep them secure.
-
Get a Plivo Phone Number:
- You need a Plivo phone number capable of sending SMS messages. For sending to US/Canada numbers, a Plivo number is mandatory. For other countries, you might use an Alphanumeric Sender ID (configurable in the Plivo console), but a number often provides better deliverability and enables two-way communication.
- Navigate to Phone Numbers -> Buy Numbers in the Plivo console.
- Search for numbers based on country, features (ensure SMS is checked), and type.
- Purchase a number suitable for your needs. Note this number down.
- Trial Account Limitation: If you are using a Plivo trial account, you can typically only send SMS messages to phone numbers that you have explicitly verified within the Plivo console (Phone Numbers -> Sandbox Numbers).
-
Configure Environment Variables:
- Create a file named
.envin the root directory of yourplivo-sms-appproject. - Add your Plivo credentials and the Plivo phone number (or Sender ID) you obtained:
dotenv# .env PLIVO_AUTH_ID=YOUR_PLIVO_AUTH_ID PLIVO_AUTH_TOKEN=YOUR_PLIVO_AUTH_TOKEN PLIVO_SENDER_ID=YOUR_PLIVO_PHONE_NUMBER_OR_SENDER_ID-
Replace
YOUR_PLIVO_AUTH_ID,YOUR_PLIVO_AUTH_TOKEN, andYOUR_PLIVO_PHONE_NUMBER_OR_SENDER_IDwith your actual values. -
Important: Add
.envto your.gitignorefile to prevent accidentally committing sensitive credentials to version control.text# .gitignore (add this line if not present) .env
- Create a file named
Environment Variable Explanation:
PLIVO_AUTH_ID: Your main account identifier for Plivo API authentication.PLIVO_AUTH_TOKEN: Your secret token for Plivo API authentication.PLIVO_SENDER_ID: The phone number (in E.164 format, e.g.,+14155551212) or Alphanumeric Sender ID (3-11 alphanumeric characters, no spaces) that will appear as the sender of the SMS.
How to Create a Plivo Service in NestJS
We'll create a dedicated NestJS service to encapsulate the logic for interacting with the Plivo API. This promotes modularity and reusability.
-
Generate the Service: Use the NestJS CLI to generate a service named
plivo.bashnest g service plivo --no-specThis creates
src/plivo/plivo.service.ts. -
Implement the Plivo Service: Open
src/plivo/plivo.service.tsand modify it as follows:typescript// src/plivo/plivo.service.ts import { Injectable, Logger, InternalServerErrorException, BadRequestException } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import * as plivo from 'plivo'; @Injectable() export class PlivoService { private readonly logger = new Logger(PlivoService.name); private client: plivo.Client; private senderId: string; constructor(private configService: ConfigService) { const authId = this.configService.get<string>('PLIVO_AUTH_ID'); const authToken = this.configService.get<string>('PLIVO_AUTH_TOKEN'); this.senderId = this.configService.get<string>('PLIVO_SENDER_ID'); if (!authId || !authToken || !this.senderId) { this.logger.error('Plivo credentials or Sender ID not configured in environment variables.'); // Throwing an error during startup is appropriate if core config is missing. throw new Error('Plivo configuration is missing. Check PLIVO_AUTH_ID, PLIVO_AUTH_TOKEN, PLIVO_SENDER_ID environment variables.'); } // This guide uses the Plivo Node SDK v3 syntax this.client = new plivo.Client(authId, authToken); this.logger.log('Plivo client initialized.'); } /** * Sends an SMS message using the Plivo API. * @param to The recipient's phone number in E.164 format (e.g., +12025551234). * @param text The content of the SMS message. * @returns The response from the Plivo API. * @throws BadRequestException if input validation fails (to, senderId format). * @throws InternalServerErrorException if the message fails to send via Plivo API. */ async sendSms(to: string, text: string): Promise<plivo.MessageCreateResponse> { this.logger.log(`Attempting to send SMS to ${to}`); // Basic E.164 format check for recipient (see E.164 phone format guide for details) if (!/^\+[1-9]\d{1,14}$/.test(to)) { this.logger.warn(`Invalid 'to' phone number format provided: ${to}. Expected E.164.`); throw new BadRequestException(`Invalid recipient phone number format: ${to}. Use E.164 format (e.g., +1xxxxxxxxxx).`); } // Validate Sender ID format (E.164 OR Alphanumeric) const isE164 = /^\+[1-9]\d{1,14}$/.test(this.senderId); const isAlphanumeric = /^[a-zA-Z0-9]{3,11}$/.test(this.senderId); // 3-11 Alphanumeric chars, no spaces if (!isE164 && !isAlphanumeric) { this.logger.warn(`Invalid 'senderId' format configured: ${this.senderId}. Expected E.164 (e.g., +1...) or Alphanumeric (3-11 chars, no spaces). Check PLIVO_SENDER_ID.`); // Throw BadRequest as it's an input configuration issue detectable before API call throw new BadRequestException(`Invalid sender ID format: ${this.senderId}. Use E.164 format or Alphanumeric Sender ID (3-11 chars, no spaces).`); } try { // Using Plivo Node SDK v3 style: client.messages.create(...) const response = await this.client.messages.create( this.senderId, // src to, // dst text, // text ); // Plivo API V3 returns messageUuid as an array of strings this.logger.log(`SMS submitted successfully to ${to}. Message UUID: ${response.messageUuid[0]}`); // console.log('Plivo API Response:', response); // Optional: Log full response for debugging return response; } catch (error) { this.logger.error(`Failed to send SMS to ${to}: ${error.message}`, error.stack); // Log the detailed error from Plivo if available (often in error.response.data for axios errors) if (error.response && error.response.data) { this.logger.error(`Plivo API Error Details: ${JSON.stringify(error.response.data)}`); } else { this.logger.error(`Plivo Error Object: ${JSON.stringify(error)}`); // Log the error object itself } // Throw a NestJS specific exception for consistent API error handling throw new InternalServerErrorException(`Failed to send SMS via Plivo: ${error.message}`); } } }
Code Explanation:
- Dependencies: We import necessary modules from
@nestjs/common(includingBadRequestException),@nestjs/config, and theplivoSDK. - Logger: A NestJS
Loggerinstance is created for logging service activity. - Constructor:
- Injects
ConfigServiceto access environment variables. - Retrieves
PLIVO_AUTH_ID,PLIVO_AUTH_TOKEN, andPLIVO_SENDER_ID. - Includes a crucial check to ensure these variables are present, throwing an error during startup if not.
- Initializes the
plivo.Clientwith the fetched credentials. Notes that this uses Plivo Node SDK v3.
- Injects
sendSmsMethod:- Takes the recipient number (
to) and messagetextas arguments. - Logs the attempt.
- Includes validation for the
tonumber format (E.164) andsenderIdformat (E.164 or Alphanumeric 3-11 chars). ThrowsBadRequestExceptionif formats are invalid, preventing unnecessary API calls. - Uses
async/awaitto callthis.client.messages.create()(v3 SDK method).src: The sender ID/number configured in.env.dst: The recipient number passed to the method.text: The message content.
- Logs the success message, including the
messageUuidreturned by Plivo (useful for tracking; v3 returns it as an array). - Includes a
try...catchblock for robust error handling:- Logs detailed error information, including the specific error from the Plivo SDK if possible.
- Throws a NestJS
InternalServerErrorException, which results in a standard 500 error response from our API if sending fails during the Plivo API interaction.
- Takes the recipient number (
How to Build the SMS API Endpoint with Controller and DTO
Now, let's create the API endpoint that external clients can call to trigger the SMS sending process.
-
Generate the Controller: Use the NestJS CLI to generate a controller named
sms.bashnest g controller sms --no-specThis creates
src/sms/sms.controller.ts. -
Create the Data Transfer Object (DTO): DTOs define the expected shape of the request body and enable automatic validation. Create a file
src/sms/dto/send-sms.dto.ts:typescript// src/sms/dto/send-sms.dto.ts import { IsString, IsNotEmpty, Matches, MaxLength } from 'class-validator'; export class SendSmsDto { @IsString() @IsNotEmpty() @Matches(/^\+[1-9]\d{1,14}$/, { // E.164 format regex message: 'Recipient phone number must be in E.164 format (e.g., +12025551234).', }) to: string; @IsString() @IsNotEmpty() @MaxLength(1600) // Plivo allows long messages (~1600 chars), but good practice to have a limit text: string; }@IsString(): Ensures the value is a string.@IsNotEmpty(): Ensures the value is not empty.@Matches(): Validates thetofield against the E.164 regex pattern.@MaxLength(): Sets a maximum length for the message text.
-
Implement the SMS Controller: Open
src/sms/sms.controller.tsand modify it:typescript// src/sms/sms.controller.ts import { Controller, Post, Body, Logger, ValidationPipe, UsePipes, HttpException } from '@nestjs/common'; import { PlivoService } from '../plivo/plivo.service'; import { SendSmsDto } from './dto/send-sms.dto'; @Controller('sms') // Route prefix: /sms export class SmsController { private readonly logger = new Logger(SmsController.name); constructor(private readonly plivoService: PlivoService) {} @Post('send') // Full route: POST /sms/send // Apply validation pipe (can also be applied globally in main.ts) @UsePipes(new ValidationPipe({ whitelist: true, forbidNonWhitelisted: true, transform: true })) async sendSms(@Body() sendSmsDto: SendSmsDto) { this.logger.log(`Received request to send SMS to: ${sendSmsDto.to}`); try { const result = await this.plivoService.sendSms(sendSmsDto.to, sendSmsDto.text); return { message: 'SMS submitted successfully.', // Only return necessary info, avoid leaking full Plivo response unless needed // Access the first element as Plivo v3 returns messageUuid as an array plivoMessageId: result.messageUuid[0], }; } catch (error) { // Log the error within the controller context this.logger.error(`Error in sendSms endpoint: ${error.message}`, error.stack); // If the error is already an HttpException (like BadRequestException or // InternalServerErrorException thrown from the service), re-throw it directly. // Otherwise, wrap it or let NestJS handle it (which might default to 500). if (error instanceof HttpException) { throw error; } // For unexpected errors not originating from our explicit throws in the service throw new HttpException(error.message || 'An unexpected error occurred', 500); } } }
Code Explanation:
@Controller('sms'): Defines the base route for this controller as/sms.- Constructor: Injects the
PlivoServicewe created earlier. @Post('send'): Decorator marks thesendSmsmethod to handle HTTP POST requests to the/sms/sendendpoint.@Body() sendSmsDto: SendSmsDto: This decorator tells NestJS to parse the request body and assign it to thesendSmsDtoparameter. Crucially, it expects the body to conform to theSendSmsDtostructure.@UsePipes(new ValidationPipe(...)): This applies the validation pipe directly to this endpoint. TheValidationPipeuses the decorators inSendSmsDto(class-validator) to validate the incoming request body before the method logic runs.whitelist: true: Strips any properties from the request body that are not defined in the DTO.forbidNonWhitelisted: true: Throws an error if extra properties (not in the DTO) are present.transform: true: Attempts to transform the plain JS object payload into an instance of the DTO class.
- Logic:
- Logs the incoming request.
- Calls
this.plivoService.sendSmswith the validatedtoandtextfrom the DTO. - Returns a simple success message along with the Plivo message UUID (accessing the first element for v3).
- Includes a
try...catchblock:- Logs errors that occur during the service call.
- Re-throws
HttpExceptioninstances (likeBadRequestExceptionorInternalServerErrorExceptionthrown from the service) directly, allowing NestJS's exception filter to handle them correctly. - Catches any other unexpected errors and throws a generic
HttpExceptionwith status 500.
How to Configure NestJS Modules for Plivo Integration
We need to ensure NestJS knows about our new service, controller, and the configuration module.
-
Update App Module (
src/app.module.ts): Modify your main application module to importConfigModuleand register thePlivoServiceandSmsController.typescript// src/app.module.ts import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { AppController } from './app.controller'; // Default controller import { AppService } from './app.service'; // Default service import { PlivoService } from './plivo/plivo.service'; import { SmsController } from './sms/sms.controller'; @Module({ imports: [ ConfigModule.forRoot({ isGlobal: true, // Makes ConfigService available globally envFilePath: '.env', // Specify the env file path // You might add validation schema here for required env vars }), ], controllers: [ AppController, // Keep or remove default controller as needed SmsController, // Register our SMS controller ], providers: [ AppService, // Keep or remove default service as needed PlivoService, // Register our Plivo service ], }) export class AppModule {}
Explanation:
ConfigModule.forRoot({...}): Initializes the configuration module.isGlobal: true: Makes theConfigServiceavailable for injection in any module without needing to importConfigModuleeverywhere.envFilePath: '.env': Tells the module to load variables from the.envfile. In production, it will automatically pick up system environment variables if the file isn't found.
controllers: [..., SmsController]: Registers ourSmsControllerso NestJS maps routes to it.providers: [..., PlivoService]: Registers ourPlivoServiceas an injectable provider, making it available for dependency injection (e.g., inSmsController).
-
Enable Global Validation Pipe (Optional but Recommended): Instead of applying
@UsePipesto every controller method, you can enable theValidationPipeglobally insrc/main.ts. This ensures all incoming requests that use DTOs are automatically validated.typescript// src/main.ts import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { Logger, ValidationPipe } from '@nestjs/common'; // Import ValidationPipe async function bootstrap() { const app = await NestFactory.create(AppModule); const logger = new Logger('Bootstrap'); // Create logger instance for bootstrap // Enable global validation pipe app.useGlobalPipes( new ValidationPipe({ whitelist: true, // Strip properties not in DTO forbidNonWhitelisted: true, // Throw error if extra properties are sent transform: true, // Automatically transform payloads to DTO instances transformOptions: { enableImplicitConversion: true, // Allow basic type conversion (e.g., string query param to number if expected) }, }), ); const port = process.env.PORT || 3000; // Use PORT from env or default to 3000 await app.listen(port); logger.log(`Application listening on port ${port}`); // Use logger } bootstrap();If you enable it globally here, you can remove the
@UsePipes(...)decorator from theSmsControllermethod.
How to Test Your Plivo SMS Integration
With the code in place, let's run the application and test the endpoint.
-
Start the Development Server: Run the following command in your terminal from the project root directory (
plivo-sms-app):bashnpm run start:dev # or yarn start:devThis command starts the NestJS application in watch mode, meaning it will automatically recompile and restart when you save code changes. You should see logs indicating the application has started, the Plivo client initialized, and it's listening on a port (default 3000). Ensure there are no startup errors related to missing Plivo configuration.
-
Test with cURL or Postman: Open another terminal window or use a tool like Postman to send a POST request to your running application.
Using cURL:
bashcurl -X POST http://localhost:3000/sms/send \ -H "Content-Type: application/json" \ -d '{ "to": "+1TARGET_PHONE_NUMBER", "text": "Hello from NestJS and Plivo! This is a test message." }'- Replace
+1TARGET_PHONE_NUMBERwith a valid phone number in E.164 format. Remember: If using a Plivo trial account, this number must be verified in your Plivo console's Sandbox Numbers section. - Make sure the
Content-Typeheader is set correctly toapplication/json. - The
-dflag provides the JSON request body.
Expected Success Response (JSON, Status 201 Created or 200 OK):
json{ "message": "SMS submitted successfully.", "plivoMessageId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" }You should also see logs in your NestJS application terminal indicating the request was received and the SMS was submitted successfully. The target phone should receive the SMS shortly after (delivery depends on Plivo and carrier networks).
Testing Validation (assuming global pipe or
@UsePipesis active):-
Missing Field:
bashcurl -X POST http://localhost:3000/sms/send -H "Content-Type: application/json" -d '{"text": "Missing recipient"}'Expected Error Response (400 Bad Request): (Messages might vary slightly based on validator versions)
json{ "statusCode": 400, "message": [ "Recipient phone number must be in E.164 format (e.g., +12025551234).", "to should not be empty", "to must be a string" ], "error": "Bad Request" } -
Invalid Phone Format:
bashcurl -X POST http://localhost:3000/sms/send -H "Content-Type: application/json" -d '{"to": "12345", "text": "Invalid number format"}'Expected Error Response (400 Bad Request):
json{ "statusCode": 400, "message": [ "Recipient phone number must be in E.164 format (e.g., +12025551234)." ], "error": "Bad Request" } -
Extra Field (if
forbidNonWhitelisted: true):bashcurl -X POST http://localhost:3000/sms/send -H "Content-Type: application/json" -d '{"to": "+1TARGET_PHONE_NUMBER", "text": "Test", "extraField": "should_fail"}'Expected Error Response (400 Bad Request):
json{ "statusCode": 400, "message": [ "property extraField should not exist" ], "error": "Bad Request" }
- Replace
Best Practices for Error Handling and Logging
We've implemented layered error handling:
- Request Validation Errors: Handled automatically by
ValidationPipe. NestJS returns a400 Bad Requestresponse with detailed error messages based on the DTO decorators. - Input Format Errors (Service Level): The
PlivoServicecheckstoandsenderIdformats before calling the API. If invalid, it throws aBadRequestException, resulting in a400 Bad Requestresponse. - Plivo API Errors: Caught within the
PlivoService.- A detailed error is logged using
Logger.error, including Plivo's response data if available. - An
InternalServerErrorExceptionis thrown. - NestJS's default exception filter catches this and returns a
500 Internal Server Errorresponse. The response body usually includes the status code and a generic error message unless detailed error exposure is enabled (not recommended for production).
- A detailed error is logged using
- Configuration Errors: Checked during
PlivoServiceinitialization. If critical config (Auth ID/Token/Sender ID) is missing, anErroris thrown, which typically stops the application startup process – this is desirable as the core function cannot operate. - Logging: The built-in
@nestjs/commonLoggeris used.- Logs key events like initialization, request reception, SMS sending attempts, successes (with Message UUID), and failures (with error messages and stack traces).
- In production, configure more robust logging:
- Log Levels: Control verbosity (e.g.,
INFO,WARN,ERROR). - Log Format: JSON for easier parsing by log aggregation tools (e.g., Datadog, Splunk, ELK).
- Log Destinations: Files, standard output/error, or external services. Libraries like
pinoorwinstonintegrated with NestJS are common.
- Log Levels: Control verbosity (e.g.,
Testing Error Scenarios:
- Invalid Credentials: Temporarily change
PLIVO_AUTH_IDorPLIVO_AUTH_TOKENin.envand restart. Send a request – it should fail with a 500 response, and logs should show Plivo authentication errors. - Invalid Sender ID Format: Set
PLIVO_SENDER_IDto an invalid format (e.g.,INVALID SENDERor+123) in.envand restart. Send a request – it should fail with a 400 response due to the service-level validation. - Trial Account Limitation: Using a trial account, try sending to a non-verified number. Plivo should reject it, resulting in an error logged by the service and a 500 response from the API.
Security Best Practices for Production SMS APIs
For production environments, enhance security:
- Credential Management:
- NEVER hardcode credentials in source code.
- Use environment variables managed securely by your deployment platform (e.g., AWS Secrets Manager, GCP Secret Manager, Kubernetes Secrets, Heroku Config Vars).
- Ensure
.envis in.gitignore.
- Input Validation:
- Robust DTO validation (
ValidationPipe) is essential. - Service-level validation (like
senderIdformat) adds another layer.
- Robust DTO validation (
- Rate Limiting:
- Implement rate limiting (e.g., using
@nestjs/throttler) to prevent abuse of the SMS endpoint and your Plivo account. Learn more about implementing rate limiting in NestJS.
- Implement rate limiting (e.g., using
- Authentication/Authorization:
- Protect the
/sms/sendendpoint. Only authorized clients/users should be able to trigger SMS. Use API Keys, JWT, OAuth, etc., leveraging NestJS modules like@nestjs/passportor@nestjs/jwt.
- Protect the
- HTTPS: Always serve your application over HTTPS in production.
Common Issues and How to Fix Them
- Trial Account Limitations: SMS only deliverable to verified "Sandbox Numbers". Check Plivo console.
- Incorrect Credentials: Double-check
PLIVO_AUTH_ID/PLIVO_AUTH_TOKENin environment variables match Plivo Console exactly. Expect 401 errors from Plivo (leading to 500 from API). - Invalid Sender ID (
srcnumber): EnsurePLIVO_SENDER_IDis a valid, owned Plivo number (E.164) or registered Alphanumeric Sender ID. Format errors should be caught by service validation (400 response); Plivo API might reject otherwise (500 response). - Invalid Recipient Number (
dstnumber): Ensuretois E.164. DTO validation should catch most format issues (400 response). Plivo API performs further checks. - Carrier Filtering: SMS marked as sent by Plivo but not delivered. Check Plivo logs for delivery status. May involve carrier spam filters, content issues, or A2P 10DLC compliance (US). Contact Plivo support if persistent.
- Rate Limits Exceeded: Plivo API returns 429 errors. Implement application-level rate limiting and potentially retry logic with backoff in
PlivoService. - Network Issues: Ensure server has outbound connectivity to
api.plivo.com(port 443/HTTPS). Check firewalls.
Deploying Your NestJS Plivo SMS Application
- Environment Variables: Configure
PLIVO_AUTH_ID,PLIVO_AUTH_TOKEN,PLIVO_SENDER_IDsecurely in the production environment. Do not deploy.env. - Build: Use
npm run buildoryarn buildto create thedistfolder. - Run: Start with
node dist/main.js. Use a process manager likepm2or rely on platform features (Docker, Kubernetes, PaaS). - HTTPS: Use a reverse proxy (Nginx, Caddy) or platform features for SSL/TLS.
- Logging & Monitoring: Integrate production-grade tools.
(CI/CD setup would involve steps like linting, testing, building, artifact storage, and deployment.)
Frequently Asked Questions About Plivo NestJS Integration
Q: Can I use Plivo with other Node.js frameworks besides NestJS? A: Yes, the Plivo Node.js SDK works with Express, Fastify, Koa, and other frameworks. See our guides for Plivo with Express and Plivo with Fastify.
Q: How much does it cost to send SMS with Plivo? A: Plivo pricing varies by destination country and message volume. Check Plivo's pricing page for current rates. Trial accounts include free credits.
Q: What's the difference between sending SMS to US numbers vs international numbers? A: US/Canada SMS typically requires 10DLC registration for application-to-person messaging. International SMS may use Alphanumeric Sender IDs in some countries for better brand recognition.
Q: How do I handle incoming SMS messages in NestJS? A: Configure a webhook endpoint in your NestJS application to receive incoming message callbacks from Plivo. See our guide on two-way SMS messaging with NestJS.
Q: Can I send MMS (multimedia messages) with this setup? A: Yes, the Plivo SDK supports MMS. Check our MMS sending guide for adding image and video support.
Related Resources
- Plivo Bulk SMS Broadcasting with NestJS
- Building Two-Factor Authentication with Plivo and NestJS
- SMS Delivery Status Callbacks in NestJS
- Understanding E.164 Phone Number Format
- 10DLC SMS Registration Guide
Pre-Launch Verification Checklist
- Project Setup: NestJS created, dependencies (
plivo,@nestjs/config,class-validator,class-transformer) installed. - Plivo Account: Active Plivo account.
- Credentials: Auth ID/Token correctly retrieved.
- Sender ID: Valid Plivo Number (E.164) or Alphanumeric Sender ID obtained.
- Environment:
.envcreated locally with correctPLIVO_*vars..envin.gitignore. (Prod env vars configured separately). - Configuration Module:
ConfigModule.forRoot({...})inAppModule. - Plivo Service:
PlivoServicecreated,plivo.Clientinitialized (v3 noted),sendSmsimplemented withtry/catch, logging,BadRequestExceptionfor format validation,InternalServerErrorExceptionfor API errors. - DTO:
SendSmsDtocreated withclass-validatordecorators (IsString,IsNotEmpty,Matchesfor E.164,MaxLength). - SMS Controller:
SmsControllercreated,PlivoServiceinjected,POST /sms/sendendpoint defined,@Body()usesSendSmsDto,ValidationPipeapplied (globally or locally), success response formatted, error handling re-throwsHttpException. - Module Registration:
SmsControllerandPlivoServiceregistered inAppModule. - Local Test (Success): Ran
npm run start:dev, sent valid POST request via cURL/Postman, received 2xx response withplivoMessageId, SMS received on target (verified) phone. - Local Test (Validation Failure): Sent invalid request (missing field, bad format), received 400 response with validation errors.
- Local Test (Config/API Failure): Tested invalid credentials/sender ID/trial number, observed expected 400/500 errors and logs.
- Security:
.envin.gitignore, considered rate limiting/auth for production.