Frequently Asked Questions
Start by setting up a new Node.js project and installing Fastify, the MessageBird SDK, and necessary dependencies like dotenv, qs, async-retry, and @fastify/rate-limit. Create a project structure with directories for source code, routes, and environment variables. Finally, set up your .env file with your MessageBird API key, webhook signing key, and originator information from your MessageBird dashboard. Use npm run dev
to start the server in development mode with automatic restarts, or npm start
for production.
It's crucial for verifying the authenticity of incoming webhooks, ensuring they originate from MessageBird. It's used to generate a signature that your application compares against the signature received in the webhook request headers, preventing unauthorized access to your application from external sources and potential malicious actors.
Because MessageBird webhooks use the 'application/x-www-form-urlencoded' content type. It's necessary to handle webhook signature verification which requires the raw request body. The custom parser added in app.js
stores the raw body string and then parses the form data reliably using the qs
library. This raw body is needed in src/routes/webhook.js within the verifyMessageBirdSignature function.
Once your server is running, send a POST request to the /api/send-message endpoint with a JSON payload containing the recipient's phone number and message content. Use a tool like curl or Postman to send the request, ensuring a valid E.164 formatted number is used. You should receive a JSON response with the message ID and status. Make sure that validation is done at the API endpoint. Failure to comply with the format will result in error messages being returned.
In the MessageBird dashboard, go to Flow Builder, create a custom flow triggered by SMS, and choose your number. In the next step, select "Forward to URL" and paste your ngrok HTTPS URL with the secret path from your .env file. Use POST and no authentication, then save and publish. Ensure that ngrok is used to tunnel the SMS message between your Fastify app and MessageBird. Note that changes to the webhook path should also be reflected in the Flow Builder configuration.
ngrok creates a secure tunnel from a public URL to your localhost server, essential for development as it makes your local app accessible to MessageBird's webhooks. Run 'ngrok http 3000' to create the tunnel and use the HTTPS URL it provides when configuring the webhook in MessageBird's flow builder.
The provided code implements a pre-handler hook that verifies the signature using an HMAC-SHA256 algorithm with your webhook signing key. The hook extracts necessary data from the header and combines the raw body of the request with the message timestamp to recompute the signature. If verification fails, the hook returns a 401 error, thereby blocking all other handlers.
Use async-retry for outgoing API calls (like sending SMS replies) to gracefully handle temporary network issues or MessageBird API hiccups. The code example demonstrates its use with messagebird.messages.create, retrying up to 3 times with exponential backoff. The provided code demonstrates the use of async-retry and how to use the library.
It signals to MessageBird that you've received and processed the webhook successfully, preventing MessageBird from retrying the webhook. This should be done even if your app fails to send the reply. Reply failures should be handled asynchronously using techniques such as queues. This helps make the application robust against transient failures without being retried unnecessarily by MessageBird.
Use a long, random secret path for your webhook URL, stored in the WEBHOOK_SECRET_PATH environment variable. The code checks for this variable and prevents start-up if the path is too short or missing. This increases security making it more difficult to discover and trigger your endpoint from external sources.
The app.js file demonstrates a best practice for handling errors. The provided code includes a global error handler, which helps to consistently format all error responses from the application and enhances maintainability. The response formatting also distinguishes between client errors and server errors. This helps the user differentiate between errors which were caused by them and those where the server was responsible.
pino-pretty formats Fastify's log output for better readability during development. In production, Fastify uses JSON logging which can be processed by logging and monitoring systems. Log levels are set via the LOG_LEVEL environment variable. This helps enhance debugging locally during development while optimizing for log aggregators.
Create separate directories for routes (webhook.js, api.js), keep your main application logic in app.js, and manage environment variables with .env. The provided project structure uses /src/routes
which enhances maintainability and keeps the logic for separate concerns isolated.
Yes, Prisma can be integrated for database interactions (optional). You would install the necessary Prisma dependencies and configure the DATABASE_URL environment variable. The code provides comments and .gitignore entries related to Prisma. It is up to the user to further configure the application to use the database if desired.
Implementing Inbound Two-Way SMS Messaging with MessageBird, Node.js, and Fastify
Introduction
Building a two-way SMS system? This comprehensive guide walks you through implementing inbound SMS messaging using MessageBird (now Bird), Node.js, and the Fastify web framework. You'll learn how to receive SMS messages via webhooks, verify their authenticity, and send automated replies—all essential for building interactive SMS applications like customer support bots, survey systems, or appointment reminders.
What you'll build: A production-ready Fastify server that receives inbound SMS messages through MessageBird webhooks, validates message authenticity using JWT signature verification, and sends automated responses. By the end of this tutorial, you'll have a complete two-way SMS messaging system ready for real-world deployment.
Note: MessageBird rebranded to Bird in early 2024. The SMS API and Node.js SDK functionality remain unchanged, though you may see both names in documentation and interfaces.
Prerequisites
Before you begin this tutorial, ensure you have:
What Is Two-Way SMS Messaging and Why Use It?
Two-way SMS messaging enables bidirectional communication between your application and mobile users. Unlike one-way SMS broadcasts, two-way messaging allows customers to respond to your messages, creating interactive conversations that drive engagement and automate customer service workflows.
Common use cases for two-way SMS:
Why choose Fastify for SMS webhooks?
Fastify excels at webhook handling due to its high performance (up to 30,000 requests per second), low overhead, and built-in features like schema validation, logging, and plugin architecture. For production SMS systems handling thousands of inbound messages, Fastify's speed and developer experience make it an ideal choice.
Understanding Two-Way SMS Architecture
Two-way SMS messaging involves both sending and receiving messages. Here's how the system works:
This bidirectional flow enables interactive conversations, automated customer service, opt-in confirmations, and more.
How to Set Up Your MessageBird Fastify Project
Create a new directory for your project and initialize a Node.js application:
Install the required dependencies:
Package purposes:
fastify
— Fast and low-overhead web framework for Node.js (Note: This tutorial uses Fastify v5.x. If you're using an older version, some APIs may differ.)messagebird
— Official MessageBird Node.js SDK for sending SMS and accessing the APIdotenv
— Loads environment variables from.env
file for secure credential managementpino-pretty
— Pretty-prints Fastify's JSON logs for easier development debuggingqs
— Parses URL-encoded webhook payloads from MessageBirdasync-retry
— Implements retry logic for failed API calls@fastify/rate-limit
— Protects your webhook endpoint from abuseHow to Configure Environment Variables for MessageBird
Create a
.env
file in your project root to store sensitive credentials securely:Configuration details:
MESSAGEBIRD_API_KEY
— Your live API key from MessageBird dashboardMESSAGEBIRD_WEBHOOK_SIGNING_KEY
— Signing key for webhook signature verification (found in webhook settings)MESSAGEBIRD_ORIGINATOR
— Your MessageBird virtual number in E.164 format (e.g., +14155552671)PORT
— Port number for your Fastify server (default: 3000)NODE_ENV
— Environment indicator (development
orproduction
)Security note: Add
.env
to your.gitignore
file to prevent accidentally committing sensitive credentials to version control.How to Create a Fastify Server for SMS Webhooks
Create a file named
server.js
and set up your basic Fastify server:Code explanation:
messagebird.initClient()
with your API key0.0.0.0
) for webhook accessHow to Verify MessageBird Webhook Signatures with JWT
Verify incoming webhooks to ensure they originate from MessageBird. Add this verification function to your
server.js
:Note: As of October 2025, MessageBird uses the
MessageBird-Signature-JWT
header for webhook authentication. This replaces older HMAC-based verification methods. Always use the SDK's built-in verification for security.Security considerations:
How to Create a Webhook Endpoint for Inbound SMS
Add a custom content type parser for raw body access, then create your webhook endpoint:
Webhook handling flow:
How to Send Automated SMS Replies with MessageBird
Add a function to send automated SMS responses with retry logic:
Implementation highlights:
How to Add Rate Limiting to Your SMS Webhook
Protect your webhook endpoint from abuse by adding rate limiting:
Rate limiting configuration:
How to Configure MessageBird Webhook Settings
Connect your Fastify server to MessageBird:
https://your-domain.com/webhooks/inbound-sms
.env
file asMESSAGEBIRD_WEBHOOK_SIGNING_KEY
Local development with ngrok:
How to Test Your Two-Way SMS Implementation
Test your two-way SMS system:
Start your server:
Send a test SMS to your MessageBird virtual number from your mobile phone
Monitor server logs to verify:
Check your phone for the automated response
Expected log output:
Complete Code Example
Here's the full implementation with all components:
Production Deployment Best Practices for SMS Webhooks
Before deploying to production, implement these best practices:
Security Enhancements
MESSAGEBIRD_WEBHOOK_SIGNING_KEY
periodicallyScalability Improvements
Reliability Features
/health
endpointsError Handling
How to Scale Your SMS Webhook System
Troubleshooting Common MessageBird Webhook Issues
Why Is My Webhook Not Receiving Messages?
Why Is MessageBird Signature Verification Failing?
.env
file contains the correctMESSAGEBIRD_WEBHOOK_SIGNING_KEY
messagebird-signature-jwt
header (lowercase)Why Aren't My Auto-Replies Sending?
MESSAGEBIRD_API_KEY
has sending permissionsHow to Fix High Latency in SMS Processing
minTimeout
andmaxTimeout
in retry configurationAdvanced Features for Two-Way SMS Systems
Build upon this foundation with advanced features:
How to Store SMS Messages in a Database
Store inbound messages for analytics and compliance:
How to Implement AI-Powered SMS Responses
Implement AI-powered responses or integrate with customer support systems:
How to Track Multi-Step SMS Conversations
Track multi-step conversations using Redis:
How to Handle SMS Opt-Out Requests Automatically
Handle unsubscribe requests automatically:
How to MessageThroughput Limit
Fastify can handle thousands of requests per second. Your limiting factor will likely be MessageBird's API rate limits and your server's resources. Implement queuing for high-volume scenarios.
Optimize Message Processing
Frequently Asked Questions
How much does MessageBird SMS cost?
MessageBird pricing varies by destination country and message volume. Inbound SMS messages typically cost between $0.005-$0.01 per message, while outbound SMS pricing ranges from $0.01-$0.50+ depending on the destination country. Volume discounts are available for high-traffic applications. Check MessageBird's pricing page for current rates specific to your target countries.
Can I send MMS messages with this setup?
This tutorial focuses on SMS messaging. To add MMS support, you'll need to modify the
sendAutoReply
function to include media URLs using MessageBird's MMS API. Add amediaUrls
array parameter containing HTTPS URLs of images, videos, or audio files (up to 5MB per file). Note that MMS support and pricing vary by country—verify MMS availability for your target regions in the MessageBird dashboard.How do I handle multiple virtual numbers in one application?
Store a mapping of phone numbers to response logic in your database or configuration file. In your webhook handler, read the
recipient
field from the webhook payload to identify which MessageBird number received the message, then route to the appropriate response logic. This approach allows you to manage multiple SMS campaigns, departments, or brands from a single Fastify application.What's the maximum message throughput for this setup?
Fastify can handle 20,000-30,000 requests per second on modern hardware, far exceeding typical SMS webhook volumes. Your actual throughput will be limited by MessageBird's API rate limits (typically 1,000+ messages per second for enterprise accounts) and your server's resources. For high-volume scenarios exceeding 100 messages per second, implement message queuing with Redis or RabbitMQ to process webhooks asynchronously.
How do I test MessageBird webhooks locally?
Use ngrok to expose your local development server to the internet:
ngrok http 3000
. Copy the generated HTTPS URL (e.g.,https://abc123.ngrok.io
) and add your webhook path (/webhooks/inbound-sms
) to create the full webhook URL for MessageBird's dashboard. Ngrok provides request inspection, making it easy to debug webhook payloads during development.Can I use TypeScript with MessageBird and Fastify?
Yes! Both Fastify and MessageBird provide official TypeScript type definitions. Install
@types/node
and create atsconfig.json
file in your project root. The MessageBird SDK includes built-in TypeScript types, while Fastify offers comprehensive type support for routes, plugins, and request/reply objects. TypeScript enhances development experience with autocomplete, type checking, and better documentation.How do I implement GDPR compliance for SMS messaging?
Store explicit opt-in consent records with timestamps and IP addresses, honor opt-out requests immediately (within minutes, not hours), provide clear unsubscribe instructions in every marketing message (e.g., "Reply STOP to unsubscribe"), maintain audit logs of all message activity, and implement data retention policies to delete conversation data after your legally required retention period. Consider using a consent management platform for complex compliance requirements.
What's the difference between MessageBird and Bird?
MessageBird rebranded to Bird in early 2024 as part of a broader platform consolidation. The SMS API, Node.js SDK (npm package
messagebird
), and webhook functionality remain unchanged. Existing MessageBird accounts continue to work without migration. The Bird platform adds enhanced CRM and marketing automation features, but the core SMS infrastructure documented in this tutorial remains fully supported and operational.How do I monitor webhook health and uptime?
Implement a
/health
endpoint (as shown in the complete code example) for external monitoring services like UptimeRobot or Pingdom. Track key metrics including webhook response time (aim for <500ms), error rate (should be <1%), signature verification failures, and MessageBird API success rates. Use application performance monitoring (APM) tools like New Relic, Datadog, or Sentry for detailed insights into webhook processing performance.Can I rate limit specific phone numbers that spam my webhook?
Yes. Extend the rate limiting configuration to track both IP addresses and phone numbers. Add a custom
keyGenerator
function that extracts theoriginator
field from webhook payloads and implements per-number rate limits. Store rate limit violations in Redis to maintain state across server restarts and enable blocking of persistent spam numbers at the application level before processing messages.Conclusion
You've built a production-ready two-way SMS messaging system using MessageBird, Node.js, and Fastify. Your implementation includes webhook signature verification, automated reply logic, rate limiting, and error handling—all essential components for reliable SMS applications.
Key takeaways:
Next steps to enhance your SMS system:
For more advanced MessageBird features, explore their official documentation and SMS API reference. Check out related guides on bulk SMS campaigns, message scheduling, and WhatsApp Business API integration for multi-channel messaging strategies.