code examples

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

Send SMS with Node.js and Express: Complete Infobip API Integration Guide

Learn how to build a Node.js SMS API using Express and Infobip. Step-by-step tutorial covering setup, authentication, error handling, and best practices for sending SMS programmatically.

Send SMS with Node.js and Express: Infobip API Integration Tutorial

Build a Node.js application using Express to send SMS messages via the Infobip API. This tutorial covers project setup, implementation, API key management, error handling, and testing.

You'll create a functional Express API endpoint that accepts a phone number and message text, then dispatches the SMS through Infobip. Use this as a foundation for integrating SMS functionality into larger applications.

Project Overview and Goals

  • Goal: Create a backend service that sends SMS messages programmatically.
  • Problem Solved: Automates transactional SMS sending, eliminating manual processes and enabling system integration.
  • Technologies Used:
    • Node.js: JavaScript runtime for server-side applications (requires v18.x or v20.x LTS). Chosen for asynchronous I/O and extensive npm ecosystem.
    • Express: Minimal Node.js web framework. Chosen for simple API route setup.
    • Axios: Promise-based HTTP client. Chosen for reliable Infobip API requests.
    • dotenv: Loads environment variables from .env files. Chosen for secure API key management.
    • Infobip API: Third-party SMS gateway service (API v2).
  • Architecture: +-----------------+ +-----------------+ +-----------------+ | Client (e.g. UI,| ---> | Node.js/Express | ---> | Infobip API | | Postman, curl) | | API Service | | (SMS Gateway) | +-----------------+ +-----------------+ +-----------------+ (HTTP POST (Uses Axios to call (Sends SMS to request with Infobip API with recipient) number/text) API Key & Base URL)
  • Outcome: A running Express server with endpoint POST /api/v1/sms/send that triggers SMS delivery via Infobip.
  • Prerequisites:
    • Node.js v18.x or v20.x LTS and npm installed. Use Node Version Manager (nvm) to manage versions.
    • Active Infobip account. Create one at infobip.com.
    • Basic JavaScript, Node.js, REST APIs, and command-line knowledge.
    • Free Trial Limitation: Infobip trial accounts can only send SMS to the phone number verified during signup. Testing other numbers fails until you fund the account.

Setting Up Your Node.js SMS Project

Initialize your Node.js project and install dependencies.

  1. Create Project Directory: Open your terminal and create a new directory. Navigate into it.

    bash
    mkdir infobip-sms-sender
    cd infobip-sms-sender
  2. Initialize Node.js Project: Run npm init to create package.json. Accept defaults with the -y flag.

    bash
    npm init -y

    This creates package.json, which tracks project metadata and dependencies.

  3. Install Dependencies: Install express for the web server, axios for HTTP requests, and dotenv for environment variables.

    bash
    npm install express axios dotenv

    This downloads packages to node_modules and lists them in package.json.

  4. Set up Project Structure: Create this directory structure within infobip-sms-sender:

    infobip-sms-sender/ ├── node_modules/ ├── src/ │ ├── controllers/ │ │ └── smsController.js │ ├── routes/ │ │ └── smsRoutes.js │ └── services/ │ └── infobipService.js ├── .env ├── .gitignore ├── app.js └── package.json
    • src/: Application source code.
    • controllers/: Handles incoming requests and orchestrates responses.
    • routes/: Defines API endpoints and maps them to controllers.
    • services/: Business logic for interacting with the Infobip API.
    • .env: Stores environment variables (API keys, configuration). Never commit this file.
    • .gitignore: Specifies files Git should ignore (node_modules, .env).
    • app.js: Main entry point for the Express application.
  5. Configure .gitignore: Create .gitignore in the project root:

    text
    # Dependencies
    node_modules/
    
    # Environment variables
    .env
    
    # Logs
    logs
    *.log
    npm-debug.log*
    yarn-debug.log*
    yarn-error.log*
    pids
    *.pid
    *.seed
    *.pid.lock
    
    # Optional Editor directories
    .vscode/
    .idea/
  6. Configure Environment Variables (.env): Create .env in the project root. You need your Infobip API Key and Base URL.

    • Find your Infobip credentials:
      1. Log in to Infobip Portal.
      2. Navigate to the Homepage or Dashboard.
      3. Copy your API Key and Base URL (typically youruniqueid.api.infobip.com).

    Add these lines to .env, replacing placeholders with your credentials:

    dotenv
    # .env
    
    # Infobip Credentials
    INFOBIP_API_KEY=your_infobip_api_key_here
    INFOBIP_BASE_URL=youruniqueid.api.infobip.com
    
    # Server Configuration
    PORT=3000
    • INFOBIP_API_KEY: Your secret API key for Infobip authentication.
    • INFOBIP_BASE_URL: Your account-specific domain for API access.
    • PORT: Port number for your Express server.

    Why .env? Storing API keys in code is insecure and complicates deployment. Environment variables let you configure applications differently across environments (development, testing, production) without code changes. dotenv loads these into process.env.

Building the Infobip SMS Service Layer

Create the service that interacts with the Infobip API. This logic adapts the Infobip developer blog post.

  1. Create src/services/infobipService.js: This file builds requests and calls the Infobip API.

    javascript
    // src/services/infobipService.js
    
    const axios = require('axios');
    
    // Helper to build the full API URL
    const buildUrl = (domain) => {
      if (!domain) {
        throw new Error('Infobip domain (Base URL) is mandatory in config');
      }
      // Ensure domain doesn't have protocol prefix for URL construction
      const cleanDomain = domain.replace(/^https?:\/\//, '');
      return `https://${cleanDomain}/sms/2/text/advanced`;
    };
    
    // Helper to build the required HTTP headers for Infobip API
    const buildHeaders = (apiKey) => {
      if (!apiKey) {
        throw new Error('Infobip API Key is mandatory in config');
      }
      return {
        'Authorization': `App ${apiKey}`,
        'Content-Type': 'application/json',
        'Accept': 'application/json',
      };
    };
    
    // Helper to construct the request body according to Infobip specs
    const buildRequestBody = (destinationNumber, message) => {
      if (!destinationNumber || !message) {
        throw new Error('Destination number and message text are mandatory');
      }
    
      // Validate E.164 format: digits only, no '+' prefix
      // Production apps should use libphonenumber for robust validation
      if (!/^\d{7,15}$/.test(destinationNumber)) {
         console.warn(`Destination number ${destinationNumber} may not conform to E.164 international format (7-15 digits, no '+' prefix).`);
      }
    
      const destinationObject = {
        to: destinationNumber,
      };
    
      const messageObject = {
        destinations: [destinationObject],
        text: message,
        // Add 'from' if you have a registered sender ID
        // from: "YourSenderID"
      };
    
      return {
        messages: [messageObject],
      };
    };
    
    // Helper function for basic argument validation
    const validateNotEmpty = (value, fieldName) => {
      if (!value) {
        throw new Error(`${fieldName} parameter is mandatory`);
      }
    };
    
    /**
     * Sends an SMS message using the Infobip API.
     * @param {string} destinationNumber - Recipient phone number in E.164 format (digits only, no '+').
     * @param {string} message - SMS text content (160 chars for GSM-7, 70 chars for Unicode/UCS-2).
     * @returns {Promise<object>} - Resolves with success response or rejects with error info.
     */
    const sendSms = async (destinationNumber, message) => {
      const apiKey = process.env.INFOBIP_API_KEY;
      const domain = process.env.INFOBIP_BASE_URL;
    
      validateNotEmpty(domain, 'Infobip Base URL (INFOBIP_BASE_URL in .env)');
      validateNotEmpty(apiKey, 'Infobip API Key (INFOBIP_API_KEY in .env)');
      validateNotEmpty(destinationNumber, 'destinationNumber');
      validateNotEmpty(message, 'message');
    
      const url = buildUrl(domain);
      const headers = buildHeaders(apiKey);
      const requestBody = buildRequestBody(destinationNumber, message);
    
      console.log(`Attempting to send SMS to ${destinationNumber} via Infobip...`);
    
      try {
        const response = await axios.post(url, requestBody, { headers });
        console.log('Infobip API call successful.');
        return parseSuccessResponse(response);
      } catch (error) {
        console.error('Infobip API call failed:', error.message);
        throw parseFailedResponse(error);
      }
    };
    
    // Parses the successful response from Infobip
    const parseSuccessResponse = (axiosResponse) => {
      const responseBody = axiosResponse.data;
      const singleMessageResponse = responseBody.messages && responseBody.messages[0];
      if (!singleMessageResponse) {
         console.warn('Infobip success response structure differs from expected format.', responseBody);
         return { success: true, data: responseBody };
      }
      return {
        success: true,
        messageId: singleMessageResponse.messageId,
        status: singleMessageResponse.status.name,
        description: singleMessageResponse.status.description,
        category: singleMessageResponse.status.groupName,
        to: singleMessageResponse.to,
      };
    };
    
    // Parses the error response from Infobip or network errors
    const parseFailedResponse = (axiosError) => {
      let errorInfo = {
        success: false,
        errorMessage: 'An unknown error occurred.',
        details: null,
        statusCode: null,
      };
    
      if (axiosError.response) {
        // Error response from Infobip API (e.g., 4xx, 5xx)
        errorInfo.statusCode = axiosError.response.status;
        const responseBody = axiosError.response.data;
        if (responseBody && responseBody.requestError && responseBody.requestError.serviceException) {
          errorInfo.errorMessage = responseBody.requestError.serviceException.text || 'Infobip service exception';
          errorInfo.details = responseBody.requestError.serviceException;
        } else {
          errorInfo.errorMessage = `Infobip API Error: Status ${errorInfo.statusCode}`;
          errorInfo.details = responseBody;
        }
      } else if (axiosError.request) {
        errorInfo.errorMessage = 'Network Error: No response received from Infobip API.';
      } else {
        errorInfo.errorMessage = `Request Setup Error: ${axiosError.message}`;
      }
      errorInfo.rawError = axiosError.message;
      return errorInfo;
    };
    
    module.exports = {
      sendSms,
    };
    • async/await: Makes asynchronous operations cleaner than Promise chains.
    • Separate helpers: Breaking logic into buildUrl, buildHeaders, buildRequestBody, parseSuccessResponse, parseFailedResponse improves readability, maintainability, and testability.
    • E.164 Format Validation: Enhanced validation checks for 7-15 digit format per E.164 international standard.

Creating the Express API Routes and Controller

Define the Express route and controller that receives requests and uses infobipService.

  1. Create src/controllers/smsController.js: This controller handles request logic.

    javascript
    // src/controllers/smsController.js
    
    const infobipService = require('../services/infobipService');
    
    const handleSendSms = async (req, res) => {
      const { to, text } = req.body;
    
      if (!to) {
        return res.status(400).json({ success: false, message: 'Missing required field: "to" (destination phone number)' });
      }
      if (!text) {
        return res.status(400).json({ success: false, message: 'Missing required field: "text" (message content)' });
      }
    
      // Enhanced validation: Check E.164 format (7-15 digits)
      const cleanNumber = to.replace(/[\s+()-]/g, '');
      if (!/^\d{7,15}$/.test(cleanNumber)) {
         console.warn(`Received invalid phone number format: ${to}. Must be E.164 format (7-15 digits, e.g., 15551234567).`);
         return res.status(400).json({ 
           success: false, 
           message: 'Invalid "to" field format. Use E.164 international format: country code + number, 7-15 digits total (e.g., 15551234567).' 
         });
      }
    
      try {
        console.log(`Controller received request to send SMS to: ${to}`);
        const result = await infobipService.sendSms(cleanNumber, text);
    
        console.log('SMS processed successfully by Infobip service:', result);
        return res.status(200).json(result);
    
      } catch (error) {
        console.error('Error in handleSendSms controller:', error);
    
        const statusCode = error.statusCode || 500;
    
        return res.status(statusCode).json({
          success: false,
          message: error.errorMessage || 'Failed to send SMS due to an internal error.',
          details: error.details || error.rawError,
        });
      }
    };
    
    module.exports = {
      handleSendSms,
    };
    • Input Validation: Validates required fields and enforces E.164 format (7-15 digits).
    • Format Cleaning: Strips common phone number formatting characters before validation.
    • Error Responses: Returns appropriate HTTP status codes with detailed error messages.
  2. Create src/routes/smsRoutes.js: This file defines the API endpoint.

    javascript
    // src/routes/smsRoutes.js
    
    const express = require('express');
    const smsController = require('../controllers/smsController');
    
    const router = express.Router();
    
    // Define the route for sending SMS
    // POST /api/v1/sms/send
    router.post('/send', smsController.handleSendSms);
    
    module.exports = router;
  3. Set up the Main Application File (app.js): Initialize Express, load environment variables, configure middleware, and mount routes.

    javascript
    // app.js
    
    const express = require('express');
    const dotenv = require('dotenv');
    const smsRoutes = require('./src/routes/smsRoutes');
    
    // Load environment variables from .env file
    dotenv.config();
    
    const app = express();
    
    // Middleware to parse JSON request bodies
    app.use(express.json());
    
    // Middleware for basic logging
    app.use((req, res, next) => {
      console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
      next();
    });
    
    // Mount the SMS routes under the /api/v1/sms prefix
    app.use('/api/v1/sms', smsRoutes);
    
    // Health check endpoint
    app.get('/health', (req, res) => {
      res.status(200).json({ status: 'UP', timestamp: new Date().toISOString() });
    });
    
    // 404 handler for undefined routes
    app.use((req, res, next) => {
      res.status(404).json({ success: false, message: 'Resource not found' });
    });
    
    // Error handler middleware
    app.use((err, req, res, next) => {
      console.error('Unhandled Error:', err);
      res.status(500).json({ success: false, message: 'An unexpected internal server error occurred.' });
    });
    
    const PORT = process.env.PORT || 3000;
    
    // Start the server
    app.listen(PORT, () => {
      console.log(`Server is running on port ${PORT}`);
      console.log(`Infobip Base URL configured: ${process.env.INFOBIP_BASE_URL}`);
      if (process.env.INFOBIP_API_KEY) {
         console.log('Infobip API Key is configured.');
      } else {
         console.warn('WARNING: Infobip API Key (INFOBIP_API_KEY) is missing in .env file!');
      }
    });
    • dotenv.config(): Loads .env variables into process.env before accessing them.
    • express.json(): Parses incoming JSON payloads (available via req.body).
    • Route Mounting: Mounts smsRoutes under /api/v1/sms, creating final endpoint http://localhost:3000/api/v1/sms/send.
    • Health Check: Includes /health endpoint for monitoring.

Configuring Infobip API Credentials

Integration happens in src/services/infobipService.js using credentials from .env.

  • Configuration Files:
    • .env: Stores INFOBIP_API_KEY and INFOBIP_BASE_URL.
  • Secure Handling:
    • Read API key via process.env.INFOBIP_API_KEY.
    • Include .env in .gitignore to prevent commits.
  • Dashboard Steps:
    1. Log in to Infobip Portal.
    2. Locate API Key and Base URL on the dashboard.
    3. Copy these values into your .env file.
  • Environment Variables:
    • INFOBIP_API_KEY: (String, Required) Your unique secret key from Infobip. Used in Authorization: App <key> header.
    • INFOBIP_BASE_URL: (String, Required) Your account-specific domain (e.g., xyz123.api.infobip.com). Used to construct API endpoint URLs.
    • PORT: (Number, Optional, Default: 3000) Your local server port.

Error Handling and Logging Best Practices

Error handling is built into the service and controller:

  • Strategy:
    • infobipService uses try...catch around axios calls.
    • Calls parseFailedResponse to create standardized error objects for API errors (4xx/5xx) or network errors.
    • Service throws parsed error objects.
    • smsController catches errors and inspects statusCode and errorMessage to return appropriate HTTP responses.
    • Uses console.log and console.error for basic logging.
  • Logging:
    • Requests logged in app.js.
    • Service calls and outcomes logged in infobipService.js.
    • Errors logged in service and controller catch blocks.
    • Production Enhancement: Use Winston or Pino for structured logging with different levels and external service routing.
  • Retry Mechanisms:
    • Not implemented in this basic example.
    • Production Enhancement: For transient network errors or rate limit responses (429 Too Many Requests), implement retries with exponential backoff using axios-retry or custom logic.
  • Testing Errors:
    • Invalid API Key: Change INFOBIP_API_KEY in .env to incorrect value. Expect 401 Unauthorized.
    • Invalid Base URL: Change INFOBIP_BASE_URL to non-existent domain. Expect network error (ENOTFOUND or timeout).
    • Missing Fields: Send request without to or text. Expect 400 Bad Request.
    • Invalid Phone Number: Send clearly invalid to value (e.g., 'abcde'). Expect 400 Bad Request from controller validation.

Security Best Practices for SMS APIs

Basic security is included; production systems need more.

  • API Key Security: Handled via .env and .gitignore. Critical.
  • Input Validation: Enhanced E.164 format validation in smsController.js.
    • Production Enhancement: Use joi or express-validator for schema validation, type checking, and length limits.
  • Rate Limiting: Not implemented. Essential for public APIs to prevent abuse.
    • Production Enhancement: Use express-rate-limit middleware to limit requests per IP or user.
  • Common Vulnerabilities:
    • Injection: Always validate and sanitize input used in database queries or commands.
    • Authentication/Authorization: This endpoint is unauthenticated. For production, implement API key validation, JWT tokens, or other auth methods.
  • HTTPS: Deploy behind reverse proxy (Nginx, Caddy) configured for HTTPS, or use platforms (Heroku, Render) handling TLS termination.
  • Dependency Security: Regularly audit dependencies (npm audit).

Understanding SMS Format Requirements and Limitations

  • Phone Number Formatting: Infobip API expects E.164 international format (e.g., 15551234567 for US, 447911123456 for UK). Enhanced validation enforces 7-15 digit format. Production apps should use libphonenumber for robust validation and formatting.
  • Message Encoding & Length:
    • GSM-7 encoding: 160 characters per SMS segment
    • UCS-2/UTF-16 (Unicode): 70 characters per segment for non-Latin scripts
    • Infobip handles concatenation for longer messages; billing is per segment. This example doesn't handle encoding or splitting.
  • Sender ID: The from field in the Infobip payload specifies sender ID (alphanumeric or phone number). Requires pre-registration and approval with Infobip. The example code comments out from.
  • Free Trial Limitations: Infobip trial accounts only send SMS to the registered phone number. Sending to other numbers fails until account funding.
  • Delivery Status Webhooks: Infobip supports webhooks for delivery reports. Configure webhook URLs in the Infobip Portal to receive real-time status updates (DELIVERED, FAILED, etc.).

Performance Optimization for High-Volume SMS

For simple, single API calls per request, performance bottlenecks are unlikely. Main latency is network round-trip to Infobip.

  • Connection Pooling: axios and Node.js HTTP agent handle connection pooling/reuse automatically.
  • Caching: Not applicable for unique transactional SMS messages.
  • Asynchronous I/O: Node.js non-blocking I/O keeps server responsive during Infobip API waits.
  • Production Enhancement: For high volumes, monitor event loop lag, CPU, and memory. Consider horizontal scaling (multiple instances behind load balancer). Analyze Infobip API response times.

Monitoring Your Node.js SMS Application

Basic logging is included. Production systems need robust monitoring.

  • Health Checks: /health endpoint provides basic status.
  • Logging: console.log/console.error provide minimal visibility.
    • Production Enhancement: Integrate Winston/Pino for structured logging to Datadog, Logz.io, or ELK stack.
  • Metrics: Track request rates, error rates, and latency (especially Infobip API calls).
    • Production Enhancement: Use prom-client for Prometheus metrics or integrate APM tools (Datadog APM, New Relic, Dynatrace).
  • Error Tracking: Capture and aggregate unhandled exceptions.
    • Production Enhancement: Use Sentry or Bugsnag for real-time error capture with stack traces.
  • Dashboards: Visualize key metrics (requests/sec, error rate, Infobip latency, SMS success/failure rates). Use Grafana with Prometheus, Datadog, or New Relic.
  • Alerting: Configure alerts for thresholds (error rate > 5%, Infobip latency > 2s, health check failures).

Troubleshooting and Caveats

  • Common Errors:
    • 401 Unauthorized (from Infobip): Incorrect INFOBIP_API_KEY. Verify key in .env and Infobip dashboard.
    • Network Error/ENOTFOUND/ECONNREFUSED/Timeout: Incorrect INFOBIP_BASE_URL, DNS issues, firewall blocking outgoing connections, or temporary Infobip unavailability. Verify Base URL and network connectivity.
    • 400 Bad Request (from Infobip): Invalid input. Check:
      • to number format (must be E.164: 7-15 digits, no '+').
      • Missing required fields in JSON payload.
      • Invalid from sender ID (if used).
      • Message content issues (unsupported characters).
      • Review details field in error response for specific Infobip error codes (e.g., Invalid destination address).
    • TypeError: Cannot read property '...' of undefined: Missing environment variables (dotenv.config() not called early, variables missing in .env) or unexpected Infobip response structures. Add logging to trace variable values.

Frequently Asked Questions (FAQ)

Q: What Node.js versions are compatible with Infobip? A: Node.js v18.x or v20.x LTS versions are recommended. Earlier versions may work but lack current security patches and performance improvements.

Q: Do I need a paid Infobip account to send SMS? A: Free trial accounts can send SMS to verified phone numbers only. For production use or testing with multiple numbers, you'll need to fund your account.

Q: What phone number format does Infobip require? A: Infobip requires E.164 international format: country code + national number, 7-15 digits total, without the '+' prefix. Example: 15551234567 (US) or 447911123456 (UK).

Q: How many characters can I send in one SMS? A: Standard SMS supports 160 characters (GSM-7 encoding) or 70 characters (UCS-2/Unicode for non-Latin scripts). Longer messages are automatically split into multiple segments, with separate billing per segment.

Q: How do I track SMS delivery status? A: Configure webhooks in the Infobip Portal to receive real-time delivery reports (DELIVERED, FAILED, etc.). The messageId returned from the send request can be used to query delivery status via Infobip's API.

Q: Can I customize the sender ID for my SMS messages? A: Yes, use the from field in the message payload. Alphanumeric sender IDs require pre-registration and approval with Infobip. Some countries restrict sender ID customization.

Q: How do I handle rate limits with Infobip? A: Implement rate limiting in your application using express-rate-limit. For transient rate limit errors (429 responses), add retry logic with exponential backoff using libraries like axios-retry.

Q: Is this code production-ready? A: This tutorial provides a foundation. For production, add: robust input validation (use joi or express-validator), comprehensive error handling, retry mechanisms, structured logging (Winston/Pino), monitoring (Datadog/New Relic), rate limiting, and authentication/authorization.

Q: How do I test my integration without sending real SMS? A: Use your verified trial phone number for testing, or upgrade to a paid account and use test numbers. Infobip also offers simulation modes in some regions—check their documentation.

Q: What's the typical latency for sending SMS through Infobip? A: Network latency to Infobip's API typically ranges from 200ms to 2 seconds depending on your location and network conditions. Actual SMS delivery to the recipient's device depends on carrier networks (usually 1-10 seconds).

Q: Can I send SMS to international numbers? A: Yes, Infobip supports international SMS delivery to 190+ countries. Ensure phone numbers are in proper E.164 format with the correct country code. Pricing varies by destination country.

Q: How do I handle special characters in SMS messages? A: GSM-7 encoding supports basic Latin characters and common symbols. For special characters (emojis, non-Latin scripts), messages use UCS-2 encoding, reducing the character limit to 70 per segment. Infobip handles encoding automatically based on message content.

Frequently Asked Questions

How to send SMS with Node.js and Express?

This guide details setting up a Node.js application with Express to send SMS messages using the Infobip API. It covers project setup, API integration, error handling, and testing. You'll create an API endpoint that accepts a phone number and message, then dispatches the SMS via Infobip.

What is the Infobip API used for?

The Infobip API is a third-party service used in this tutorial to send SMS messages programmatically. It handles the actual delivery of the SMS to the recipient's phone number. This automation is useful for transactional messages, alerts, and user communication within applications.

Why use Express framework with Node.js?

Express.js simplifies the process of building a web server and API endpoints in Node.js. Its minimal structure and routing capabilities make it ideal for creating the SMS sending endpoint required in this tutorial.

When should I validate phone numbers with Infobip?

Phone number validation should occur before sending any SMS via the Infobip API. The controller in this example performs a basic check but stricter format validation is recommended. It's crucial for preventing errors and ensuring deliverability, especially when using international numbers.

Can I use a free Infobip account for testing?

Yes, you can use an Infobip free trial account, but it has limitations. Testing is typically restricted to sending SMS messages only to the phone number verified during signup. Other numbers will likely fail until you upgrade to a paid account.

How to set up environment variables for Infobip?

Create a `.env` file in your project's root directory. Add your `INFOBIP_API_KEY` and `INFOBIP_BASE_URL` obtained from your Infobip account dashboard. The `dotenv` package loads these variables into `process.env` for secure access within your Node.js application.

What is Axios used for in this project?

Axios is a promise-based HTTP client used to make requests to the Infobip API. It simplifies sending the POST request with the recipient's number and message text to trigger the SMS sending process. The example code demonstrates how to use axios and parse responses.

How to handle errors with the Infobip API?

Error handling involves using `try...catch` blocks around the API call with `axios` within the `infobipService` and controller. The `parseFailedResponse` function helps standardize error objects, and you can add logging and retry mechanisms. The example includes basic error parsing and response handling.

Why is a database not used in this tutorial?

This tutorial focuses on demonstrating a simple, stateless SMS sending function where incoming requests are handled directly via the Infobip API. A database isn't needed to store application state or message details, reducing complexity for the basic example.

How to structure a Node.js project for sending SMS?

The tutorial recommends a structure with `controllers`, `routes`, and `services` directories within a `src` folder. Controllers manage requests, routes define API endpoints, and services encapsulate the Infobip API interaction logic.

What are the prerequisites for this Node.js SMS project?

You need Node.js and npm (or yarn) installed, an active Infobip account, and basic understanding of JavaScript, Node.js, REST APIs, and command-line usage. Familiarity with environment variables and asynchronous operations is also beneficial.

How to test the Infobip SMS integration?

After setting up the project and configuring your `.env` file, you can test by sending a POST request to the `/api/v1/sms/send` endpoint with a valid phone number and message text in the request body. Tools like Postman or curl can be used to make these test requests.

What security considerations are important with Infobip?

Protecting your API key is critical. The `.env` file keeps it out of version control. Input validation is essential to prevent issues and robust phone number formatting is recommended. Additional security measures like rate limiting and HTTPS in production are important considerations.

How to get Infobip API key and base URL?

Log in to your Infobip account portal and navigate to the main dashboard or homepage. Your unique API Key and Base URL will be displayed there. Copy these values into the `.env` file in your project.