Frequently Asked Questions
You can send SMS messages with NestJS by integrating the Vonage Messages API. Create a NestJS service that uses the Vonage Node.js Server SDK to interact with the API. Expose a POST endpoint in a controller to handle incoming SMS requests and trigger the sending logic implemented in the service.
The Vonage Messages API is a unified API for sending messages through various channels, including SMS. It's known for its robust features, global reach, and developer-friendly tools like the Node.js Server SDK, making it suitable for applications needing to send notifications or alerts.
NestJS provides a structured and efficient framework for building server-side applications in Node.js. Its modular architecture, dependency injection, and features like validation and configuration management make it ideal for integrating with external APIs like Vonage Messages.
First, create a Vonage API account. Then, set the Messages API as the default SMS setting in your Vonage dashboard, which is crucial for this process. You'll need to create a Vonage Application, generate keys, enable Messages capability and link your Vonage number. Finally, configure your environment variables in you .env
file.
You'll need Node.js and npm/yarn installed, a Vonage API account (free credits available), and basic knowledge of TypeScript, Node.js, and REST APIs. Familiarity with a terminal/command prompt and optionally Postman or curl
for testing are helpful.
Save your private.key
file in your project root and reference its path in your .env
file, not directly in code. Add both .env
and private.key
to your .gitignore
to prevent accidental commits. Do not embed the key directly into your codebase. In production, use a proper secrets management solution like AWS Secrets Manager or HashiCorp Vault.
Use NestJS's ValidationPipe with Data Transfer Objects (DTOs). Create a DTO (e.g., SendSmsDto
) with class-validator decorators (@IsNotEmpty, @IsPhoneNumber, @Length) to define validation rules for properties like recipient number and message text.
A NestJS application with a POST endpoint (/sms/send
) that accepts recipient phone number and message text, sending the message via Vonage Messages API. You'll have error handling, logging, and configuration management in place, which are essential for production-ready applications.
Consider Vonage Messages API when you need a unified API across multiple messaging channels, not just SMS. Its robust features, global reach, and well-maintained SDKs are advantages for serious applications.
This tutorial covers only sending SMS. Receiving SMS and delivery receipts require webhooks, a more advanced topic covered in Vonage documentation but beyond the scope of this guide.
Use try...catch blocks in your service to handle errors from the Vonage SDK. Log these errors with a NestJS Logger and throw specific HttpExceptions at the controller level with appropriate status codes (e.g., 500 Internal Server Error) and detailed error messages for clients.
For unit tests, mock the ConfigService, Vonage SDK (vonage.messages.send
), and the 'fs' module using Jest. Test success and failure scenarios for the sendSms
method. For end-to-end (e2e) tests, use supertest to make real HTTP requests and check responses, including validation errors and service layer errors.
Protect your Vonage API credentials, especially the private key. Use robust input validation to prevent injection attacks and malformed data. Implement rate limiting using @nestjs/throttler to prevent abuse and unexpected costs. Add authentication/authorization to your /sms/send
endpoint to control access.
Send SMS with NestJS and Vonage Messages API: Complete Tutorial
Quick Answer: Send SMS with NestJS and Vonage in 5 Steps
To send SMS with NestJS and Vonage: (1) Install
@vonage/server-sdk
via npm, (2) Configure Vonage Application ID and private key using NestJS ConfigModule, (3) Create an SMS service that initializes the Vonage client, (4) Build a controller with a validated POST endpoint (/sms/send
), (5) Callvonage.messages.send()
with proper error handling. This complete tutorial covers setup, authentication, validation, testing, and production deployment.This comprehensive guide walks you through building a production-ready NestJS application for sending SMS messages using the Vonage Messages API. You'll learn project setup, Vonage authentication, service implementation, API endpoint creation, input validation, error handling, security best practices, testing strategies, and deployment considerations.
By the end of this tutorial, you will have a fully functional NestJS SMS service with a REST API endpoint that sends text messages reliably through Vonage. This solves common business needs like sending notifications, alerts, verification codes, and OTPs (One-Time Passwords) programmatically.
Technologies Used:
Prerequisites:
curl
for testing API endpoints.Final Outcome:
A production-ready NestJS application with a POST endpoint (
/sms/send
) that accepts a recipient phone number and message text, validates the input, and sends the SMS via the Vonage Messages API with comprehensive error handling.(Note: This guide focuses on sending SMS messages. To receive inbound SMS or delivery receipts, you need to configure webhooks, which is covered in the Vonage webhooks documentation but is beyond the scope of this tutorial.)
1. Setting up the NestJS Project
First, create a new NestJS project and install the necessary dependencies for SMS functionality.
Install NestJS CLI (Command Line Interface): If you don't have it installed globally, run:
Create NestJS Project: Navigate to your desired parent directory in the terminal and run:
Choose your preferred package manager (npm or yarn) when prompted. This command scaffolds a new NestJS project with a standard structure including TypeScript configuration, testing setup, and essential dependencies.
Navigate to Project Directory:
Install Dependencies: Install the Vonage Server SDK and NestJS's configuration module.
@vonage/server-sdk
: The official Vonage library for Node.js.@nestjs/config
: For managing environment variables within NestJS applications.dotenv
: To load environment variables from a.env
file during development.Project Structure Overview:
Your initial project structure will look something like this:
You will primarily work within the
src
directory, creating new modules, controllers, and services for SMS functionality.2. Configuring Vonage Messages API Credentials
To interact with the Vonage API, you need proper authentication credentials and a Vonage phone number. The Vonage Messages API requires an Application ID and a private key for secure authentication.
Log in to Vonage Dashboard: Access your Vonage API Dashboard.
Find API Key and Secret: Your API Key and Secret are displayed at the top of the dashboard home page. Note these down as you may need them for certain operations or when using the Vonage CLI tool.
Set Messages API as Default (Crucial):
Create a Vonage Application:
private.key
file. Save this file securely – you'll place it in your project root later. The public key is stored by Vonage automatically.https://example.com/status
,https://example.com/inbound
). These are required fields for receiving messages or delivery receipts, but not strictly necessary for sending only. However, Vonage requires valid HTTPS URLs here.Link a Vonage Number:
14155550100
).Configure Environment Variables:
private.key
file you downloaded into the root directory of yourvonage-sms-app
project..env
in the project root directory.VONAGE_APPLICATION_ID
: The unique ID of the Vonage application you created. Found on the Application details page in the dashboard.VONAGE_PRIVATE_KEY_PATH
: The relative path from your project root to theprivate.key
file you downloaded.VONAGE_NUMBER
: The Vonage virtual phone number you linked to the application, in E.164 format (e.g.,14155550100
). This will be the "from" number for outgoing SMS messages.VONAGE_API_KEY
/VONAGE_API_SECRET
: Your main account API key/secret. Not directly used for sending via Messages API in this code, but good to store for other potential uses (like CLI operations or other Vonage services).PORT
: The port your NestJS application will run on (default is 3000).Update
.gitignore
: Ensure your.env
file andprivate.key
are not committed to version control. Add these lines to your.gitignore
file if they aren't already present:Load Configuration in NestJS: Modify
src/app.module.ts
to load the.env
file usingConfigModule
.ConfigModule.forRoot({...})
: Initializes the configuration module.isGlobal: true
: Makes theConfigService
available throughout your application without needing to importConfigModule
in every feature module.envFilePath: '.env'
: Tells the module where to find the environment variables file.3. Implementing the SMS Service with Dependency Injection
Now, create a dedicated module and service in NestJS to handle the logic for sending SMS messages using proper dependency injection patterns.
Generate SMS Module and Service: Use the NestJS CLI to generate the necessary files:
This creates a
src/sms
directory containingsms.module.ts
andsms.service.ts
(and spec file for testing).Implement
SmsService
: Opensrc/sms/sms.service.ts
and implement the logic to initialize the Vonage SDK and send messages.ConfigService
to retrieve environment variables. Initializes theVonage
SDK instance using the Application ID and the content of the private key file (read usingfs.readFileSync
). It includes checks to ensure credentials and the key file exist.sendSms
Method:to
) and messagetext
as arguments.to
number format.payload
object according to the Vonage Messages API requirements for SMS (message_type: 'text'
,channel: 'sms'
,to
,from
,text
).this.vonage.messages.send(payload)
to send the SMS. Note the use ofmessages
, notmessage
.async/await
for cleaner asynchronous code.Logger
.message_uuid
on success or throws an error on failure.Update
SmsModule
: EnsureSmsService
is listed as a provider and exported so it can be used in other modules (like the controller you'll create next).Import
SmsModule
inAppModule
: Now uncomment theSmsModule
import insrc/app.module.ts
.4. Building the SMS API Endpoint with Validation
Create a controller with an endpoint that accepts POST requests to trigger the SMS sending functionality with proper input validation.
Generate SMS Controller:
This creates
src/sms/sms.controller.ts
(and spec file for testing).Create Request DTO (Data Transfer Object): Create a file
src/sms/dto/send-sms.dto.ts
for validating the incoming request body. Install validation dependencies if you haven't already:Note: This uses class-validator v0.14.2 (May 2024) and class-transformer (actively maintained), which are the most commonly used validation packages in NestJS due to their decorator-based approach that integrates seamlessly with NestJS's ValidationPipe.
Now, define the DTO:
class-validator
to define validation rules.@IsNotEmpty()
: Ensures the field is not empty.@IsPhoneNumber(null)
: Validates if the string is a phone number (accepts various formats, but E.164 is recommended for Vonage). Setting region tonull
allows international numbers.@IsString()
: Ensures the field is a string.@Length(1, 1600)
: Ensures the message text has a reasonable length. Vonage SMS limits:Implement
SmsController
: Opensrc/sms/sms.controller.ts
and define the POST endpoint.@Controller('sms')
: Defines the base route for this controller.SmsService
.@Post('send')
: Defines a handler for POST requests to/sms/send
.@UsePipes(new ValidationPipe(...))
: Applies the validation pipe to this route.transform: true
: Automatically transforms the incoming JSON payload into an instance ofSendSmsDto
.whitelist: true
: Strips any properties from the request body that are not defined in the DTO.@Body() sendSmsDto: SendSmsDto
: Injects the validated and transformed request body into thesendSmsDto
parameter.smsService.sendSms
method. Returns a success response with themessageId
. NestJS handles the 201 status. Throws anHttpException
with a 500 status code if the service throws an error.Register Controller in
SmsModule
: Uncomment theSmsController
insrc/sms/sms.module.ts
.Enable Global Validation Pipe (Optional but Recommended): Instead of applying
@UsePipes
to every handler, you can enable theValidationPipe
globally insrc/main.ts
.If you do this, you can remove the
@UsePipes(...)
decorator from theSmsController
.5. Error Handling and Logging Best Practices
You've already incorporated basic logging and error handling:
Logger
instances in both the service and controller provide context-specific logs for requests, successes, and failures. Check your console output when running the app.ValidationPipe
automatically handles request validation errors, returning 400 Bad Request responses with details about the validation failures.SmsService
catches errors from the Vonage SDK (try...catch
) and logs them before re-throwing.SmsController
catches errors from the service and transforms them into standardHttpException
responses, ensuring consistent JSON error formats for the client.Further Enhancements:
6. Security Considerations for Production SMS Services
While this is a simple service, security is paramount:
.env
file orprivate.key
to Git. Ensure they are in.gitignore
..env
files. Inject these secrets as environment variables into your deployed application.private.key
on your server (chmod 400 private.key
).ValidationPipe
andSendSmsDto
. This prevents malformed requests and potential injection issues related to input data.forbidNonWhitelisted: true
in the global pipe adds an extra layer of protection against unexpected input fields.@nestjs/throttler
module is excellent for this.npm install @nestjs/throttler
app.module.ts
:ttl
andlimit
as needed./sms/send
endpoint itself. In a real-world application, protect this endpoint using strategies like API Keys, JWT tokens, or OAuth, ensuring only authorized clients can trigger SMS sending. NestJS provides modules and strategies for implementing these. For more details, see the NestJS authentication documentation.7. Testing the SMS Implementation (Unit and E2E Tests)
Testing ensures your service works as expected and helps prevent regressions.
Unit Testing (
SmsService
):sms.service.spec.ts
).@nestjs/testing
to create a testing module.ConfigService
,Vonage
SDK,fs
). Jest's mocking capabilities are ideal here.sendSms
method:vonage.messages.send
with the correct payload.send
to resolve successfully).send
to reject with an error).Example Snippet:
E2E (End-to-End) Testing (
SmsController
):test
directory.@nestjs/testing
andsupertest
to make HTTP requests to your running application instance (or a test instance)./sms/send
endpoint:SmsService.sendSms
to reject) and check for 500 Internal Server Error responses.Example Snippet (Conceptual):
Frequently Asked Questions (FAQ)
What is the difference between Vonage SMS API and Messages API?
The Vonage SMS API is the legacy API for sending SMS messages, while the Messages API is the newer, unified API that supports multiple channels (SMS, MMS, WhatsApp, Viber, Facebook Messenger) through a single interface. The Messages API uses Application ID and private key authentication instead of API Key/Secret, provides better error handling, and is the recommended approach for new applications. This tutorial uses the Messages API for maximum flexibility and future compatibility.
How much does it cost to send SMS with Vonage?
Vonage SMS pricing varies by destination country and typically ranges from $0.0037 to $0.15 per message. New accounts receive free trial credits (usually $2 – $10) to test the service. Pricing is per-segment: messages up to 160 GSM-7 characters or 70 unicode characters count as one segment, while longer messages split into 153-character (GSM-7) or 67-character (unicode) segments with each segment billed separately. Check the Vonage Pricing page for current rates in your target countries.
Can I use Vonage with NestJS for two-factor authentication (2FA)?
Yes, you can use Vonage with NestJS for 2FA/OTP verification. However, Vonage offers a dedicated Verify API specifically designed for 2FA that handles OTP generation, delivery, retry logic, and verification automatically. For simple SMS-based 2FA, you can use this tutorial's implementation to send randomly generated codes, then store and validate them server-side. For production 2FA, consider using Vonage Verify API, which provides built-in rate limiting, fraud detection, and fallback channels (SMS → voice call).
How do I receive SMS messages and delivery receipts in NestJS?
To receive inbound SMS messages and delivery receipts, you need to create webhook endpoints in your NestJS application. Create a new controller with POST endpoints for inbound messages (
/webhooks/inbound-sms
) and delivery receipts (/webhooks/delivery-receipt
), configure these URLs in your Vonage Application settings (they must be publicly accessible HTTPS URLs), and use DTOs withclass-validator
to validate the webhook payloads. For local development, use ngrok to expose your localhost to the internet. The webhook payloads contain message status, timestamps, error codes, and sender information.What is E.164 phone number format and why does Vonage require it?
E.164 is the international standard for phone number formatting:
+[country code][subscriber number]
with no spaces, hyphens, or parentheses (e.g.,+14155550100
for a US number). Vonage requires E.164 format because it eliminates ambiguity about country codes and ensures reliable message delivery worldwide. The@IsPhoneNumber(null)
validator fromclass-validator
accepts E.164 format. Always store and transmit phone numbers in E.164 format, but you can display them with formatting for user interfaces.How do I handle SMS sending errors in NestJS with Vonage?
The Vonage SDK throws errors with specific properties that help identify issues. Common errors include: Authentication failures (invalid Application ID or private key, HTTP 401), Insufficient credit (account balance too low, HTTP 402), Invalid phone numbers (malformed recipient, HTTP 400), Rate limiting (too many requests, HTTP 429), and Network timeouts (connectivity issues). Wrap
vonage.messages.send()
calls intry...catch
blocks, log errors with context using NestJS Logger, inspecterror.response?.data
for Vonage-specific error details, throw appropriateHttpException
instances with user-friendly messages, and implement retry logic for transient errors using libraries likeasync-retry
.Can I send bulk SMS messages with this NestJS implementation?
This tutorial's implementation sends single SMS messages per API call. For bulk messaging (hundreds or thousands of recipients), you should: Use Vonage Campaigns API for marketing messages (supports opt-out management and scheduling), implement queue-based processing using Bull or BullMQ to avoid overwhelming your API with concurrent requests, add rate limiting logic to respect Vonage's API rate limits (typically 30 – 100 requests/second depending on your account tier), use Promise.all() with batching for parallel sends with controlled concurrency, and store message results in a database for tracking delivery status and failures. Consider Vonage's Bulk SMS or Campaigns API for large-scale messaging needs.
How do I test SMS sending without actually sending messages?
For testing without sending real SMS messages: Mock the Vonage SDK in unit tests using Jest's
jest.mock()
to simulate successful sends and error conditions, Use Vonage's test credentials (some SMS APIs provide sandbox/test modes, though Vonage primarily uses real credentials), Send to your own phone numbers during development (free trial credits cover testing), Implement a "dry run" mode with an environment variable (SMS_DRY_RUN=true
) that logs intended sends without calling the Vonage API, and Use E2E tests with mocked service layer to test controller validation and error handling without actual API calls (see Section 7 for examples).What are the SMS character limits and encoding types?
Vonage supports two encoding types: GSM-7 (standard English alphabet, numbers, basic symbols) allows 160 characters per single message or 153 characters per segment for concatenated messages (7-byte UDH header overhead), while UCS-2/Unicode (emoji, non-Latin scripts, special characters) allows 70 characters per single message or 67 characters per segment for concatenated messages. Messages automatically use UCS-2 if they contain any unicode characters, which significantly reduces the character limit. To maximize efficiency: avoid emoji in transactional SMS, use GSM-7 characters when possible (check GSM-7 character set), and be aware that some characters like
[]{}|^€~\\
count as 2 characters in GSM-7 encoding.How do I deploy this NestJS SMS service to production?
To deploy your NestJS SMS service to production: Use environment-based secrets management (AWS Secrets Manager, Azure Key Vault, Google Secret Manager) instead of
.env
files, Enable HTTPS using load balancers, reverse proxies (Nginx, Caddy), or platforms with built-in SSL (Heroku, Vercel), Implement rate limiting with@nestjs/throttler
to prevent abuse and control costs, Add authentication (JWT, API keys, OAuth) to protect the/sms/send
endpoint, Configure structured logging (Winston, Pino) with log aggregation (Datadog, CloudWatch, ELK), Set up monitoring and alerts for SMS failures, rate limit hits, and cost thresholds, Use PM2 or Docker for process management and zero-downtime deployments, and Implement retry logic and dead letter queues for handling transient failures. Consider platforms like AWS ECS, Google Cloud Run, or DigitalOcean App Platform for containerized deployments.Recap and Next Steps
What You've Built:
You've created a production-ready NestJS application that:
POST /sms/send
) for sending SMS messagesNext Steps:
/sms/send
endpoint with API keys, JWT tokens, or OAuthFor more information, consult the Vonage API Documentation and the NestJS Documentation.