Frequently Asked Questions
Use the Infobip Node.js SDK and the /api/send-sms
endpoint. Send a POST request to this endpoint with a JSON body containing the recipient's number (to
) and the message text (text
). The server uses your configured Infobip credentials to send the SMS.
The @infobip-api/sdk is Infobip's official Node.js library, simplifying interaction with the Infobip API. It handles authentication and provides methods for sending SMS messages and other communication services.
Socket.IO enables real-time, bidirectional communication between the server and the frontend. It allows the server to push updates about sent and received messages instantly to the user interface, creating a dynamic chat-like experience without constant polling.
ngrok is recommended for local development to expose your local server to the internet, allowing Infobip to send webhooks to your development machine. In production, replace the ngrok URL with your application's public URL.
Yes, you can use yarn. The instructions use npm, but yarn is a compatible package manager. After creating the project, use yarn commands (like yarn add
, yarn dev
) instead of their npm equivalents.
Set up a webhook endpoint (/webhooks/infobip
in this project) and configure this URL in your Infobip number settings. When someone replies to your Infobip number, Infobip will send the message data as a POST request to your webhook, which then pushes the message to the frontend via Socket.IO.
The project uses a monorepo structure with backend
and frontend
directories at the root. The backend contains the Node.js/Express server code, while the frontend contains the Vite/React application.
Cross-Origin Resource Sharing (CORS) is essential for the frontend (running on a potentially different port) to communicate with the backend API. The cors
middleware enables this communication by specifying allowed origins.
Use ngrok to expose your local server, then paste the HTTPS ngrok forwarding URL followed by /webhooks/infobip
into the webhook settings in your Infobip number configuration.
The .env
file stores sensitive configuration data, like your Infobip API Key, Base URL, and sender number. This approach keeps secrets out of version control.
Basic security can be added with a shared secret header. For stronger security in production, use IP whitelisting and consider Infobip's signature verification methods if available. Do not rely solely on the obscurity of the webhook URL.
A messages
table could include columns for sender, recipient, message content, direction (inbound/outbound), Infobip status/DLR information, and timestamps. Indexing is crucial for efficient queries. Consider using a trigger to automatically update timestamps.
Error handling is essential for robustness. It includes validation of inputs, managing potential Infobip API errors, logging important events, and handling invalid or incomplete data. This enables appropriate responses and debugging.
Infobip's SDK handles long SMS messages by automatically splitting them into multiple parts. Be aware of the higher credit cost for these concatenated SMS, and ensure the UI provides visibility if needed.
Build Two-Way SMS Messaging with Node.js, React, and Infobip
This step-by-step guide shows you how to build a web application that sends SMS messages via Infobip and receives replies in real-time. You'll use Node.js with Express for the backend API and webhook handling, the official Infobip Node.js SDK for sending messages, Socket.IO for real-time communication, and Vite with React for the frontend interface.
What you'll build:
Technologies Used:
.env
file.System Architecture:
(Note: An image diagram (SVG/PNG) would be preferable here for better readability across platforms.)
Prerequisites:
What you'll have by the end:
By completing this guide, you'll have a functional web application consisting of:
GitHub Repository:
Find a complete working example of the code on GitHub: [repository link placeholder]
1. Set Up the Project
Create a monorepo structure with separate folders for the backend and frontend.
1.1. Create Project Directory
Open your terminal and create the main project folder:
1.2. Set Up the Backend (Node.js/Express)
Navigate into the main directory and create the backend folder, initialize npm, and install dependencies.
Dependencies explained:
express
: Web server frameworksocket.io
: Real-time communication library (server-side)@infobip-api/sdk
: Infobip's official Node.js SDKdotenv
: Loads environment variables from.env
filecors
: Enables Cross-Origin Resource Sharing (necessary for frontend communication)nodemon
: Monitors for changes and automatically restarts the server (useful during development)1.3. Create Backend Project Structure
Create the following basic structure within the
backend
folder:.env.example
: A template for required environment variables.gitignore
: Specifies files/folders git should ignore (likenode_modules
and.env
)package.json
: Project manifest that tracks dependencies and scriptsserver.js
: Main application file for the backend server1.4. Configure Backend Environment
Create a file named
.env
in thebackend
directory (copy.env.example
). You'll populate this later with your Infobip credentials..env.example
:Add
node_modules
and.env
to your.gitignore
file:.gitignore
:1.5. Set Up the Frontend (Vite/React)
Navigate back to the root project directory (
infobip-two-way-sms/
) and create the frontend project using Vite.socket.io-client
: Real-time communication library (client-side)Vite scaffolds a React project structure for you inside the
frontend
folder.1.6. Add Development Scripts (Recommended)
Modify the
scripts
section inbackend/package.json
to usenodemon
:backend/package.json
:Now run
npm run dev
in thebackend
directory for auto-reloading development.2. Implement Core Backend Functionality
Build the backend server logic in
backend/server.js
.backend/server.js
:How the code works:
@infobip-api/sdk
client with your Base URL and API Key/health
Endpoint: A simple endpoint to check if the server is running/api/send-sms
Endpoint (POST):to
(recipient number) andtext
(message content) from the frontend request bodyinfobip.channels.sms.send()
to send the message via the SDK. YourINFOBIP_NUMBER
is used as thefrom
addressreceiveMessage
event via Socket.IO to push the sent message back to all connected clients (including the sender) so the UI updates immediately. Mark it asdirection: 'outbound'
andsender: 'Me'
/webhooks/infobip
Endpoint (POST):results
array from the Infobip payloadresults
, it emits areceiveMessage
event via Socket.IO, pushing the inbound message details (id
,sender
,text
,timestamp
,direction: 'inbound'
) to all connected clients200 OK
status back to Infobip to acknowledge receipt – Infobip expects this acknowledgment3. Build the API Layer
The backend code in
server.js
already includes the necessary API endpoints:POST /api/send-sms
Purpose: Send an outgoing SMS message
Authentication: Implicitly authenticated via the Infobip API Key configured on the server. No user-level auth is implemented in this basic example.
Request Validation: Checks for the presence of
to
andtext
in the JSON bodyRequest Body (JSON):
Success Response (200 OK, JSON):
Error Response (400 Bad Request, JSON): Missing fields
Error Response (500 Internal Server Error, JSON): Infobip API error
Test with cURL:
Replace
+1555YOURNUMBER
with a valid test number, likely your own during free trial.POST /webhooks/infobip
Purpose: Receive inbound SMS messages from Infobip
Authentication: Relies on the obscurity of the URL and optionally a shared secret header (commented out). For production, verify the source IP or use stronger signature verification methods provided by Infobip.
Request Validation: Checks for the presence and format of the
results
array in the JSON bodyRequest Body (JSON – Example from Infobip):
Success Response: Empty body with status 200 acknowledges receipt
Error Responses:
Testing: Requires configuring the Infobip webhook and sending an SMS to your Infobip number.
4. Integrate with Infobip
4.1. Obtain Infobip Credentials
xxxxx.api.infobip.com
) and copy it+14155550100
)4.2. Update Your .env File
Open
backend/.env
and paste the values you copied:4.3. Configure Infobip Webhook for Inbound SMS
This step is crucial for receiving messages. Since your backend runs locally during development, use ngrok to expose it to Infobip.
Start your backend server:
Confirm it logs
Server listening on port 4000
Start ngrok: Open another terminal window and run:
ngrok displays forwarding URLs. Copy the
https
URL (e.g.,https://random-string.ngrok-free.app
).Configure Infobip Forwarding:
https://<your-ngrok-subdomain>.ngrok-free.app/webhooks/infobip
server.js
, add a custom HTTP header likeX-Webhook-Secret
with the value matching yourWEBHOOK_SECRET
in.env
When someone sends an SMS to your Infobip number, Infobip forwards it via POST request to your ngrok URL, which tunnels it to your local
http://localhost:4000/webhooks/infobip
endpoint.Important: ngrok URLs are temporary – you get a new one each time you restart ngrok. For production, use a permanent public URL hosted on your deployment platform.
5. Implementing Error Handling and Logging
Our
server.js
includes basic error handling and logging:400 Bad Request
for missing fields in/api/send-sms
.try...catch
block aroundinfobip.channels.sms.send
catches errors during the API call. It logs detailed error information (if available from the SDK's response) and returns a500 Internal Server Error
to the client.results
array and logs warnings for invalid formats. Returns400 Bad Request
or401 Unauthorized
(if secret check is enabled and fails).console.log
andconsole.error
to output information about server startup, connections, API calls, responses, webhook receipts, and errors.Improvements for Production:
Winston
orPino
for structured JSON logging, which is easier to parse and analyze with log management tools. Include request IDs for tracing.status.groupName
,status.name
, andstatus.description
fields in both the API response and webhook payloads for detailed insights into message delivery or failures. (Refer to Infobip documentation for code meanings).async-retry
. This is less critical for SMS compared to other API calls but can improve reliability.2xx
response. Ensure your webhook handler is idempotent (processing the same message multiple times doesn't cause issues) if possible, or implement logic to detect and ignore duplicate message IDs.6. Creating a Database Schema (Conceptual)
While this guide doesn't implement database persistence for brevity, a real-world application would need to store messages for history and status tracking.
Conceptual Schema (e.g., using PostgreSQL):
Implementation Notes:
db-migrate
) to manage schema changes./api/send-sms
, after a successful Infobip API call, insert a record withdirection: 'outbound'
,sender: INFOBIP_NUMBER
(or 'Me'),recipient: to
, and the initial status (e.g., 'PENDING'). Store themessageId
./webhooks/infobip
, when processing an inbound message, insert a record withdirection: 'inbound'
,sender: message.from
,recipient: message.to
, and the received text/timestamp. Store themessageId
./webhooks/infobip-dlr
) specifically for receiving DLRs from Infobip. This handler would update the status fields (status_group_name
,status_name
, etc.) of the corresponding outbound message in your database using themessageId
provided in the DLR payload. This is essential for knowing if a message was actually delivered.infobip_message_id
,sender_number
,recipient_number
, timestamps) for efficient querying. Use connection pooling.7. Adding Security Features
Security is paramount, especially when dealing with APIs and external webhooks.
.env
locally, secure configuration management in deployment)..env
file is listed in.gitignore
.X-Webhook-Secret
) for basic verification. Choose a strong, random secret./api/send-sms
) and webhook (/webhooks/infobip
) handlers. Check data types, lengths, and formats (e.g., ensureto
looks like a phone number). Libraries likeJoi
orexpress-validator
can help. Sanitize any data before storing it or potentially rendering it (though React helps prevent XSS)./api/send-sms
endpoint from abuse. Implement rate limiting using libraries likeexpress-rate-limit
to restrict the number of requests a single IP address can make within a specific time window.server.js
, thecors
middleware is currently configured to allow requests only fromFRONTEND_URL
. Keep this restricted to trusted origins in production.npm update
) and use tools likenpm audit
or Snyk to check for known vulnerabilities in your project's dependencies.8. Handling Special Cases
Real-world SMS messaging involves nuances:
+15551234567
), users might enter numbers differently. Consider adding frontend and/or backend logic to normalize inputs to E.164 before sending to the API. Libraries exist for phone number parsing and validation (e.g.,libphonenumber-js
).""STOP""
). Infobip often has features to manage opt-out lists automatically. Ensure you comply with local regulations. Your inbound webhook handler (/webhooks/infobip
) might need to check incoming messages for keywords like STOP, HELP, etc., and take appropriate action (e.g., marking the number as opted-out in your database or relying on Infobip's platform features).9. Implementing Performance Optimizations
For this simple application, performance isn't a major concern, but consider these for scaling:
React.memo
,useMemo
, anduseCallback
appropriately to prevent unnecessary re-renders in your React components, especially in the message list.react-window
orreact-virtualized
) to render only the visible items.Frequently Asked Questions
What is two-way SMS messaging?
Two-way SMS messaging enables bidirectional communication where users can both send SMS messages to recipients and receive replies back. This requires configuring webhooks to receive inbound messages from your SMS provider (like Infobip) and real-time communication (like Socket.IO) to update the user interface when replies arrive.
How do webhooks work with Infobip?
Webhooks are HTTP POST requests that Infobip sends to your server when an event occurs (like receiving an inbound SMS). You configure a webhook URL in your Infobip portal that points to your server endpoint (e.g.,
/webhooks/infobip
). When someone sends an SMS to your Infobip number, Infobip forwards the message data to your webhook endpoint.Why use Socket.IO for real-time updates?
Socket.IO provides real-time, bidirectional communication between the browser and server using WebSockets. This allows your application to instantly push received SMS messages to all connected clients without requiring them to poll the server repeatedly. It creates a chat-like experience where messages appear immediately.
Do I need ngrok for production deployment?
No. ngrok is only necessary for local development to expose your localhost server to the public internet for webhook testing. In production, deploy your application to a hosting platform with a permanent public URL (like AWS, Heroku, or DigitalOcean) and configure that URL as your Infobip webhook endpoint.
Which Node.js versions are compatible with this implementation?
This implementation works with Node.js LTS versions v18, v20, and v22. Node.js v14 reached end-of-life on April 30, 2023, and should not be used. Always use an actively maintained LTS version for production deployments.
How do I secure my webhook endpoint?
Implement multiple security layers: (1) Use a shared secret header that Infobip includes in webhook requests and verify it in your handler, (2) Whitelist Infobip's IP addresses in your firewall, (3) Use signature verification if Infobip provides it, and (4) Always use HTTPS for the webhook URL.
What's the difference between SMS sending and delivery reports?
Sending an SMS means the message was successfully submitted to Infobip's API. Delivery reports (DLRs) are separate webhook notifications that tell you the final status of the message (delivered, failed, rejected). You need a separate webhook endpoint to handle DLRs if you want to track delivery status.
Can I use Vue.js instead of React for the frontend?
Yes. The backend code remains the same. For the frontend, replace the React/Vite setup with Vue 3 and Vite (using
npm create vite@latest frontend -- --template vue
), then use the Socket.IO client in your Vue components with the Composition API or Options API to connect to the backend and handle real-time updates.How do I handle message history and persistence?
Implement a database (PostgreSQL, MongoDB, or MySQL) to store all sent and received messages with fields like message ID, direction (inbound/outbound), sender, recipient, text, timestamp, and status. Query this database to load message history when users open the application. Use the conceptual schema in Section 6 as a starting point.
What are the common rate limits for Infobip SMS?
Rate limits vary by account type and region. Free trial accounts typically have strict limits on message volume and destination numbers. Check your Infobip account dashboard or contact their support for your specific limits. Implement rate limiting on your API endpoints to prevent exceeding these limits.
Summary
You've now built a complete two-way SMS messaging application using Node.js, Express, Socket.IO, React, Vite, and the Infobip API. This implementation provides real-time bidirectional communication where users can send SMS messages through a web interface and receive replies instantly via webhooks and WebSocket connections.
The application architecture demonstrates key concepts including REST API design, webhook handling, real-time server-to-client communication, and third-party API integration. You've learned how to configure Infobip for inbound SMS forwarding, expose local development servers with ngrok, implement proper error handling and validation, and apply security best practices.
For production deployment, consider adding database persistence for message history, implementing delivery report webhooks for status tracking, adding user authentication, scaling with Redis-backed Socket.IO adapters for multiple server instances, and implementing comprehensive logging and monitoring. This foundation can be extended to support multiple users, conversation threads, media messaging (MMS), and integration with other communication channels.