code examples
code examples
How to Receive SMS with MessageBird Node.js Express: Inbound Webhook Tutorial 2025
Learn how to receive and send SMS messages with MessageBird, Node.js, and Express. Complete webhook tutorial covering two-way SMS, MessageBird SDK setup, Flow Builder configuration, and inbound message handling.
MessageBird Node.js Express Tutorial: Build Two-Way SMS with Webhooks (2024-2025)
Build a Node.js application using Express to send and receive SMS messages via the MessageBird API (now branded as Bird). This comprehensive tutorial covers implementing two-way SMS messaging with webhooks, including project setup, MessageBird SDK configuration, outbound SMS sending, inbound SMS webhook receivers, error handling, and testing.
Important Note (February 2024): MessageBird rebranded as "Bird" in February 2024 with significant price reductions. The legacy MessageBird API (used in this guide) continues to be supported but no longer accepts new customers. New integrations should use the Bird API (docs.bird.com), though the concepts and patterns for two-way SMS messaging remain similar.
By the end of this tutorial, you'll have a functional Express server with REST API endpoints for both sending SMS messages and receiving inbound SMS via webhooks – enabling true bidirectional communication for customer support, notifications, and interactive messaging.
What You'll Build: Two-Way SMS Application Overview
Goal: Create a backend service that programmatically sends and receives SMS messages for two-way communication using MessageBird's Node.js SDK.
Problem Solved: Integrate bidirectional SMS capabilities into larger applications for notifications, alerts, customer support, surveys, or interactive communication without complex infrastructure.
Technologies Used:
- Node.js: JavaScript runtime for server-side code. Widespread adoption, large npm ecosystem, asynchronous I/O operations. Recommended: Node.js v22 (Active LTS) or v20 (Maintenance LTS) as of 2024–2025.
- Express: Minimal, flexible Node.js web framework. Current version: Express 5.1.0 (requires Node.js 18+) as of 2025. Simplifies routes and HTTP request handling – ideal for API endpoints and webhook receivers.
- MessageBird Node.js SDK: Official library for the MessageBird SMS API. Simplifies API calls, authentication, and response handling.
- dotenv: Loads environment variables from
.envintoprocess.env. Securely manages sensitive information like API keys outside your codebase.
Prerequisites:
- Node.js (v18 or higher) and npm (or yarn) installed
- MessageBird account (or Bird account for new signups)
- Terminal or command prompt access
- Text editor or IDE (VS Code recommended)
- Tunneling service like ngrok for testing inbound webhooks locally
Final Outcome: A running Express server with:
POST /send-smsendpoint that sends SMS messages using MessageBird APIPOST /webhook/inbound-smsendpoint that receives and processes incoming SMS messages- Full two-way SMS communication capability for interactive messaging
1. Set Up the Node.js Project
Initialize your Node.js project and install dependencies.
-
Create Project Directory: Open your terminal and create a directory:
bashmkdir node-messagebird-sms cd node-messagebird-sms -
Initialize Node.js Project: Create
package.json:bashnpm init -yThe
-yflag accepts default settings. -
Install Dependencies: Install Express, MessageBird SDK, and dotenv:
bashnpm install express messagebird dotenvexpress– Web frameworkmessagebird– SDK for MessageBird APIdotenv– Loads environment variables from.env
-
Create Project Files:
bashtouch index.js .env .gitignoreindex.js– Express server and API logic.env– Sensitive credentials (MessageBird API key). Never commit to version control..gitignore– Specifies untracked files Git should ignore
-
Configure
.gitignore: Open.gitignoreand add:text# Environment variables .env # Node dependencies node_modules/ # Optional build/log folders dist/ logs/ *.log npm-debug.log* yarn-debug.log* yarn-error.log*Keeping
.envout of Git is crucial for security.node_modulescan be regenerated withnpm install. -
Project Structure: Your directory should look like this:
node-messagebird-sms/ ├── .env ├── .gitignore ├── index.js ├── node_modules/ ├── package-lock.json └── package.json
2. Configure MessageBird API Credentials
Configure your application to use MessageBird credentials securely.
-
Obtain MessageBird API Key:
- Log in to your MessageBird Dashboard
- Navigate to "Developers" in the left menu
- Click "API access" tab
- Create a live API key: Click "Add access key"
- Add a description (e.g., "Node SMS App Key") and select "Live key"
- Click "Add"
- Copy the API key immediately – you won't see it again after closing the modal
- (For testing without costs, use "Test key" but messages won't actually deliver)
-
Purchase a Virtual Number for Two-Way SMS:
SMS messages need a sender ("originator"). For two-way messaging:
- Purchased Number (Required for Inbound): Navigate to "Numbers" → "Buy a number" → Select your country → Check "SMS" capability → Purchase virtual mobile number. Required for receiving inbound SMS (two-way messaging).
- Alphanumeric Sender ID (Outbound Only): Custom name (up to 11 characters, e.g., "MyApp"). Configure in MessageBird dashboard under SMS → Sender IDs. Note: Not supported in all countries (e.g., US). Recipients cannot reply – one-way only. Check MessageBird's country restrictions.
Choose a purchased number for full two-way messaging capabilities.
-
Understanding MessageBird Rate Limits (US/Canada): American and Canadian numbers have:
- 500 SMS per day per number
- 1 SMS per second throughput
- Purchase additional numbers for higher capacity (e.g., 3 numbers = 3 SMS/second, 1,500 SMS/day)
-
Configure Environment Variables: Open
.envand add your credentials:dotenv# .env MESSAGEBIRD_API_KEY=YOUR_LIVE_API_KEY_HERE MESSAGEBIRD_ORIGINATOR=YOUR_PURCHASED_NUMBER_OR_SENDER_ID- Replace
YOUR_LIVE_API_KEY_HEREwith your copied key - Replace
YOUR_PURCHASED_NUMBER_OR_SENDER_IDwith your virtual number (international format:+12005550100) or alphanumeric sender ID - Keeping credentials in
.envseparates them from code – more secure and easier to manage across environments
- Replace
3. How to Send SMS Messages: Build the Outbound API Endpoint
Build the Express server and API endpoint for sending SMS messages with MessageBird.
-
Set Up Express Server: Open
index.jsand add:javascript// index.js require('dotenv').config(); // Load environment variables const express = require('express'); const { initClient } = require('messagebird'); // Validate essential environment variables if (!process.env.MESSAGEBIRD_API_KEY) { console.error('FATAL ERROR: MESSAGEBIRD_API_KEY not set.'); process.exit(1); } if (!process.env.MESSAGEBIRD_ORIGINATOR) { console.error('FATAL ERROR: MESSAGEBIRD_ORIGINATOR not set.'); process.exit(1); } // Initialize MessageBird client const messagebird = initClient(process.env.MESSAGEBIRD_API_KEY); const app = express(); const port = process.env.PORT || 3000; // Middleware to parse JSON request bodies app.use(express.json()); // Root route app.get('/', (req, res) => { res.send('SMS Sending Service is running!'); }); // --- SMS Sending Endpoint goes here --- // Start server app.listen(port, () => { console.log(`Server listening on port ${port}`); });Key Points:
require('dotenv').config()– Loads.envvariables. Must be called early.initClient(...)– Initializes MessageBird SDK with your API keyexpress()– Creates Express applicationapp.use(express.json())– Parses incoming JSON payloads. Crucial for API endpoint.- Validation checks ensure required environment variables exist before starting
-
Create SMS Sending Endpoint: Add the
POST /send-smsroute inindex.jsbelowapp.use(express.json())and beforeapp.listen():javascript// index.js (continued) // --- SMS Sending Endpoint --- app.post('/send-sms', (req, res) => { const { recipient, message } = req.body; // Validate input if (!recipient || !message) { return res.status(400).json({ error: 'Missing required fields: recipient and message', }); } // Construct message parameters const params = { originator: process.env.MESSAGEBIRD_ORIGINATOR, recipients: [recipient], // Must be array body: message, }; console.log(`Attempting to send SMS to ${recipient}…`); // Send message using MessageBird SDK messagebird.messages.create(params, (err, response) => { if (err) { console.error('MessageBird API Error:', err); const errorMessage = err.errors && Array.isArray(err.errors) && err.errors.length > 0 ? err.errors[0].description : 'Failed to send SMS due to API error.'; return res.status(500).json({ error: 'MessageBird API error', details: errorMessage, }); } console.log('MessageBird API Success:', response); res.status(200).json({ message: 'SMS sent successfully!', details: { id: response.id, recipients: response.recipients.totalSentCount, }, }); }); }); // --- End SMS Sending Endpoint ---Key Points:
app.post('/send-sms', ...)– Listens for POST requests at/send-smsreq.body– Parsed JSON payload (viaexpress.json()middleware)- Validation ensures both required fields exist. Returns 400 Bad Request if missing.
params– Data for MessageBird API call.recipientsmust be array.messagebird.messages.create(params, callback)– Asynchronous SDK callcallback(err, response)– Executes when MessageBird respondsif (err)– API call failed. Log error, return 500 Internal Server Error with description.else– Success. Log response, return 200 OK with message ID and recipient count.
- Alternative: SDK also supports Promises (
.then().catch()) andasync/await
4. Add Error Handling and Logging
Basic error handling is already in the /send-sms route:
- Input Validation: Checks for missing
recipientormessage. Returns 400 Bad Request. - API Error Handling: Uses
errobject from MessageBird callback. Logs withconsole.error, returns 500 with details. - Logging:
console.logfor informational messages,console.errorfor errors.
Production Enhancements:
- Robust Validation: Use
joiorexpress-validatorfor complex validation (e.g., E.164 phone number format) - Structured Logging: Implement
winstonorpinofor structured JSON logs, log levels, and external logging services (Datadog, Loggly) - Centralized Error Handler: Use Express error-handling middleware for consistent error formatting across routes
- Retry Mechanisms: For transient network errors, implement retry strategy (e.g.,
async-retrywith exponential backoff) – critical for important notifications
5. Implement Security Best Practices
Basic security is in place, but consider:
- API Key Security: Using environment variables (
dotenv) and.gitignorekeeps keys out of version control. Set restricted permissions on server (e.g.,chmod 600 .env). - Input Validation: Prevents basic errors with
recipientandmessagechecks.- Sanitization (Recommended): If storing or displaying user-provided
messagecontent elsewhere, sanitize to prevent Cross-Site Scripting (XSS) – usedompurifyfor HTML rendering or ensure proper database escaping.
- Sanitization (Recommended): If storing or displaying user-provided
- Rate Limiting (Production): Prevent abuse with
express-rate-limitmiddleware. Restrict requests per IP/user within time windows (e.g., 10 requests/minute). Controls costs and prevents spamming.
6. Understanding SMS Character Limits and Encoding
- Originator Restrictions: Alphanumeric sender IDs aren't supported everywhere and don't support inbound messages. Test delivery across countries/carriers. Purchased virtual numbers are more reliable and required for two-way messaging. Use international format (e.g.,
+14155552671). - Character Limits & Concatenation:
- GSM-7 encoding: 160 characters single message, 153 characters per segment for concatenated messages
- UCS-2 encoding (emojis, non-Latin): 70 characters single message, 67 characters per segment for concatenated
- Reduction due to 6-byte User Data Header (UDH) for concatenation instructions
- MessageBird bills per segment. Check message length to manage costs.
- Invalid Recipient Numbers: MessageBird returns errors for invalid format or non-existent numbers. Error handling extracts and returns MessageBird's description.
7. How to Receive SMS Messages: Implement Inbound Webhooks
Enable two-way messaging by configuring MessageBird to forward incoming SMS to your application via webhooks.
Set Up Webhook Endpoint for Inbound SMS
-
Create Inbound SMS Handler: Add this route in
index.jsbeforeapp.listen():javascript// index.js (add this section) // --- Inbound SMS Webhook Handler --- app.post('/webhook/inbound-sms', express.urlencoded({ extended: true }), (req, res) => { console.log('Received inbound SMS webhook:', req.body); // Extract message details const { originator, // Sender's phone number recipient, // Your MessageBird number body, // Message content id, // Message ID createdDatetime // Timestamp } = req.body; // Validate required fields if (!originator || !body) { console.error('Invalid webhook payload: missing originator or body'); return res.status(400).send('Invalid payload'); } console.log(`SMS from ${originator}: ${body}`); // Process inbound message: // - Store in database // - Trigger business logic // - Send auto-reply // - Forward to customer service // Example: Echo auto-reply const replyMessage = `You said: "${body}"`; const replyParams = { originator: recipient, // Use number that received message recipients: [originator], // Reply to sender body: replyMessage, }; // Send auto-reply (optional) messagebird.messages.create(replyParams, (err, response) => { if (err) { console.error('Failed to send auto-reply:', err); } else { console.log('Auto-reply sent successfully:', response.id); } }); // MessageBird expects 200 OK res.status(200).send('OK'); }); // --- End Inbound SMS Webhook Handler ---Key Points:
- MessageBird sends form-encoded requests – use
express.urlencoded()middleware - Always respond with 200 OK to acknowledge receipt
originator= sender's number,recipient= your MessageBird number- Process messages asynchronously (don't block webhook response)
- MessageBird sends form-encoded requests – use
Configure MessageBird Flow Builder for Webhooks
-
Configure Webhook in MessageBird Dashboard:
Important: Webhook URLs cannot be set via API – you must use Flow Builder in the MessageBird dashboard.
a. Expose Local Server for Testing:
bashngrok http 3000Copy the HTTPS forwarding URL (e.g.,
https://abc123.ngrok.io)b. Set Up Flow Builder for Webhook Routing:
- Log into MessageBird Dashboard
- Navigate to Flow Builder
- Select template "Call HTTP endpoint with SMS" → Click "Try this flow"
- Step 1 (SMS): Select virtual number(s) to receive messages
- Step 2 (Forward to URL):
- Method: POST
- URL: Your webhook URL (e.g.,
https://abc123.ngrok.io/webhook/inbound-sms)
- Save and Publish the flow
Webhook Payload Structure
MessageBird sends form-encoded fields:
{
id: 'message-id',
originator: '+1234567890', // Sender
recipient: '+14155552671', // Your MessageBird number
body: 'Hello!', // Message content
createdDatetime: '2025-01-05T12:00:00+00:00',
type: 'sms',
datacoding: 'plain',
mccmnc: '310260', // Mobile Country/Network Code
reference: null
}Production Webhook Security
Implement signature verification for production:
// Verify MessageBird signatures
function verifyMessageBirdSignature(req, res, next) {
// MessageBird signs webhooks with your signing key
// Implement signature verification
// See: developers.messagebird.com/docs/verify-http-requests
next();
}
app.post('/webhook/inbound-sms',
verifyMessageBirdSignature,
express.urlencoded({ extended: true }),
(req, res) => {
// Handler code…
}
);8. Testing Your Two-Way SMS Application
-
Start the Server: Open your terminal in the project directory and run:
bashnode index.jsYou should see
Server listening on port 3000. -
Test Outbound SMS with
curl: Open another terminal window and usecurl(or a tool like Postman/Insomnia) to send a POST request to your endpoint. ReplaceYOUR_RECIPIENT_PHONE_NUMBERwith a real phone number (in international format, e.g.,+14155552671) you can check.bashcurl -X POST http://localhost:3000/send-sms \ -H "Content-Type: application/json" \ -d '{ "recipient": "YOUR_RECIPIENT_PHONE_NUMBER", "message": "Hello from my Node.js app! Testing MessageBird." }' -
Test Inbound SMS (Two-Way Messaging):
a. Ensure your server is running and ngrok is active (if testing locally) b. Ensure Flow Builder is configured with your webhook URL c. Send an SMS from your phone to your MessageBird virtual number d. Check your server logs – you should see the webhook payload e. If auto-reply is enabled, check your phone for the response
9. Common Issues and Troubleshooting
- Error:
FATAL ERROR: MESSAGEBIRD_API_KEY environment variable is not set.- Cause: The
.envfile is missing, not named correctly (.env), not located in the root directory wherenode index.jsis executed, or theMESSAGEBIRD_API_KEYline is missing/commented out. Therequire('dotenv').config();call might be missing or placed after the variable is accessed. - Solution: Verify the
.envfile's presence, name, location, and content. Ensurerequire('dotenv').config();is at the very top ofindex.js.
- Cause: The
- Error:
Authentication failed(from MessageBird API Response)- Cause: The
MESSAGEBIRD_API_KEYin your.envfile is incorrect, has been revoked, or is a test key being used when a live key is required (or vice-versa). - Solution: Double-check the API key in your
.envfile against the active key in your MessageBird Dashboard (Developers -> API access). Ensure you are using the correct type of key (live vs. test).
- Cause: The
- Error:
message submission failed, invalid originator/Originator not allowed- Cause: The
MESSAGEBIRD_ORIGINATORspecified in.envis not a valid purchased number associated with your MessageBird account, or it's an alphanumeric sender ID that is not permitted for the recipient's country or mobile carrier. Alphanumeric IDs also cannot be used in some countries (like the US). - Solution: Verify the originator value in
.env. Ensure purchased numbers are entered in the correct international E.164 format (+followed by country code and number, e.g.,+447123456789). Check MessageBird's documentation on country restrictions for alphanumeric sender IDs or switch to using a purchased virtual number.
- Cause: The
- Error:
invalid recipient/recipient not found- Cause: The
recipientphone number provided in the API request body is not in a valid international format (e.g., missing the+prefix or country code), contains invalid characters, or represents a number that does not exist or is unreachable. - Solution: Ensure the client application sending the request provides the phone number in the correct E.164 international format (e.g.,
+14155552671). Verify the number itself is correct.
- Cause: The
- SMS Not Received:
- Cause: Using a test API key (messages are simulated but not delivered); recipient number is incorrect or cannot receive SMS; insufficient funds in your MessageBird account; country/carrier restrictions blocking the message (especially with alphanumeric senders or to certain networks); the originator number is blocked by the recipient; potential temporary MessageBird platform issues (check their official status page).
- Solution: Confirm you're using a live API key. Double-check the recipient number's format and validity. Check your MessageBird account balance. Try using a purchased number as the originator if using an alphanumeric ID. Consult MessageBird support if issues persist after checking common causes.
- Request Timeout/Network Error:
- Cause: Local machine network connectivity issues; firewall blocking outbound connections; temporary MessageBird API service disruption or latency.
- Solution: Check your server's internet connection. Ensure firewalls allow outbound HTTPS traffic (typically port 443). Consider adding retry logic (as mentioned in Section 4) for production applications to handle transient network glitches.
- Webhook Not Receiving Inbound Messages:
- Cause: Flow Builder not configured correctly; webhook URL incorrect or unreachable; ngrok tunnel expired; firewall blocking inbound requests; wrong HTTP method configured.
- Solution: Verify Flow Builder configuration in MessageBird Dashboard. Ensure webhook URL is publicly accessible (check ngrok status). Confirm POST method is selected. Check server logs for any incoming requests. Test webhook URL directly with curl to ensure it's reachable.
- Error:
Cannot POST /webhook/inbound-sms(404):- Cause: The route is not defined in your Express app or URL path doesn't match.
- Solution: Verify the route is defined in
index.jsbeforeapp.listen(). Ensure the URL in Flow Builder exactly matches your route path.
- Inbound Messages Show But Auto-Reply Fails:
- Cause: The
recipientfield (your MessageBird number) cannot be used as originator for replies; insufficient account balance; API key issues. - Solution: Ensure you're using the correct MessageBird number as the originator in replies. Check account balance. Verify API key permissions.
- Cause: The
Frequently Asked Questions About MessageBird Two-Way SMS
How do I receive SMS messages with MessageBird Node.js SDK?
To receive SMS with MessageBird, purchase a virtual number with SMS capability, create a webhook endpoint in your Express app (POST /webhook/inbound-sms), configure Flow Builder in the MessageBird dashboard to forward incoming SMS to your webhook URL, and process the form-encoded payload containing the sender's number and message content. Learn more about webhook configuration and implementing inbound SMS handlers.
Can I use MessageBird for two-way SMS conversations?
Yes, MessageBird supports two-way SMS messaging. Purchase a virtual phone number (not an alphanumeric sender ID), set up webhook endpoints to receive inbound SMS, and use the MessageBird API to send replies. Alphanumeric sender IDs only support one-way outbound messaging. See the complete two-way SMS implementation guide.
What's the difference between MessageBird and Bird API?
MessageBird rebranded as "Bird" in February 2024 with 90% price reductions. The legacy MessageBird API (developers.messagebird.com) continues to be supported but no longer accepts new customers. New integrations should use the Bird API (docs.bird.com). Both support two-way SMS messaging with similar SDK patterns.
How do I test MessageBird webhooks locally?
Use a tunneling service like ngrok to expose your local Express server to the internet. Run ngrok http 3000 to get a public HTTPS URL, then configure that URL in MessageBird Flow Builder. Send SMS to your MessageBird number to test the webhook locally. For detailed setup instructions, see the webhook testing section.
What are the SMS rate limits for MessageBird in the US?
US and Canadian MessageBird numbers have rate limits of 500 SMS per day per number and 1 SMS per second throughput. To send more messages, purchase additional virtual numbers (e.g., 3 numbers = 3 SMS/second and 1,500 SMS/day). Learn more about MessageBird rate limits.
How much does a MessageBird SMS cost?
MessageBird SMS pricing varies by destination country. After the February 2024 rebrand to "Bird," prices were reduced by 40-90%. Check the MessageBird Pricing API or dashboard for specific rates. Messages are billed per segment: 160 characters (GSM-7) or 70 characters (UCS-2 with emojis). Understand SMS character limits and pricing.
10. Deploy Your SMS Application to Production
Deploying this application involves running the Node.js server in a production environment (like a cloud virtual machine or a Platform-as-a-Service) and ensuring the environment variables are configured securely.
- Platforms: Common choices include Heroku, Vercel (especially for serverless functions), Render, AWS (EC2, Elastic Beanstalk, Lambda), Google Cloud (App Engine, Cloud Run, Compute Engine), Azure (App Service, Functions).
- Environment Variables: Crucially, do not commit your
.envfile to Git or upload it directly. Use the deployment platform's specific mechanism for setting environment variables (e.g., Heroku config vars, AWS Parameter Store/Secrets Manager, Vercel Environment Variables). SetMESSAGEBIRD_API_KEYandMESSAGEBIRD_ORIGINATORin the production environment. You might also want to setNODE_ENV=production. - Build Step: For this simple application, no explicit build step is required unless you introduce TypeScript or other transpilation.
- Start Command: Ensure the platform is configured to start your application using
node index.js. Alternatively, define astartscript in yourpackage.json("start": "node index.js") and configure the platform to runnpm start. - Port: The code uses
process.env.PORT || 3000. Most PaaS platforms automatically set thePORTenvironment variable, which your application will correctly bind to.
Example (Conceptual Heroku Deployment):
- Ensure you have the Heroku CLI installed and logged in (
heroku login). - Initialize a Git repository if you haven't already (
git init,git add .,git commit -m "Initial commit"). - Create a Heroku app:
heroku create your-unique-sms-app-name - Set the required environment variables on Heroku:
bash
heroku config:set MESSAGEBIRD_API_KEY=YOUR_ACTUAL_LIVE_KEY heroku config:set MESSAGEBIRD_ORIGINATOR=YOUR_ACTUAL_SENDER_ID_OR_NUMBER # Optional: Set Node environment heroku config:set NODE_ENV=production - Deploy your code:
git push heroku main(ormaster, depending on your branch name). - Heroku will build and deploy your app. You can check logs with
heroku logs --tail.
11. Enhance Your Two-Way SMS Application
You have successfully built a service with bidirectional SMS capabilities using Node.js, Express, and MessageBird. From here, you can expand its capabilities:
Enhance Two-Way Messaging:
- Implement conversational logic with state management (e.g., using Redis or in-memory storage) to track multi-step conversations
- Build keyword-based auto-responders (e.g., "HELP", "STOP", "INFO") for customer service automation
- Integrate with AI/NLP services for intelligent responses
- Store message history in a database for analytics and customer support
- Add delivery receipt tracking via MessageBird webhooks
Explore More MessageBird/Bird Features:
- Delivery Reports: Implement webhooks to receive real-time delivery reports (DLRs) for sent messages
- Send MMS: Adapt the code to send Multimedia Messages (requires different API parameters and MMS-enabled numbers)
- Verify API: Use MessageBird's Verify API for sending One-Time Passwords (OTP) for user authentication
- Voice & WhatsApp: Explore MessageBird's APIs for making automated voice calls or sending WhatsApp Business messages
- Migrate to Bird API: For new projects, consider using the new Bird API platform (docs.bird.com) with updated pricing and features
Remember to replace placeholders like YOUR_LIVE_API_KEY_HERE, YOUR_PURCHASED_NUMBER_OR_SENDER_ID, and YOUR_RECIPIENT_PHONE_NUMBER with your actual values during setup and testing.