Frequently Asked Questions
You can send WhatsApp messages programmatically using Node.js, Express.js, and the MessageBird Conversations API. The provided Node.js code demonstrates how to create an API endpoint that sends WhatsApp messages via the MessageBird SDK. This enables automated notifications, customer support, and conversational commerce directly within your app.
The MessageBird Conversations API allows developers to integrate WhatsApp messaging into their applications. It provides a way to send and receive WhatsApp messages, manage conversations, and track message status. This API is used with the MessageBird Node.js SDK for seamless integration with a Node.js backend.
Ngrok creates a public tunnel to your local server, making it accessible from the internet. This is crucial for local development as it allows MessageBird to send webhooks to your application while testing. For production deployments, you'll need a stable, public HTTPS URL.
WhatsApp Message Templates (HSMs) are required to initiate conversations with users outside the 24-hour customer service window. You must submit and have these templates pre-approved by MessageBird through their dashboard before using them in your integration.
Configure your webhook URL (ngrok for development, public HTTPS for production) in your MessageBird Dashboard, under Channels > WhatsApp > Your Channel. Set the event triggers to "message.created" and "message.updated" and provide a strong signing key that is the same value as your MESSAGEBIRD_WEBHOOK_SIGNING_SECRET variable.
The MessageBird Channel ID is a unique identifier for your WhatsApp Business channel. This ID is essential for sending WhatsApp messages and is used within the API requests and should be stored as the MESSAGEBIRD_WHATSAPP_CHANNEL_ID variable.
Yes, you can receive WhatsApp messages by setting up a webhook endpoint in your Node.js application. The MessageBird Conversations API will send an HTTP POST request to your specified URL every time a new message is received on your WhatsApp Business number.
Implement webhook signature verification using the messagebird-signature header to ensure the request originates from MessageBird and is not a fraudulent request. The provided Node.js example demonstrates this crucial security practice.
The article utilizes Express.js to create the web server and API endpoints, the MessageBird Node.js SDK for interactions with the MessageBird API, dotenv to load environment variables from a .env file, and ngrok for webhook testing during local development.
Verify the signature by calculating a HMAC-SHA256 hash of the combined timestamp, your signing secret, and the raw request body, then compare this hash with the signature provided in the request header. The webhook handling logic shown in the Node.js example provides a detailed implementation of this verification process.
Integrate WhatsApp messaging by installing the necessary libraries (Express, MessageBird SDK, dotenv) and implementing the API endpoint and webhook handler logic as described in the article. You will need to configure your MessageBird account, obtain your API key and Channel ID, and set up a public URL for the webhook.
Set MESSAGEBIRD_API_KEY, MESSAGEBIRD_WHATSAPP_CHANNEL_ID, MESSAGEBIRD_WEBHOOK_SIGNING_SECRET, and PORT as environment variables. Store these in a .env file and load them with dotenv.
Use the "message.updated" webhook event, which MessageBird sends when a message status changes (e.g., delivered, read). Update your database with the new status by matching it to the unique message identifier.
The E.164 format (+[country code][number]) ensures consistent and internationally recognized phone number representation for WhatsApp. This is crucial to deliver messages correctly.
MessageBird WhatsApp Integration with Node.js Express: Complete Implementation Guide
> Important Branding Update: MessageBird rebranded to "Bird" in February 2024 (source). The company maintains legacy developer documentation at
developers.messagebird.comwhile new API documentation is atdocs.bird.com. The Node.js SDK package name remainsmessagebirdon npm. This guide uses the establishedmessagebirdpackage and references, but be aware that official support and new features are now under the Bird brand.> Note: While this guide's filename references Next.js and NextAuth, the implementation uses Express.js. If you need Next.js App Router (v14/15) or NextAuth.js v5 integration, you'll need to adapt this Express.js foundation to Next.js Route Handlers (app/api/*/route.ts). The core MessageBird integration patterns remain the same.
Learn how to send WhatsApp messages programmatically from your Node.js application using the MessageBird WhatsApp Business API. This comprehensive tutorial walks you through building a production-ready Express server that handles both outbound and inbound WhatsApp messaging.
By the end of this guide, you will have a working Node.js application that can:
This integration enables you to automate WhatsApp business messaging for use cases like customer notifications, two-factor authentication, support automation, and conversational commerce—all from your Node.js backend.
What You'll Build
Goal: Create a Node.js/Express server that sends and receives WhatsApp messages programmatically through the MessageBird Conversations API.
Technologies:
messagebirdNode.js SDK: Official SDK version 4.0.1 (released January 25, 2023) (GitHub). Note: This SDK hasn't been updated since January 2023. For production applications, monitor the repository for updates or consider direct REST API callsdotenv: Environment variable management for secure credential storagengrok: Development tool to expose localhost to the internet for webhook testingSystem Architecture:
The typical message flow works as follows:
/send-whatsapp)/webhook)Prerequisites:
ngrokor similar for local development, HTTPS URL for productionFinal Outcome: A production-ready Node.js server with endpoints to send outgoing WhatsApp messages and receive incoming messages via webhooks.
1. Setting Up Your Node.js WhatsApp Project
Initialize the Node.js project and install the necessary dependencies.
Step 1: Create Project Directory and Initialize
Open your terminal and run the following commands:
This creates a new directory, navigates into it, and initializes a
package.jsonfile with default settings.Step 2: Install Dependencies
Install Express, the MessageBird SDK, and
dotenv:express: The web framework.messagebird: The official Node.js SDK for interacting with the MessageBird API.dotenv: To manage environment variables securely.Step 3: Create Project Structure
Create the basic files and directories:
Your initial structure should look like this:
Step 4: Configure
.gitignoreAdd
node_modulesand.envto your.gitignorefile to prevent committing them to version control:Step 5: Set Up Environment Variables
Open the
.envfile and add the following variables. Retrieve these values from your MessageBird Dashboard.MESSAGEBIRD_API_KEY: Go to your MessageBird Dashboard → Developers → API access. Use your Live API key.MESSAGEBIRD_WHATSAPP_CHANNEL_ID: Go to Channels → WhatsApp → Click on your configured channel. The Channel ID is displayed there.MESSAGEBIRD_WEBHOOK_SIGNING_SECRET: Create a strong, unique secret (e.g., using a password generator). Configure this exact secret in the MessageBird dashboard when setting up your webhook. This is crucial for security.PORT: The local port your Express server will listen on.Step 6: Basic Express Server Setup
Open
server.jsand add the initial Express server configuration:Explanation:
require('dotenv').config();loads the variables from your.envfile. It's crucial to call this early.require('messagebird')(process.env.MESSAGEBIRD_API_KEY)initializes the MessageBird client with your API key.express()creates an Express application instance.app.use(express.json());enables the server to parse incoming JSON payloads, which we'll use for our API endpoint and webhook handler./healthendpoint is included as good practice for monitoring.app.listenstarts the server. We add a check to ensure the essential environment variables are loaded.You can now run your basic server:
You should see
Server listening on port 3000and confirmation that the environment variables loaded.2. Sending WhatsApp Messages Programmatically
Now we'll implement the core functionality to send WhatsApp messages through the MessageBird API.
Step 1: Create the Sending Function
Add a function within
server.jsto handle the API call to MessageBird. We'll use theconversations.startmethod for simplicity, which can initiate a conversation (often requires a pre-approved template if outside the 24-hour customer service window) or send a freeform message if within the window.Explanation:
sendWhatsAppMessagefunction takes therecipientnumber andtextmessage.paramsobject required by the MessageBirdconversations.startmethod.to: The destination WhatsApp number (must be in E.164 format).from: Your unique MessageBird WhatsApp Channel ID (loaded from.env).type: Specifies the message type (textfor now). Other types includehsm(for templates),image,video,audio,file,location.content: An object containing the message payload, specific to thetype. Fortext, it's{ text: '...' }.messagebird.conversations.startinitiates the API call. It uses a callback pattern. We wrap it in aPromisefor easier use withasync/awaitin our API endpoint later.err.errorscould be implemented.Important Note on Templates (HSMs) and the 24-Hour Window:
24-Hour Customer Service Window: According to WhatsApp Business Policy, you may reply to a user message without using a Message Template as long as it's within 24 hours of the last user message (WhatsApp Business Messaging Policy). Within this window, you can send free-form session messages. Outside this window, you must use pre-approved Message Templates.
Message Templates Required Outside 24-Hour Window: To initiate a conversation with a user who hasn't messaged you in the last 24 hours, WhatsApp requires you to use a pre-approved Message Template (also known as HSM - Highly Structured Message) (Meta WhatsApp Template Guidelines).
To send a template, you would change
typeto'hsm'and modify thecontentobject accordingly. Example:Managing and submitting templates is done through the MessageBird Dashboard. (MessageBird Templates Guide)
For this guide's simplicity, we focus on the
texttype, assuming you're either replying within the 24-hour window or testing with a number where you've initiated contact manually first.3. Building the API Layer to Send Messages
Let's create an HTTP endpoint that triggers the
sendWhatsAppMessagefunction.Step 1: Add the POST Endpoint
Add the following route handler in
server.jsbefore theapp.listencall:Explanation:
app.post('/send-whatsapp', ...)defines a route that listens for POST requests on the/send-whatsapppath.const { recipient, message } = req.body;extracts the phone number and message content from the JSON request body.recipientandmessageare provided and that therecipientlooks like an E.164 number. You should implement more robust validation in a production environment (e.g., using libraries likeexpress-validator).sendWhatsAppMessagefunction is called usingawait.200 OKresponse is sent back with the MessageBird message ID and status.catch), a500 Internal Server Erroris returned with error details (be cautious about exposing too much detail in production errors).Step 2: Test the Sending Endpoint
Restart your server: If it's running, stop it (
Ctrl+C) and restart:node server.js.Use
curlor Postman: Send a POST request to your running server. Replace+YOUR_TEST_WHATSAPP_NUMBERwith a real WhatsApp number you can check (in E.164 format).Using
curl:Expected Response (Success):
Expected Response (Error - e.g., Bad Number Format):
Check WhatsApp: You should receive the message on the test number shortly after a successful API call. Check your server logs (
console.log) for output from thesendWhatsAppMessagefunction and the MessageBird API response.4. Receiving WhatsApp Messages with Webhooks
To receive incoming WhatsApp messages, you'll set up a webhook endpoint. MessageBird sends an HTTP POST request to your specified URL whenever a new message arrives, enabling two-way WhatsApp conversations.
Step 1: Expose Local Server with
ngrok(Development Only)During development, your
localhostserver isn't accessible from the public internet.ngrokcreates a secure tunnel. Remember,ngrokprovides temporary URLs suitable only for development; a permanent public URL is needed for production.Install
ngrok: Follow instructions at ngrok.com.Run
ngrok: Open a new terminal window (keep your Node server running) and startngrok, pointing it to the port your Node app is running on (default 3000):Copy the HTTPS URL:
ngrokwill display forwarding URLs. Copy thehttpsURL (e.g.,https://random-string.ngrok-free.app). This is your public webhook URL for now.Step 2: Configure Webhook in MessageBird Dashboard
https://URL fromngrok, followed by the path for your webhook handler (we'll use/webhook). Example:https://random-string.ngrok-free.app/webhookmessage.createdandmessage.updated(for status updates).MESSAGEBIRD_WEBHOOK_SIGNING_SECRETin your.envfile.Step 3: Implement the Webhook Handler in Node.js
Add the following code to
server.jsto create the/webhookendpoint and handle incoming requests. This includes crucial signature verification based on Bird's official documentation.Important: The webhook signature verification method has been updated to match Bird's official documentation (as of November 2024).
Explanation of Webhook Handler & Verification:
cryptoModule: Imported for cryptographic functions (HMAC-SHA256).express.raw({ type: 'application/json' }): This middleware is applied only to the/webhookroute. It preventsexpress.json()(which we applied globally earlier) from parsing the body for this route. We need the raw, unparsed request body (as a Buffer) to correctly verify the signature.messagebird-signatureandmessagebird-request-timestampheaders sent by MessageBird. Reconstruct the full request URL as required by Bird's verification method.timestamp + "\n" + requestUrl + "\n" + bodyHashBinarycrypto.timingSafeEqualto prevent timing attacksJSON.parse(requestBody.toString('utf8')).message.created: Extract message details (sendermessage.from, contentmessage.content, typemessage.type). This is where you add your core logic to respond or act on the incoming message (e.g., save to DB, call other services, send a reply).message.updated: Log status updates likedeliveredorreadfor messages you sent previously. Use themessage.idto update the status in your database.200 OKresponse back to MessageBird promptly. MessageBird expects a quick acknowledgment. Any time-consuming processing (database writes, external API calls) should ideally be done asynchronously (e.g., push the event data to a queue) after sending the 200 OK, to avoid timeouts.403 Forbidden,400 Bad Request).Step 4: Test Receiving Messages
node server.js.ngrokis running: Check the terminal where you startedngrok.node server.jsis running. You should see logs indicating:message.created).ngrokLogs: Thengrokterminal (or its web interface, usually athttp://localhost:4040) also shows incoming requests and their status codes, which is useful for debugging connection issues or seeing if MessageBird is hitting your endpoint.5. Implementing Proper Error Handling and Logging
While basic
console.logandconsole.errorare used, production applications need more robust logging and error handling.Error Handling Strategy:
Specific API Errors: In the
sendWhatsAppMessagecallback/promise rejection, inspect theerr.errorsarray provided by the MessageBird SDK for detailed error codes and descriptions. Log these details. Decide whether specific errors are retryable.Webhook Errors: Log signature verification failures clearly, including the received signature if possible (be mindful of logging sensitive data). Handle JSON parsing errors gracefully.
Centralized Express Error Handler: Implement Express middleware to catch unhandled errors in your routes. This should be the last middleware added.
Logging:
Replace
console.log/error: Use a dedicated logging library likewinstonorpino. These offer structured logging (JSON format is common), different log levels (info, warn, error, debug), and transport options (console, file, external logging services).Retry Mechanisms (Conceptual):
sendWhatsAppMessage, implement a retry strategy.async-retryorp-retryto simplify this implementation.6. Creating a Database Schema and Data Layer (Conceptual)
Storing message history, user consent, and conversation state is often necessary for real applications.
Schema Example (Conceptual - using PostgreSQL syntax):
Data Layer:
saveIncomingMessage(messageData): Called from the webhook handler (message.created) to insert a new record into themessagestable withdirection = 'incoming'.saveOutgoingMessage(messageData): Called before or after callingsendWhatsAppMessageto insert a record withdirection = 'outgoing'and the initialstatus(e.g., 'pending' or 'sent'). Store themessagebird_message_idreturned by the API.updateMessageStatus(messagebirdMessageId, status, timestamp): Called from the webhook handler (message.updated) to update thestatusandstatus_updated_atfields for an existing message based on itsmessagebird_message_id.checkConsent(contactMsisdn): Check thewhatsapp_consenttable before sending proactive messages (especially templates).recordConsent(contactMsisdn, optedIn): Update the consent status.Integrating this data layer involves calling these functions within your
/send-whatsappendpoint and/webhookhandler. Remember to handle database errors appropriately.7. Production Deployment Guide
Before deploying your WhatsApp integration to production, implement these essential requirements:
https://api.yourdomain.com/webhook).helmetmiddleware.Additional Resources
Conclusion
You now have a complete Node.js/Express application that can send and receive WhatsApp messages via the MessageBird (now Bird) Conversations API. This foundation can be extended with additional features like:
Remember to follow WhatsApp's Business Policy and Commerce Policy when building customer-facing WhatsApp applications.