Frequently Asked Questions
Install the Infobip SDK (`npm install @infobip-api/sdk`) and the NestJS ConfigModule (`npm install @nestjs/config`). Create a NestJS service to handle sending SMS using the Infobip API and a controller to create an endpoint to trigger the SMS sending functionality. Configure environment variables for your Infobip API key and base URL. Finally, create a DTO for request validation.
The Infobip Node.js SDK (`@infobip-api/sdk`) simplifies interaction with the Infobip API. It provides pre-built methods for sending SMS messages and handles authentication, reducing the need for direct API calls and simplifying the development process.
NestJS provides a robust, structured framework with features like dependency injection, modularity, and built-in configuration management. This simplifies development, testing, and maintenance of SMS sending services compared to plain Node.js.
Use bulk sending when you need to send multiple messages at once, either to different recipients or the same message to many. It's more efficient than individual API calls, reducing overhead and improving performance, especially for high-volume messaging.
Yes, you can use a free trial Infobip account for initial testing. However, be aware of limitations, such as typically being able to send SMS only to the registered phone number during the trial and possible restrictions on sender IDs.
Implement try-catch blocks in your service and controller to handle errors during API calls. Use NestJS's Logger to log error details and optionally create custom exception filters for consistent error responses. Consider retry mechanisms for transient network issues, using exponential backoff to avoid overwhelming the API.
Protect your API key using environment variables and .gitignore. Validate input using DTOs and a ValidationPipe, implement rate limiting with libraries like @nestjs/throttler, and add authentication/authorization (JWT, API keys, OAuth2) to restrict access.
Infobip expects international format, but basic regex validation isn't sufficient. Use a library like libphonenumber-js for robust international number handling, validation, and formatting, accounting for varying country codes and number formats.
Check for trial account limitations, verify the recipient number, examine Infobip's delivery reports using messageId, test with a known valid number, and review sender ID rules for the destination country. Also check your account balance or contact Infobip support if problems continue.
For high volume, use Infobip's bulk sending feature to send multiple messages in a single API call. Implement asynchronous processing with a message queue for very high throughput, decoupling API requests from actual sending. Consider connection pooling if needed for high concurrency.
While sending a single SMS doesn't strictly require a database, for real-world applications, consider PostgreSQL with TypeORM for storing SMS logs, managing recipients, and tracking status updates via webhooks. Ensure appropriate error handling and security measures are also in place.
Create a .env file in your project's root directory. Add your INFOBIP_API_KEY and INFOBIP_BASE_URL from the Infobip portal. Import and configure the ConfigModule in your app.module.ts to make these environment variables accessible in your NestJS application. Never commit your .env file to version control.
The recommended structure includes a sms module with a service and controller for handling SMS logic and API requests. This modular organization promotes code maintainability and separation of concerns.
Use a library like async-retry to wrap your Infobip API calls. Configure retries with exponential backoff, but avoid retrying non-transient errors like invalid API keys. Ensure you're checking for specific error responses from the API to decide when to retry.
This guide provides a step-by-step walkthrough for building a production-ready service using Node.js and the NestJS framework to send SMS messages via the Infobip API. We will cover project setup, core implementation, API creation, configuration management, error handling, security considerations, and testing.
By the end of this tutorial, you will have a functional NestJS application capable of accepting API requests to send SMS messages, securely configured using environment variables, and incorporating basic logging and error handling.
Project Overview and Goals
What We're Building:
We will create a simple NestJS application with a single API endpoint. This endpoint will accept a destination phone number and a message text, then use the Infobip Node.js SDK to send the SMS message.
Problem Solved:
This provides a foundational microservice or module for applications needing programmatic SMS capabilities – for notifications, alerts, verification codes, or other communication needs – abstracting the direct interaction with the Infobip API into a reusable service within a standard Node.js framework.
Technologies Used:
@infobip-api/sdk
): Simplifies interaction with the Infobip API by providing pre-built methods and handling authentication.System Architecture:
The architecture follows this flow:
/sms/send
endpoint, handled by theSmsController
.SmsController
uses theSmsService
.SmsService
uses theConfigService
to read credentials from the.env
file.SmsService
calls the Infobip Node.js SDK.Prerequisites:
Final Outcome:
A NestJS application running locally with an endpoint (
POST /sms/send
) that successfully sends an SMS via Infobip when provided with valid credentials and recipient details.1. Setting up the Project
Let's initialize a new NestJS project and install the necessary dependencies.
Create a new NestJS Project: Open your terminal and run the NestJS CLI command:
When prompted, choose your preferred package manager (npm or yarn). We'll use
npm
in these examples.Navigate to Project Directory:
Install Infobip SDK: Add the official Infobip Node.js SDK to your project:
Install Configuration Module: NestJS provides a dedicated module for handling environment variables and configuration.
(Note:
@nestjs/config
usesdotenv
under the hood).Set up Environment Variables: Create a
.env
file in the root of your project. This file will store sensitive credentials and configuration details. Never commit this file to version control.YOUR_INFOBIP_API_KEY
with the actual API key from your Infobip account.YOUR_INFOBIP_BASE_URL
with the specific base URL provided for your account (e.g.,xxxxx.api.infobip.com
).Configure the
ConfigModule
: Import and configure theConfigModule
in your main application module (src/app.module.ts
). This makes environment variables accessible throughout your application via theConfigService
.isGlobal: true
allows injectingConfigService
into any module without needing to importConfigModule
everywhere.envFilePath: '.env'
tells the module where to load the variables from.Project Structure: Your basic project structure will look like this after these steps (NestJS generates some files automatically):
2. Implementing Core Functionality (SMS Service)
We'll encapsulate the logic for interacting with the Infobip SDK within a dedicated NestJS service.
Generate the SMS Module and Service: Use the NestJS CLI to generate a module and a service for SMS functionality:
This creates the
src/sms/
directory withsms.module.ts
andsms.service.ts
(and a spec file).Implement the
SmsService
: Opensrc/sms/sms.service.ts
and implement the logic to initialize the Infobip client and send messages.ConfigService
to securely retrieve the API key and base URL.Infobip
) is instantiated in the constructor using credentials from the configuration.sendSms
method constructs the payload required by the SDK'schannels.sms.send
function.Logger
is added for monitoring.try...catch
block handles potential errors during the API call, logging details and throwing an appropriate error.messageId
from the success response, which is useful for tracking.Export the Service: Ensure
SmsService
is listed in theproviders
andexports
arrays insrc/sms/sms.module.ts
so it can be injected into other modules (like our future controller).3. Building the API Layer (SMS Controller)
Now, let's create an API endpoint to trigger the SMS sending functionality.
Generate the SMS Controller:
This creates
src/sms/sms.controller.ts
. We add--no-spec
to skip the test file for brevity in this step.Install Validation Packages: NestJS uses
class-validator
andclass-transformer
for request validation via Data Transfer Objects (DTOs).Enable Validation Pipe: Globally enable the
ValidationPipe
insrc/main.ts
to automatically validate incoming request bodies against DTOs.Create a Request DTO: Define a DTO (
Data Transfer Object
) to represent the expected structure and validation rules for the request body. Create a new directorysrc/sms/dto
and a filesrc/sms/dto/send-sms.dto.ts
.@IsString
,@IsNotEmpty
,@Length
,@Matches
, and@IsOptional
define validation rules.Implement the
SmsController
: Opensrc/sms/sms.controller.ts
and define the endpoint.@Controller('sms')
decorator sets the base route/sms
.@Post('send')
defines a POST endpoint at/sms/send
.@Body()
decorator tells NestJS to parse the request body and validate it against theSendSmsDto
(thanks to the globalValidationPipe
).SmsService
and calls itssendSms
method.Import the Controller: Ensure
SmsController
is added to thecontrollers
array insrc/sms/sms.module.ts
.4. Integrating with Infobip (Configuration Details)
We've already set up the configuration loading, but let's detail obtaining the credentials.
Log in to Infobip: Access your Infobip Portal.
Find API Key: Navigate to the API Keys management section. This is often found under your account settings or a dedicated ""Developers"" or ""API"" section. Generate a new API key if you don't have one. Copy the key value.
Find Base URL: Your account-specific Base URL is usually displayed prominently on the API documentation landing page within the portal after you log in, or sometimes near the API key management section. It will look something like
xxxxx.api.infobip.com
. Copy this URL.Update
.env
: Paste the copied API Key and Base URL into your.env
file created in Step 1.5.Security: Remember that your
.env
file contains sensitive credentials..env
is listed in your.gitignore
file (NestJS includes it by default).5. Error Handling, Logging, and Retries
Error Handling: We implemented basic
try...catch
blocks in both the service and controller. The service attempts to parse specific Infobip errors, and the controller either re-throws the error for NestJS's default exception filter (which typically returns a 500 Internal Server Error for unhandled exceptions or specific statuses forHttpException
) or can be customized to return specific error formats. Consider creating custom exception filters in NestJS for more consistent error responses across your application.Logging: We use the built-in
Logger
. In a production environment, you would configure more robust logging:Retry Mechanisms: For transient network issues or temporary Infobip API unavailability, implementing a retry strategy can improve resilience.
infobipClient.channels.sms.send
call in a loop with a delay.async-retry
can simplify this.Example Snippet Concept (using
async-retry
- requiresnpm install async-retry @types/async-retry
):6. Database Schema and Data Layer
For this specific task of sending a single SMS, a database is not strictly required. However, in a real-world application, you would likely integrate a database to:
messageId
, status). This is crucial for auditing, tracking, and debugging.If adding a database (e.g., PostgreSQL with TypeORM):
Install Dependencies:
npm install @nestjs/typeorm typeorm pg
Configure
TypeOrmModule
: Set up connection details (likely viaConfigService
).Define Entities: Create TypeORM entities (e.g.,
SmsLog
) representing your database tables.Create Repositories: Inject the repository (
@InjectRepository(SmsLog)
) into yourSmsService
to interact with the database (save logs before sending, update status andmessageId
after successful submission, update status via webhook handler).Migrations: Use TypeORM migrations to manage schema changes (
typeorm migration:generate -n InitialSchema
,typeorm migration:run
).7. Security Features
.gitignore
. Ensure proper secrets management in production.class-validator
decorators in the DTO and the globalValidationPipe
. This prevents malformed requests and basic injection attempts in the validated fields.@nestjs/throttler
to limit the number of requests per user or IP address within a specific time window.app.module.ts
and apply the guard globally or to specific controllers/routes.@nestjs/jwt
and@nestjs/passport
.helmet
middleware (vianpm install helmet
) insrc/main.ts
(app.use(helmet());
) to set various security-related HTTP headers (XSS protection, disabling content sniffing, etc.).from
field). Infobip may enforce specific rules depending on the country. Do not allow arbitrary user input for thefrom
field unless strictly controlled and validated.8. Handling Special Cases
447123456789
for UK,14155552671
for US). The basic validation regex (/^\d{10,15}$/
) used earlier is very limited (e.g., it doesn't handle leading '+' signs, variable country code lengths, or specific national number formats). For robust international number handling, using a dedicated library likelibphonenumber-js
(npm install libphonenumber-js
) is strongly recommended for parsing, validation, and formatting based on country codes if your application handles diverse international numbers. You would integrate this validation within the DTO or the service layer.text
input. The SDK should handle encoding correctly for standard text. You might want to add length validation or warnings based on segment counts.9. Performance Optimizations
For sending single SMS messages on demand, performance bottlenecks are unlikely within this simple service itself. However, if scaling to high volume or bulk sending:
messages
array. This is significantly more efficient than making individual API calls in a loop. Modify theSmsService
and API to accept arrays of recipients/messages.PENDING
status, and place a job onto a message queue (like RabbitMQ, Kafka, BullMQ). A separate worker service would then consume from the queue, interact with the Infobip API (potentially using bulk sending), handle retries robustly, and update the database status.UV_THREADPOOL_SIZE
environment variable if needed for other blocking operations, though less relevant for pure network I/O) if performing many concurrent outbound requests or other CPU/IO-intensive tasks.10. Monitoring, Observability, and Analytics
/health
) using@nestjs/terminus
. This allows load balancers or monitoring systems to verify the service is running and optionally check dependencies (like database connectivity). Checking Infobip reachability might be excessive for a basic health check but could be part of a deeper diagnostic check./sms/send
endpoint).infobipClient.channels.sms.send
).prom-client
) and expose a/metrics
endpoint, or integrate with APM tools (Datadog APM, New Relic, Dynatrace).@sentry/node
) or equivalent to capture, aggregate, and alert on unhandled exceptions and errors in real-time. Integrate with the NestJS exception filter or logger.messageId
andbulkId
returned by Infobip to correlate application logs with Infobip's delivery reports or webhooks.11. Troubleshooting and Caveats
Unauthorized
/Invalid login details
(Infobip Response)INFOBIP_API_KEY
orINFOBIP_BASE_URL
. The Base URL must be the specific one assigned to your account, not a generic one..env
file against those provided in the Infobip portal. Ensure there are no extra spaces or characters. Verify theConfigModule
is loading the.env
file correctly.Missing permissions
/Forbidden
(Infobip Response)Invalid destination address
to
phone number format is incorrect or the number itself is invalid/not reachable.44...
,1...
, without leading+
or00
usually, but check Infobip docs). Implement robust phone number validation (e.g., usinglibphonenumber-js
). Check if the number is valid.to
number, carrier filtering/blocking, Sender ID issues (e.g., blocked alphanumeric ID in a country requiring numeric), insufficient funds on Infobip account.to
number. Check Infobip delivery reports using themessageId
. Test with a known valid number. Review Sender ID rules for the destination country. Check account balance. Contact Infobip support if issues persist..env
file not found at the expected path,ConfigModule
not configured correctly (envFilePath
), variables misspelled in.env
orconfigService.get()
..env
file location and name. CheckAppModule
configuration forConfigModule.forRoot()
. Ensure variable names match exactly. Add logging in theSmsService
constructor to print the loaded values (remove before production).SendSmsDto
structure or validation rules (@IsString
,@Length
,@Matches
, etc.).Content-Type: application/json
header is sent. Review the DTO validation rules and compare them against the request. The error response from NestJS'sValidationPipe
usually details which fields failed validation.