MessageBird WhatsApp Integration with Node.js and Express: Complete Guide
Build a WhatsApp integration with Node.js and Express using MessageBird API. Learn to send messages, handle webhooks, implement security, and deploy to production.
Build a production-ready Node.js WhatsApp integration using the Express framework and MessageBird Conversations API. Learn everything from project setup and core functionality to security, error handling, and deployment.
By the end of this tutorial, you'll have a functional Express server that:
Sends text messages to WhatsApp users via the MessageBird API
Receives incoming WhatsApp messages through MessageBird webhooks
Securely handles API credentials and verifies webhook authenticity
This WhatsApp Business API integration enables programmatic customer communication on WhatsApp for use cases like automated notifications, customer support automation, and two-factor authentication. You'll use MessageBird's official Node.js SDK for simplified API interaction.
System Architecture:
Your client application triggers your Node.js server to send a message. Your Node.js server uses the MessageBird API Key to call the MessageBird API, which relays the message to WhatsApp and the end user. For incoming messages, WhatsApp sends to MessageBird, which forwards to your Node.js application via a configured webhook URL using a signing key for verification.
Node.js (LTS version recommended) and npm (or yarn)
MessageBird account
Provisioned WhatsApp Business channel on MessageBird or access to MessageBird WhatsApp Sandbox for testing
Basic understanding of Node.js, Express, and REST APIs
Tool for testing API endpoints (like curl or Postman)
ngrok or similar tunneling service for testing webhooks locally
1. Project Setup for WhatsApp Integration
Initialize your Node.js project and install the necessary dependencies for WhatsApp messaging.
Create Project Directory:
Open your terminal and create a new directory for your project, then navigate into it.
Bash
mkdir node-whatsapp-messagebird
cd node-whatsapp-messagebird
Initialize Node.js Project:
Initialize the project using npm, which creates a package.json file. The -y flag accepts default settings.
Bash
npm init -y
Install Dependencies:
Install express for your web server, dotenv to manage environment variables, and the messagebird SDK. Modern Express includes body parsing, so body-parser isn't needed separately.
Bash
npm install express dotenv messagebird
express: Web framework for Node.js. Includes built-in middleware for parsing JSON (express.json()) and raw (express.raw()) request bodies.
dotenv: Loads environment variables from a .env file into process.env. Essential for keeping secrets out of code.
messagebird: Official MessageBird Node.js SDK (v4.0.1 as of January 2023), simplifying API interactions and including webhook signature verification utilities.
Create Project Structure:
Set up a basic file structure.
Bash
touch server.js .env .gitignore
server.js: Main entry point for your Express application.
.env: Stores sensitive information like API keys. Never commit this file to version control.
.gitignore: Specifies intentionally untracked files that Git should ignore (like .env and node_modules).
Configure .gitignore:
Add the following lines to your .gitignore file to prevent committing sensitive data and unnecessary files:
Set up Environment Variables (.env):
Open the .env file and add placeholders for your MessageBird API Key and WhatsApp Channel ID. You also need a secret for webhook verification.
.env
# MessageBird API Credentials
MESSAGEBIRD_API_KEY=YOUR_MESSAGEBIRD_LIVE_API_KEY
MESSAGEBIRD_CHANNEL_ID=YOUR_WHATSAPP_CHANNEL_ID
MESSAGEBIRD_WEBHOOK_SIGNING_KEY=YOUR_WEBHOOK_SIGNING_KEY # Generate a secure random string
# Server Configuration
PORT=3000
MESSAGEBIRD_API_KEY: Your live API key from the MessageBird Dashboard (Developers → API access). Essential for server startup and API calls.
MESSAGEBIRD_CHANNEL_ID: The ID of your installed WhatsApp channel in MessageBird (Channels → WhatsApp → ID). Essential for sending messages.
MESSAGEBIRD_WEBHOOK_SIGNING_KEY: A unique, cryptographically secure random string you generate. This verifies incoming webhooks genuinely originated from MessageBird. Required only if you implement the webhook endpoint. Keep this secret.
PORT: The port your Express server listens on.
2. Implementing WhatsApp Message Sending
Build the core logic to send WhatsApp messages using the MessageBird SDK.
Basic Server Setup (server.js):
Set up a minimal Express server that loads environment variables and initializes the MessageBird client.
JavaScript
// server.jsrequire('dotenv').config(); // Load environment variables from .env fileconst express = require('express');
const messagebird = require('messagebird').initClient(process.env.MESSAGEBIRD_API_KEY);
const app = express();
const port = process.env.PORT || 3000;
// --- Middleware will be applied per-route as needed ---// We need express.json() for sending API, express.raw() for webhooks.// --- Routes will be added here ---
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
// Essential variable checksif (!process.env.MESSAGEBIRD_API_KEY) {
console.warn('CRITICAL WARNING: MESSAGEBIRD_API_KEY environment variable not set. MessageBird client initialization may fail.');
}
if (!process.env.MESSAGEBIRD_CHANNEL_ID) {
console.warn('WARNING: MESSAGEBIRD_CHANNEL_ID environment variable not set. Sending messages will likely fail.');
}
// Conditional variable checkif (!process.env.MESSAGEBIRD_WEBHOOK_SIGNING_KEY) {
console.info('INFO: MESSAGEBIRD_WEBHOOK_SIGNING_KEY environment variable not set. Webhook verification will not function if the webhook endpoint is used.');
}
});
module.exports = app; // Export for potential testing
Initialize dotenv first to ensure environment variables are available.
Initialize the messagebird client with the API key from .env.
Add startup warnings for essential environment variables. The warning for the signing key clarifies its specific purpose.
Get MessageBird Credentials:
API Key: Log in to your MessageBird Dashboard. Navigate to Developers → API access. Copy your live API key. Paste it into the MESSAGEBIRD_API_KEY field in your .env file. Never use your test key for production traffic.
Channel ID: Navigate to Channels in the Dashboard. Select your installed WhatsApp channel. Copy the Channel ID displayed. Paste it into the MESSAGEBIRD_CHANNEL_ID field in your .env file.
Webhook Signing Key: Generate a strong, random string (e.g., using a password manager or online generator). Paste this into MESSAGEBIRD_WEBHOOK_SIGNING_KEY in your .env file. You'll also need to enter this exact same key in the MessageBird dashboard when configuring your webhook later.
Create the Sending Endpoint (server.js):
Add an Express route to handle POST requests for sending messages using async/await for cleaner asynchronous code.
JavaScript
// server.js (continued)// ... previous setup code ...// Apply JSON body parser specifically for this route using built-in Express middleware
app.post('/send-whatsapp', express.json(), async (req, res) => {
const { recipientPhoneNumber, messageText } = req.body;
// Basic input validationif (!recipientPhoneNumber || !messageText) {
return res.status(400).json({ error: 'Missing required fields: recipientPhoneNumber and messageText' });
}
// Validate phone number format (basic example, enhance as needed)// E.164 format is generally recommended: +[country code][subscriber number]if (!/^\+[1-9]\d{1,14}$/.test(recipientPhoneNumber)) {
return res.status(400).json({ error: 'Invalid recipient phone number format. Use E.164 format (e.g., +14155552671).' });
}
const params = {
to: recipientPhoneNumber, // The recipient's WhatsApp number in E.164 formatfrom: process.env.MESSAGEBIRD_CHANNEL_ID, // Your WhatsApp Channel ID from MessageBirdtype: 'text',
content: {
text: messageText,
},
};
console.log(`Attempting to send message via Conversation API:`, JSON.stringify(params, null, 2));
try {
// Use the Conversations API to send the message with async/awaitconst response = await messagebird.conversations.start(params);
console.log('MessageBird API Response:', JSON.stringify(response, null, 2));
// The 'response' object contains details about the created conversation/message// Typically includes an 'id' for the conversation
res.status(200).json({ success: true, messageId: response.id, status: response.status });
} catch (err) {
console.error('Error sending WhatsApp message:', err);
// Provide more specific error feedback if possibleconst errorMessage = err.errors ? err.errors.map(e => e.description).join(', ') : (err.message || 'Failed to send message');
const statusCode = err.statusCode || 500; // Use statusCode from MessageBird error if availablereturn res.status(statusCode).json({ error: 'MessageBird API error', details: errorMessage });
}
});
// --- Webhook route will be added later ---// ... app.listen code ...
Use express.json() middleware built into Express for this route.
Perform basic validation.
Construct the params object for messagebird.conversations.start.
Use async/await with a try...catch block for the API call, improving readability and error handling flow.
The catch block handles errors from the SDK, attempting to extract specific details and status codes.
3. Building the WhatsApp API Layer
The /send-whatsapp endpoint created above constitutes your initial API layer for sending messages.
Authentication/Authorization:
Current State: The endpoint is currently open. In production, secure this endpoint before deployment. Deploying this code to the public internet without authentication poses a significant security risk, allowing anyone to send messages using your MessageBird account.
Recommendations:
API Keys: Issue unique API keys to clients. Validate the key in middleware.
JWT Tokens: Protect the route using JWT validation middleware if part of a larger system.
IP Whitelisting: Restrict access to known IP addresses.
Implement robust authentication before any production deployment.
Request Validation:
The current implementation includes basic checks.
Enhancements: Use libraries like express-validator or joi for schema validation, type checking, length constraints, etc.
API Endpoint Documentation:
Endpoint:POST /send-whatsapp
Description: Sends a text message to a specified WhatsApp number via MessageBird. Requires Authentication in Production.
Request Body (JSON):
JSON
{"recipientPhoneNumber":"+14155552671","messageText":"Hello from our Node.js app!"}
recipientPhoneNumber (string, required): Recipient's phone number in E.164 format.
messageText (string, required): The text content of the message.
Purpose: Identifies which of your WhatsApp numbers/channels should send the message.
Storage: Store in the MESSAGEBIRD_CHANNEL_ID environment variable.
Obtain/Generate Webhook Signing Key:
Path: Generate this yourself (secure random string). Enter it in MessageBird Dashboard → Channels → Select your WhatsApp Channel → Edit → Webhook section → Signing Key.
Purpose: Verifies incoming webhook requests genuinely originated from MessageBird.
Storage: Store in the MESSAGEBIRD_WEBHOOK_SIGNING_KEY environment variable. Must match the value in the MessageBird dashboard.
Purpose: Tells MessageBird where to send incoming message events. Must point to your publicly accessible /webhook endpoint.
Local Testing: Use ngrok http 3000 to get a public URL (https://<your-ngrok-id>.ngrok.io) and set the webhook URL in MessageBird to https://<your-ngrok-id>.ngrok.io/webhook.
Production: Use your deployed application's public URL (e.g., https://yourapp.yourdomain.com/webhook).
Fallback mechanisms typically involve ensuring your application's high availability and monitoring MessageBird's status. Implement retries to mitigate transient network issues.
5. Error Handling, Logging, and Retries
Production systems require robust error handling and logging.
Consistent Error Strategy:
Use standard HTTP status codes.
Return consistent JSON error responses.
Log errors server-side with detail (stack traces, request context).
Logging:
Current: Basic console.log/error.
Production: Integrate winston or pino for structured (JSON), leveled logging with configurable outputs (console, file, external services). (See Section 10 for more).
Retry Mechanisms:
Implement retries with exponential backoff for transient errors (e.g., 5xx, network timeouts) using libraries like async-retry.
Caution: Only retry idempotent operations. Sending messages might have side effects if the first attempt succeeded but the response failed. Consider tracking attempts if duplicate prevention is critical. Retries add complexity.
Implementation omitted for brevity.
Testing Error Scenarios:
Use invalid credentials in .env.
Send invalid requests to /send-whatsapp.
Simulate network errors.
Trigger webhook processing errors.
6. Database Schema and Data Layer (Optional Extension)
Storing message logs, user data, or conversation state often requires a database.
Use Cases: Auditing, user profiles, chatbot state, status tracking.
Technology: Choose a database (PostgreSQL, MongoDB, etc.) and ORM/Query Builder (Prisma, Sequelize, etc.).
Example Schema (Conceptual – PostgreSQL with Prisma):
Prisma
// schema.prisma
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client { provider = "prisma-client-js" }
model MessageLog {
id String @id @default(cuid())
messagebirdId String? @unique
direction String // "incoming" or "outgoing"
channelId String
sender String // E.164 or channel ID
recipient String // E.164 or channel ID
content Json? // Message content
status String? // e.g., pending, sent, delivered, read, failed
timestamp DateTime @default(now())
// ... other fields ...
}
Implementation: Involves setting up the DB, installing/configuring the ORM, running migrations, and using the ORM client in your code to save/retrieve data.
7. Adding Security Features
Security is non-negotiable.
Input Validation and Sanitization:
Use robust validation libraries (express-validator, joi) for API inputs and webhook payloads.
Sanitize data before database storage or display (prevent XSS/injection).
Webhook Security (Signature Verification):
Critical for /webhook. Ensures requests are from MessageBird. Implemented in the next section.
API Key Security:
Use environment variables (.env, platform secrets). Never hardcode keys.
Rotate keys periodically.
Rate Limiting:
Protect endpoints from abuse using express-rate-limit.
Bash
npm install express-rate-limit
JavaScript
// server.js (Add near the top)const rateLimit = require('express-rate-limit');
const apiLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutesmax: 100, // Limit each IP to 100 requests per windowmessage: 'Too many requests, try again later.',
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headerslegacyHeaders: false, // Disable the `X-RateLimit-*` headers
});
// Apply to relevant routes
app.use('/send-whatsapp', apiLimiter);
// Consider limits for /webhook too
Other Protections:
Use helmet (npm install helmet) for security headers: const helmet = require('helmet'); app.use(helmet());
Keep dependencies updated (npm audit fix).
Use security scanning tools.
8. Handling Special Cases: Receiving WhatsApp Messages (Webhook)
Implement the endpoint to receive incoming WhatsApp messages via MessageBird webhooks.
Set up ngrok (Local Development):
Install: https://ngrok.com/download
Run: ngrok http 3000 (or your PORT)
Note the https:// Forwarding URL.
Configure MessageBird Webhook:
Go to MessageBird Dashboard → Channels → Your WhatsApp Channel → Edit → Webhook section.
Webhook URL: Enter your public URL + /webhook (e.g., https://<ngrok-id>.ngrok.io/webhook or https://yourapp.com/webhook).
Events: Check message.created, message.updated.
Signing Key: Enter your MESSAGEBIRD_WEBHOOK_SIGNING_KEY from .env.
Save.
Create the Webhook Endpoint (server.js):
Handle POST requests, verify the signature, and process the message.
JavaScript
// server.js (continued)// ... other routes and setup ...const crypto = require('crypto'); // Node.js built-in crypto module// Helper function to verify JWT signature (adapt based on MessageBird's actual JWT structure)// This is a conceptual example; MessageBird might provide a utility or specific algorithm.// Consult MessageBird documentation for the official verification method.// The SDK's internal 'verifyRequest' might be the intended way, but using internal paths is risky.// A manual JWT verification approach is shown here for illustration if no stable utility exists.functionverifyMessageBirdJwt(token, secret) {
try {
const [headerEncoded, payloadEncoded, signatureEncoded] = token.split('.');
if (!headerEncoded || !payloadEncoded || !signatureEncoded) {
thrownewError('Invalid JWT format');
}
const signature = Buffer.from(signatureEncoded, 'base64url');
const dataToSign = `${headerEncoded}.${payloadEncoded}`;
// IMPORTANT: Verify the algorithm used by MessageBird (e.g., HS256)const expectedSignature = crypto.createHmac('sha256', secret)
.update(dataToSign)
.digest();
if (!crypto.timingSafeEqual(signature, expectedSignature)) {
thrownewError('Invalid signature');
}
const payload = JSON.parse(Buffer.from(payloadEncoded, 'base64url').toString('utf8'));
// Optional: Add timestamp validation (using payload claims like 'nbf', 'exp', 'iat')// const now = Math.floor(Date.now() / 1000);// if (payload.nbf && now < payload.nbf) throw new Error('Token not yet valid');// if (payload.exp && now >= payload.exp) throw new Error('Token expired');return payload; // Return the parsed payload if valid
} catch (err) {
console.error('JWT Verification Error:', err.message);
thrownewError(`JWT verification failed: ${err.message}`); // Re-throw for the route handler
}
}
// Webhook endpoint - Use raw body parser (built-in Express) for signature verification
app.post('/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
const signatureJwt = req.get('MessageBird-Signature-JWT'); // Official header name// const timestamp = req.get('MessageBird-Request-Timestamp'); // Use if needed by verification logicconst webhookSigningKey = process.env.MESSAGEBIRD_WEBHOOK_SIGNING_KEY;
if (!signatureJwt || !webhookSigningKey) {
console.warn('Webhook received without signature JWT or signing key not configured.');
return res.status(400).send('Signature required');
}
try {
// PREFERRED METHOD: Use MessageBird SDK's built-in verification (v4.0.1+)// The SDK provides Express middleware for webhook verification.// Example: const { verifyRequest } = require('messagebird/lib/middleware');// However, using internal lib paths may break with SDK updates.// Check official MessageBird Node.js SDK docs for stable verification method.// ALTERNATIVE METHOD: Manual JWT verification (shown below for educational purposes)// Verify the webhook signature using the JWT token.// MessageBird uses HMAC-SHA256 with the signing key.const verifiedPayload = verifyMessageBirdJwt(signatureJwt, webhookSigningKey);
// If verification passes, `verifiedPayload` contains the parsed JSON object from the JWTconsole.log('Webhook JWT verified successfully. Payload:', JSON.stringify(verifiedPayload, null, 2));
// --- Process the incoming event ---if (verifiedPayload.type === 'message.created') {
const message = verifiedPayload.message;
const conversation = verifiedPayload.conversation;
// Ensure contact and display name exist before loggingconst senderName = conversation?.contact?.displayName || 'Unknown Sender';
// Verify 'msisdn' is the correct field for sender ID in the payload.const senderNumber = conversation?.contact?.msisdn || 'Unknown Number';
console.log(`Received message from ${senderName} (${senderNumber}): ${message?.content?.text || '[Non-text content]'}`);
// Add your logic: store message, trigger replies, etc.// Example: Simple echo reply (use cautiously)// Check direction and if the conversation allows replies (e.g., based on lastReceivedDatetime)/*
if (message.direction === 'received' && conversation.lastReceivedDatetime) {
const replyParams = {
// Ensure conversation.contact.msisdn is the correct identifier for replying.
to: conversation.contact.msisdn,
from: process.env.MESSAGEBIRD_CHANNEL_ID,
type: 'text',
content: {
text: `You said: ${message.content.text}`
}
};
try {
// Use reply method with async/await
const replyRes = await messagebird.conversations.reply(conversation.id, replyParams);
console.log('Reply sent successfully:', replyRes.id);
} catch (replyErr) {
console.error('Error sending reply:', replyErr);
}
}
*/
} elseif (verifiedPayload.type === 'message.updated') {
// Handle status updates (e.g., delivered, read)const message = verifiedPayload.message;
console.log(`Message status update for ${message.id}: ${message.status}`);
// Update status in your database if tracking messages
} else {
console.log(`Received unhandled webhook type: ${verifiedPayload.type}`);
}
// --- End processing ---// Always respond quickly with 200 OK to acknowledge receipt
res.status(200).send('Webhook received');
} catch (error) {
// Log the specific error from verifyMessageBirdJwt or other issuesconsole.error('Webhook processing failed:', error.message);
res.status(400).send('Signature verification failed or processing error');
}
});
// ... app.listen code ...
Use express.raw({ type: 'application/json' }) built-in middleware for the raw body Buffer, which might be needed depending on the exact signature verification method.
Important: The code includes a conceptual verifyMessageBirdJwt function using Node's crypto module. This demonstrates manual JWT verification. Consult the official MessageBird documentation for their recommended and stable method for webhook signature verification. Using internal SDK paths like messagebird/lib/webhooks/verify is highly discouraged due to potential breaking changes in SDK updates. If MessageBird provides a stable utility function, use that instead.
The example assumes the JWT payload contains the webhook data. Adjust if the raw body is needed alongside the JWT for verification.
The try...catch block handles verification errors.
If successful, process based on verifiedPayload.type.
Comments highlight potential areas needing verification against MessageBird's specific payload structure (e.g., msisdn, lastReceivedDatetime).
The example reply uses async/await.
Crucially, respond 200 OK quickly. Offload heavy processing if necessary.
9. Performance Optimizations
For higher scale:
Asynchronous Operations: Ensure all I/O (API calls, DB) is non-blocking (using async/await or Promises correctly).
Caching: Use Redis/Memcached for frequently accessed, slow-changing data (e.g., config, user profiles).
Load Balancing: Deploy multiple instances behind a load balancer (Nginx, AWS ELB). Design stateless or use sticky sessions/external session store if needed.
Database Optimization: Use indexing, efficient queries, connection pooling.
Resource Monitoring: Use pm2 or container orchestrator features to monitor CPU/memory. Optimize bottlenecks.
10. Monitoring, Observability, and Analytics
Understand production behavior:
Health Checks: Implement a /health endpoint.
JavaScript
// server.js (add this route)
app.get('/health', (req, res) => {
// Add more checks if needed (e.g., DB connectivity)
res.status(200).json({ status: 'UP', timestamp: newDate().toISOString() });
});
Monitor this endpoint externally.
Logging: Centralize structured logs (JSON via Winston/Pino) to services like Datadog, Logz.io, Papertrail, ELK stack.
Error Tracking: Use Sentry, Bugsnag to capture and alert on runtime errors.
Metrics: Track KPIs (API latency, webhook time, message counts, error rates) using prom-client (Prometheus) or APM tools (Datadog APM, New Relic).
Dashboards: Visualize logs and metrics (Kibana, Grafana, Datadog) for system overview.
11. Troubleshooting and Common Issues
Common issues when integrating WhatsApp with Node.js:
Invalid API Key/Channel ID: Check .env against MessageBird dashboard (use live key). Look for Authentication failure or channel errors in logs or MessageBird API responses.
Webhook Verification Failed:400 Bad Request on /webhook.
Ensure MESSAGEBIRD_WEBHOOK_SIGNING_KEY in .envexactly matches the key configured in the MessageBird dashboard webhook settings.
Confirm the correct body parser (express.raw) is used for the webhook route if required by the verification method.
Verify the signature verification logic (JWT or other method) matches MessageBird's specification. Check required headers (MessageBird-Signature-JWT, MessageBird-Request-Timestamp if used).
Check timestamp tolerance if timestamp validation is enabled. Significant clock skew between MessageBird and your server can cause failures.
Message Not Sent/Received:
Check MessageBird Conversation Logs in their dashboard for detailed errors or status updates.
Verify recipient number format (E.164: + followed by country code and number) and ensure the user opted-in to receive messages from your business.
Check MessageBird account balance and channel status (active, configured correctly).
Confirm the webhook URL configured in MessageBird points correctly to your running application (ngrok URL for local testing, public deployment URL for production).
Check your server application logs (console.log, structured logs) for any errors during message sending or webhook processing.
Rate Limits:429 Too Many Requests response from MessageBird API or potential blocking. Implement client-side rate limiting if sending many messages; respect MessageBird and WhatsApp platform limits. Check MessageBird documentation for specific limits.
WhatsApp Template Messages:Crucial: To initiate conversations with users or to reply more than 24 hours after the user's last message, you must use pre-approved WhatsApp Message Templates. Sending free-form text (type: 'text') is only permitted within this 24-hour customer service window. Attempting to send free-form text outside this window results in message delivery failures. Consult the official MessageBird and WhatsApp Business Platform documentation for details on template creation, approval process, and how to send template messages via the API.
Sandbox Limitations: The MessageBird WhatsApp Sandbox environment has limitations (e.g., only works with pre-registered test numbers, potential behavioral differences from live). Always test thoroughly on a live, provisioned WhatsApp channel before full production deployment.
Opt-Ins:Critical: WhatsApp policy strictly requires businesses to obtain explicit user opt-inbefore initiating messages to them. Failure to comply with opt-in requirements can lead to suspension or banning of your WhatsApp channel. Ensure your user acquisition and communication flows clearly document user consent. Consult the official WhatsApp Business Policy and MessageBird documentation for detailed guidance on obtaining and managing opt-ins.
FAQ: MessageBird WhatsApp Integration
How do I send WhatsApp messages with Node.js?
Use the MessageBird Conversations API with their Node.js SDK. Install the messagebird package, initialize it with your API key, and call messagebird.conversations.start() with your WhatsApp channel ID, recipient number in E.164 format, and message content.
What is the 24-hour messaging window in WhatsApp Business API?
WhatsApp allows businesses to send free-form messages only within 24 hours of the user's last message. Outside this window, you must use pre-approved WhatsApp Message Templates. This policy ensures users only receive messages from businesses they've actively engaged with recently.
How do I verify MessageBird webhook signatures?
MessageBird sends webhooks with a MessageBird-Signature-JWT header containing an HMAC-SHA256 signed JWT token. Verify this signature using your webhook signing key (configured in both your .env file and MessageBird dashboard). The MessageBird Node.js SDK v4.0.1+ includes Express middleware for signature verification.
Do I need a WhatsApp Business Account for MessageBird integration?
Yes, you need a provisioned WhatsApp Business channel through MessageBird. You can start with the MessageBird WhatsApp Sandbox for testing, but production use requires an approved WhatsApp Business API account linked to your MessageBird dashboard.
What phone number format should I use for WhatsApp messages?
Always use E.164 format for phone numbers: a plus sign (+) followed by the country code and subscriber number with no spaces or special characters (e.g., +14155552671). This ensures proper message routing across international WhatsApp networks.
How do I handle incoming WhatsApp messages in Express?
Create a POST endpoint (e.g., /webhook) that accepts incoming webhooks from MessageBird. Use express.raw() middleware, verify the webhook signature, parse the message payload, and respond with 200 OK quickly. Configure this endpoint URL in your MessageBird dashboard under your WhatsApp channel settings.
What are the rate limits for sending WhatsApp messages?
Rate limits vary by your MessageBird account tier and WhatsApp Business API policies. Implement exponential backoff retry logic and respect 429 Too Many Requests responses. For high-volume messaging, contact MessageBird about enterprise tier limits and use queuing systems like Redis or RabbitMQ.
Can I use the same WhatsApp channel for multiple applications?
Yes, you can use the same WhatsApp Business channel for multiple applications, but each application should have its own API key and webhook configuration. Ensure each application's webhook endpoint is correctly configured in the MessageBird dashboard.
What are WhatsApp Message Templates?
WhatsApp Message Templates are pre-approved messages that businesses can send to users. They're required for initiating conversations with users or replying more than 24 hours after the user's last message. Templates can include placeholders for dynamic content and must be approved by WhatsApp before use.
How do I track WhatsApp message delivery status?
Track WhatsApp message delivery status by storing the MessageBird Conversation ID (messageId) and checking the conversation's status in the MessageBird dashboard. MessageBird provides detailed conversation logs that include delivery status updates.
Can I send WhatsApp messages to any phone number?
No, you can only send WhatsApp messages to users who opted-in to receive messages from your business. WhatsApp requires businesses to obtain explicit user consent before sending messages.
What happens if a WhatsApp user blocks my business?
If a WhatsApp user blocks your business, they won't receive any further messages from you. You can check the user's status in the MessageBird dashboard to see if they've blocked your business.
Can I send WhatsApp messages from a non-WhatsApp Business account?
No, WhatsApp Business API requires a provisioned WhatsApp Business channel. You cannot use a personal WhatsApp account to send business messages.
What happens if I send WhatsApp messages to a non-WhatsApp number?
If you send WhatsApp messages to a non-WhatsApp number, the messages will fail to deliver. WhatsApp only allows businesses to send messages to users who opted-in to receive messages from your business.
Can I send WhatsApp messages to multiple recipients at once?
Yes, you can send WhatsApp messages to multiple recipients by using the MessageBird Conversations API. You can send messages to up to 100 recipients in a single request.
Can I send WhatsApp messages from multiple channels?
Yes, you can send WhatsApp messages from multiple channels. Each channel has its own WhatsApp number and can be used to send messages to different recipients.
Frequently asked questions
Use the MessageBird Conversations API with their Node.js SDK and Express. Set up an Express route to handle requests, build the message parameters, and use the messagebird.conversations.start() method to send messages via the API. Don't forget to secure your API key and set up proper authentication.
It's a service that lets you programmatically send and receive WhatsApp messages through their platform. The API handles the complex integration with WhatsApp, simplifying the process for developers by providing a clean interface and SDKs like the Node.js SDK used in this article.
Install the 'messagebird' npm package, initialize the client with your API key, and create specific endpoints in your Express app to handle message sending. Use environment variables to safely store API credentials and construct the message parameters as defined in the MessageBird API documentation. Ensure all necessary opt-ins are collected before messaging.
Direct access to the WhatsApp Business API is often restricted and complex. MessageBird provides a simpler, managed interface, handling integration, security, and scalability so you can focus on building your application logic.
Use ngrok during local development to create a temporary public URL for your server. This allows MessageBird webhooks to reach your local machine, enabling you to test and debug webhook functionality before deployment.
No, WhatsApp requires explicit opt-in from users before you initiate communication. Sending unsolicited messages is a violation of their policies and can lead to account suspension. Also, replies to user-initiated conversations are restricted to a 24-hour window unless you are using a pre-approved Message Template.
Create a '.env' file in your project root, add your API key, channel ID, and signing key as 'MESSAGEBIRD_API_KEY', 'MESSAGEBIRD_CHANNEL_ID', and 'MESSAGEBIRD_WEBHOOK_SIGNING_KEY', and install the 'dotenv' npm package. The 'dotenv' package loads these variables into process.env for use in your server.js file.
The webhook signing key is used to verify the authenticity of incoming webhooks. It ensures that the requests are genuinely from MessageBird and not malicious actors. It is crucial for security.
Configure a webhook URL in your MessageBird dashboard pointing to a route in your Express app (e.g., '/webhook'). Use the signing key to verify that incoming requests originated from MessageBird, parse the JSON payload, and process the incoming messages accordingly.
After a user initiates a conversation, you can send free-form text messages within 24 hours. Beyond that window, you must use pre-approved message templates to comply with WhatsApp's Business API policies, unless the customer re-initiates the conversation.
Use the 'messagebird-signature-jwt' header from the webhook request. MessageBird provides a way to verify the signature with your signing key, and you should consult their documentation for the most secure, reliable, and current method to do this. Implement proper error handling in case of failure. Return a 200 OK as quickly as possible, offloading heavy processing if necessary.
The SDK simplifies interaction with the MessageBird API by providing convenient functions, handling authentication, and managing API calls. It reduces boilerplate code and accelerates development. Be sure to validate incoming data to maintain application security.
Install ngrok to expose your localhost. Configure your MessageBird webhook URL to point to your ngrok HTTPS URL. Send a WhatsApp message to your test number and verify that your local server receives the message.
The sandbox may have limits on the types of content or features supported. It typically only works with pre-registered test numbers and may have slight behavioral differences compared to a fully provisioned WhatsApp Business account. Testing in a live environment is crucial before production release.
Build a production-ready Node.js WhatsApp integration using the Express framework and MessageBird Conversations API. Learn everything from project setup and core functionality to security, error handling, and deployment.
By the end of this tutorial, you'll have a functional Express server that:
This WhatsApp Business API integration enables programmatic customer communication on WhatsApp for use cases like automated notifications, customer support automation, and two-factor authentication. You'll use MessageBird's official Node.js SDK for simplified API interaction.
System Architecture:
Your client application triggers your Node.js server to send a message. Your Node.js server uses the MessageBird API Key to call the MessageBird API, which relays the message to WhatsApp and the end user. For incoming messages, WhatsApp sends to MessageBird, which forwards to your Node.js application via a configured webhook URL using a signing key for verification.
Prerequisites:
curlor Postman)ngrokor similar tunneling service for testing webhooks locally1. Project Setup for WhatsApp Integration
Initialize your Node.js project and install the necessary dependencies for WhatsApp messaging.
Create Project Directory: Open your terminal and create a new directory for your project, then navigate into it.
mkdir node-whatsapp-messagebird cd node-whatsapp-messagebirdInitialize Node.js Project: Initialize the project using npm, which creates a
package.jsonfile. The-yflag accepts default settings.Install Dependencies: Install
expressfor your web server,dotenvto manage environment variables, and themessagebirdSDK. Modern Express includes body parsing, sobody-parserisn't needed separately.express: Web framework for Node.js. Includes built-in middleware for parsing JSON (express.json()) and raw (express.raw()) request bodies.dotenv: Loads environment variables from a.envfile intoprocess.env. Essential for keeping secrets out of code.messagebird: Official MessageBird Node.js SDK (v4.0.1 as of January 2023), simplifying API interactions and including webhook signature verification utilities.Create Project Structure: Set up a basic file structure.
touch server.js .env .gitignoreserver.js: Main entry point for your Express application..env: Stores sensitive information like API keys. Never commit this file to version control..gitignore: Specifies intentionally untracked files that Git should ignore (like.envandnode_modules).Configure
.gitignore: Add the following lines to your.gitignorefile to prevent committing sensitive data and unnecessary files:Set up Environment Variables (
.env): Open the.envfile and add placeholders for your MessageBird API Key and WhatsApp Channel ID. You also need a secret for webhook verification.MESSAGEBIRD_API_KEY: Your live API key from the MessageBird Dashboard (Developers → API access). Essential for server startup and API calls.MESSAGEBIRD_CHANNEL_ID: The ID of your installed WhatsApp channel in MessageBird (Channels → WhatsApp → ID). Essential for sending messages.MESSAGEBIRD_WEBHOOK_SIGNING_KEY: A unique, cryptographically secure random string you generate. This verifies incoming webhooks genuinely originated from MessageBird. Required only if you implement the webhook endpoint. Keep this secret.PORT: The port your Express server listens on.2. Implementing WhatsApp Message Sending
Build the core logic to send WhatsApp messages using the MessageBird SDK.
Basic Server Setup (
server.js): Set up a minimal Express server that loads environment variables and initializes the MessageBird client.// server.js require('dotenv').config(); // Load environment variables from .env file const express = require('express'); const messagebird = require('messagebird').initClient(process.env.MESSAGEBIRD_API_KEY); const app = express(); const port = process.env.PORT || 3000; // --- Middleware will be applied per-route as needed --- // We need express.json() for sending API, express.raw() for webhooks. // --- Routes will be added here --- app.listen(port, () => { console.log(`Server listening on port ${port}`); // Essential variable checks if (!process.env.MESSAGEBIRD_API_KEY) { console.warn('CRITICAL WARNING: MESSAGEBIRD_API_KEY environment variable not set. MessageBird client initialization may fail.'); } if (!process.env.MESSAGEBIRD_CHANNEL_ID) { console.warn('WARNING: MESSAGEBIRD_CHANNEL_ID environment variable not set. Sending messages will likely fail.'); } // Conditional variable check if (!process.env.MESSAGEBIRD_WEBHOOK_SIGNING_KEY) { console.info('INFO: MESSAGEBIRD_WEBHOOK_SIGNING_KEY environment variable not set. Webhook verification will not function if the webhook endpoint is used.'); } }); module.exports = app; // Export for potential testingdotenvfirst to ensure environment variables are available.messagebirdclient with the API key from.env.Get MessageBird Credentials:
MESSAGEBIRD_API_KEYfield in your.envfile. Never use your test key for production traffic.MESSAGEBIRD_CHANNEL_IDfield in your.envfile.MESSAGEBIRD_WEBHOOK_SIGNING_KEYin your.envfile. You'll also need to enter this exact same key in the MessageBird dashboard when configuring your webhook later.Create the Sending Endpoint (
server.js): Add an Express route to handle POST requests for sending messages usingasync/awaitfor cleaner asynchronous code.// server.js (continued) // ... previous setup code ... // Apply JSON body parser specifically for this route using built-in Express middleware app.post('/send-whatsapp', express.json(), async (req, res) => { const { recipientPhoneNumber, messageText } = req.body; // Basic input validation if (!recipientPhoneNumber || !messageText) { return res.status(400).json({ error: 'Missing required fields: recipientPhoneNumber and messageText' }); } // Validate phone number format (basic example, enhance as needed) // E.164 format is generally recommended: +[country code][subscriber number] if (!/^\+[1-9]\d{1,14}$/.test(recipientPhoneNumber)) { return res.status(400).json({ error: 'Invalid recipient phone number format. Use E.164 format (e.g., +14155552671).' }); } const params = { to: recipientPhoneNumber, // The recipient's WhatsApp number in E.164 format from: process.env.MESSAGEBIRD_CHANNEL_ID, // Your WhatsApp Channel ID from MessageBird type: 'text', content: { text: messageText, }, }; console.log(`Attempting to send message via Conversation API:`, JSON.stringify(params, null, 2)); try { // Use the Conversations API to send the message with async/await const response = await messagebird.conversations.start(params); console.log('MessageBird API Response:', JSON.stringify(response, null, 2)); // The 'response' object contains details about the created conversation/message // Typically includes an 'id' for the conversation res.status(200).json({ success: true, messageId: response.id, status: response.status }); } catch (err) { console.error('Error sending WhatsApp message:', err); // Provide more specific error feedback if possible const errorMessage = err.errors ? err.errors.map(e => e.description).join(', ') : (err.message || 'Failed to send message'); const statusCode = err.statusCode || 500; // Use statusCode from MessageBird error if available return res.status(statusCode).json({ error: 'MessageBird API error', details: errorMessage }); } }); // --- Webhook route will be added later --- // ... app.listen code ...express.json()middleware built into Express for this route.paramsobject formessagebird.conversations.start.async/awaitwith atry...catchblock for the API call, improving readability and error handling flow.catchblock handles errors from the SDK, attempting to extract specific details and status codes.3. Building the WhatsApp API Layer
The
/send-whatsappendpoint created above constitutes your initial API layer for sending messages.Authentication/Authorization:
Request Validation:
express-validatororjoifor schema validation, type checking, length constraints, etc.API Endpoint Documentation:
Endpoint:
POST /send-whatsappDescription: Sends a text message to a specified WhatsApp number via MessageBird. Requires Authentication in Production.
Request Body (JSON):
{ "recipientPhoneNumber": "+14155552671", "messageText": "Hello from our Node.js app!" }recipientPhoneNumber(string, required): Recipient's phone number in E.164 format.messageText(string, required): The text content of the message.Success Response (200 OK – JSON):
{ "success": true, "messageId": "mb_conv_xxxxxxxxxxxxxxxxxxxx", "status": "pending" }success(boolean): Indicates if MessageBird accepted the request.messageId(string): The MessageBird Conversation ID.status(string): The initial status of the conversation (e.g.,pending,accepted).Error Responses:
400 Bad Request: Missing fields or invalid phone number format.{ "error": "Missing required fields: recipientPhoneNumber and messageText" }{ "error": "Invalid recipient phone number format. Use E.164 format (e.g., +14155552671)." }401 Unauthorized/403 Forbidden(If Authentication added): Invalid or missing credentials.5xx/ Other MessageBird Errors: Error communicating with the MessageBird API.{ "error": "MessageBird API error", "details": "Authentication failure" }Testing with
curl: Replace placeholders with your actual recipient number and message. Ensure your server is running (node server.js).curl -X POST http://localhost:3000/send-whatsapp \ -H "Content-Type: application/json" \ # Add Authentication header if implemented, e.g.: -H "Authorization: Bearer YOUR_API_KEY" \ -d '{ "recipientPhoneNumber": "+1xxxxxxxxxx", "messageText": "Test message from curl!" }'4. Integrating with MessageBird (Setup Recap)
This section consolidates the critical MessageBird configuration steps:
Obtain API Key:
MESSAGEBIRD_API_KEYenvironment variable.Obtain WhatsApp Channel ID:
MESSAGEBIRD_CHANNEL_IDenvironment variable.Obtain/Generate Webhook Signing Key:
MESSAGEBIRD_WEBHOOK_SIGNING_KEYenvironment variable. Must match the value in the MessageBird dashboard.Configure Webhook URL (For Receiving Messages – Covered Later):
/webhookendpoint.ngrok http 3000to get a public URL (https://<your-ngrok-id>.ngrok.io) and set the webhook URL in MessageBird tohttps://<your-ngrok-id>.ngrok.io/webhook.https://yourapp.yourdomain.com/webhook).Fallback mechanisms typically involve ensuring your application's high availability and monitoring MessageBird's status. Implement retries to mitigate transient network issues.
5. Error Handling, Logging, and Retries
Production systems require robust error handling and logging.
Consistent Error Strategy:
Logging:
console.log/error.winstonorpinofor structured (JSON), leveled logging with configurable outputs (console, file, external services). (See Section 10 for more).Retry Mechanisms:
async-retry.Testing Error Scenarios:
.env./send-whatsapp.6. Database Schema and Data Layer (Optional Extension)
Storing message logs, user data, or conversation state often requires a database.
Use Cases: Auditing, user profiles, chatbot state, status tracking.
Technology: Choose a database (PostgreSQL, MongoDB, etc.) and ORM/Query Builder (Prisma, Sequelize, etc.).
Example Schema (Conceptual – PostgreSQL with Prisma):
Implementation: Involves setting up the DB, installing/configuring the ORM, running migrations, and using the ORM client in your code to save/retrieve data.
7. Adding Security Features
Security is non-negotiable.
Input Validation and Sanitization:
express-validator,joi) for API inputs and webhook payloads.Webhook Security (Signature Verification):
/webhook. Ensures requests are from MessageBird. Implemented in the next section.API Key Security:
.env, platform secrets). Never hardcode keys.Rate Limiting:
express-rate-limit.// server.js (Add near the top) const rateLimit = require('express-rate-limit'); const apiLimiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 100, // Limit each IP to 100 requests per window message: 'Too many requests, try again later.', standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers legacyHeaders: false, // Disable the `X-RateLimit-*` headers }); // Apply to relevant routes app.use('/send-whatsapp', apiLimiter); // Consider limits for /webhook tooOther Protections:
helmet(npm install helmet) for security headers:const helmet = require('helmet'); app.use(helmet());npm audit fix).8. Handling Special Cases: Receiving WhatsApp Messages (Webhook)
Implement the endpoint to receive incoming WhatsApp messages via MessageBird webhooks.
Set up
ngrok(Local Development):https://ngrok.com/downloadngrok http 3000(or yourPORT)https://Forwarding URL.Configure MessageBird Webhook:
/webhook(e.g.,https://<ngrok-id>.ngrok.io/webhookorhttps://yourapp.com/webhook).message.created,message.updated.MESSAGEBIRD_WEBHOOK_SIGNING_KEYfrom.env.Create the Webhook Endpoint (
server.js): Handle POST requests, verify the signature, and process the message.// server.js (continued) // ... other routes and setup ... const crypto = require('crypto'); // Node.js built-in crypto module // Helper function to verify JWT signature (adapt based on MessageBird's actual JWT structure) // This is a conceptual example; MessageBird might provide a utility or specific algorithm. // Consult MessageBird documentation for the official verification method. // The SDK's internal 'verifyRequest' might be the intended way, but using internal paths is risky. // A manual JWT verification approach is shown here for illustration if no stable utility exists. function verifyMessageBirdJwt(token, secret) { try { const [headerEncoded, payloadEncoded, signatureEncoded] = token.split('.'); if (!headerEncoded || !payloadEncoded || !signatureEncoded) { throw new Error('Invalid JWT format'); } const signature = Buffer.from(signatureEncoded, 'base64url'); const dataToSign = `${headerEncoded}.${payloadEncoded}`; // IMPORTANT: Verify the algorithm used by MessageBird (e.g., HS256) const expectedSignature = crypto.createHmac('sha256', secret) .update(dataToSign) .digest(); if (!crypto.timingSafeEqual(signature, expectedSignature)) { throw new Error('Invalid signature'); } const payload = JSON.parse(Buffer.from(payloadEncoded, 'base64url').toString('utf8')); // Optional: Add timestamp validation (using payload claims like 'nbf', 'exp', 'iat') // const now = Math.floor(Date.now() / 1000); // if (payload.nbf && now < payload.nbf) throw new Error('Token not yet valid'); // if (payload.exp && now >= payload.exp) throw new Error('Token expired'); return payload; // Return the parsed payload if valid } catch (err) { console.error('JWT Verification Error:', err.message); throw new Error(`JWT verification failed: ${err.message}`); // Re-throw for the route handler } } // Webhook endpoint - Use raw body parser (built-in Express) for signature verification app.post('/webhook', express.raw({ type: 'application/json' }), async (req, res) => { const signatureJwt = req.get('MessageBird-Signature-JWT'); // Official header name // const timestamp = req.get('MessageBird-Request-Timestamp'); // Use if needed by verification logic const webhookSigningKey = process.env.MESSAGEBIRD_WEBHOOK_SIGNING_KEY; if (!signatureJwt || !webhookSigningKey) { console.warn('Webhook received without signature JWT or signing key not configured.'); return res.status(400).send('Signature required'); } try { // PREFERRED METHOD: Use MessageBird SDK's built-in verification (v4.0.1+) // The SDK provides Express middleware for webhook verification. // Example: const { verifyRequest } = require('messagebird/lib/middleware'); // However, using internal lib paths may break with SDK updates. // Check official MessageBird Node.js SDK docs for stable verification method. // ALTERNATIVE METHOD: Manual JWT verification (shown below for educational purposes) // Verify the webhook signature using the JWT token. // MessageBird uses HMAC-SHA256 with the signing key. const verifiedPayload = verifyMessageBirdJwt(signatureJwt, webhookSigningKey); // If verification passes, `verifiedPayload` contains the parsed JSON object from the JWT console.log('Webhook JWT verified successfully. Payload:', JSON.stringify(verifiedPayload, null, 2)); // --- Process the incoming event --- if (verifiedPayload.type === 'message.created') { const message = verifiedPayload.message; const conversation = verifiedPayload.conversation; // Ensure contact and display name exist before logging const senderName = conversation?.contact?.displayName || 'Unknown Sender'; // Verify 'msisdn' is the correct field for sender ID in the payload. const senderNumber = conversation?.contact?.msisdn || 'Unknown Number'; console.log(`Received message from ${senderName} (${senderNumber}): ${message?.content?.text || '[Non-text content]'}`); // Add your logic: store message, trigger replies, etc. // Example: Simple echo reply (use cautiously) // Check direction and if the conversation allows replies (e.g., based on lastReceivedDatetime) /* if (message.direction === 'received' && conversation.lastReceivedDatetime) { const replyParams = { // Ensure conversation.contact.msisdn is the correct identifier for replying. to: conversation.contact.msisdn, from: process.env.MESSAGEBIRD_CHANNEL_ID, type: 'text', content: { text: `You said: ${message.content.text}` } }; try { // Use reply method with async/await const replyRes = await messagebird.conversations.reply(conversation.id, replyParams); console.log('Reply sent successfully:', replyRes.id); } catch (replyErr) { console.error('Error sending reply:', replyErr); } } */ } else if (verifiedPayload.type === 'message.updated') { // Handle status updates (e.g., delivered, read) const message = verifiedPayload.message; console.log(`Message status update for ${message.id}: ${message.status}`); // Update status in your database if tracking messages } else { console.log(`Received unhandled webhook type: ${verifiedPayload.type}`); } // --- End processing --- // Always respond quickly with 200 OK to acknowledge receipt res.status(200).send('Webhook received'); } catch (error) { // Log the specific error from verifyMessageBirdJwt or other issues console.error('Webhook processing failed:', error.message); res.status(400).send('Signature verification failed or processing error'); } }); // ... app.listen code ...express.raw({ type: 'application/json' })built-in middleware for the raw body Buffer, which might be needed depending on the exact signature verification method.verifyMessageBirdJwtfunction using Node'scryptomodule. This demonstrates manual JWT verification. Consult the official MessageBird documentation for their recommended and stable method for webhook signature verification. Using internal SDK paths likemessagebird/lib/webhooks/verifyis highly discouraged due to potential breaking changes in SDK updates. If MessageBird provides a stable utility function, use that instead.try...catchblock handles verification errors.verifiedPayload.type.msisdn,lastReceivedDatetime).async/await.200 OKquickly. Offload heavy processing if necessary.9. Performance Optimizations
For higher scale:
async/awaitor Promises correctly).pm2or container orchestrator features to monitor CPU/memory. Optimize bottlenecks.10. Monitoring, Observability, and Analytics
Understand production behavior:
Health Checks: Implement a
/healthendpoint.// server.js (add this route) app.get('/health', (req, res) => { // Add more checks if needed (e.g., DB connectivity) res.status(200).json({ status: 'UP', timestamp: new Date().toISOString() }); });Monitor this endpoint externally.
Logging: Centralize structured logs (JSON via Winston/Pino) to services like Datadog, Logz.io, Papertrail, ELK stack.
Error Tracking: Use Sentry, Bugsnag to capture and alert on runtime errors.
Metrics: Track KPIs (API latency, webhook time, message counts, error rates) using
prom-client(Prometheus) or APM tools (Datadog APM, New Relic).Dashboards: Visualize logs and metrics (Kibana, Grafana, Datadog) for system overview.
11. Troubleshooting and Common Issues
Common issues when integrating WhatsApp with Node.js:
.envagainst MessageBird dashboard (use live key). Look forAuthentication failureor channel errors in logs or MessageBird API responses.400 Bad Requeston/webhook.MESSAGEBIRD_WEBHOOK_SIGNING_KEYin.envexactly matches the key configured in the MessageBird dashboard webhook settings.express.raw) is used for the webhook route if required by the verification method.MessageBird-Signature-JWT,MessageBird-Request-Timestampif used).+followed by country code and number) and ensure the user opted-in to receive messages from your business.ngrokURL for local testing, public deployment URL for production).console.log, structured logs) for any errors during message sending or webhook processing.429 Too Many Requestsresponse from MessageBird API or potential blocking. Implement client-side rate limiting if sending many messages; respect MessageBird and WhatsApp platform limits. Check MessageBird documentation for specific limits.type: 'text') is only permitted within this 24-hour customer service window. Attempting to send free-form text outside this window results in message delivery failures. Consult the official MessageBird and WhatsApp Business Platform documentation for details on template creation, approval process, and how to send template messages via the API.FAQ: MessageBird WhatsApp Integration
How do I send WhatsApp messages with Node.js?
Use the MessageBird Conversations API with their Node.js SDK. Install the
messagebirdpackage, initialize it with your API key, and callmessagebird.conversations.start()with your WhatsApp channel ID, recipient number in E.164 format, and message content.What is the 24-hour messaging window in WhatsApp Business API?
WhatsApp allows businesses to send free-form messages only within 24 hours of the user's last message. Outside this window, you must use pre-approved WhatsApp Message Templates. This policy ensures users only receive messages from businesses they've actively engaged with recently.
How do I verify MessageBird webhook signatures?
MessageBird sends webhooks with a
MessageBird-Signature-JWTheader containing an HMAC-SHA256 signed JWT token. Verify this signature using your webhook signing key (configured in both your.envfile and MessageBird dashboard). The MessageBird Node.js SDK v4.0.1+ includes Express middleware for signature verification.Do I need a WhatsApp Business Account for MessageBird integration?
Yes, you need a provisioned WhatsApp Business channel through MessageBird. You can start with the MessageBird WhatsApp Sandbox for testing, but production use requires an approved WhatsApp Business API account linked to your MessageBird dashboard.
What phone number format should I use for WhatsApp messages?
Always use E.164 format for phone numbers: a plus sign (+) followed by the country code and subscriber number with no spaces or special characters (e.g.,
+14155552671). This ensures proper message routing across international WhatsApp networks.How do I handle incoming WhatsApp messages in Express?
Create a POST endpoint (e.g.,
/webhook) that accepts incoming webhooks from MessageBird. Useexpress.raw()middleware, verify the webhook signature, parse the message payload, and respond with200 OKquickly. Configure this endpoint URL in your MessageBird dashboard under your WhatsApp channel settings.What are the rate limits for sending WhatsApp messages?
Rate limits vary by your MessageBird account tier and WhatsApp Business API policies. Implement exponential backoff retry logic and respect
429 Too Many Requestsresponses. For high-volume messaging, contact MessageBird about enterprise tier limits and use queuing systems like Redis or RabbitMQ.Can I use the same WhatsApp channel for multiple applications?
Yes, you can use the same WhatsApp Business channel for multiple applications, but each application should have its own API key and webhook configuration. Ensure each application's webhook endpoint is correctly configured in the MessageBird dashboard.
What are WhatsApp Message Templates?
WhatsApp Message Templates are pre-approved messages that businesses can send to users. They're required for initiating conversations with users or replying more than 24 hours after the user's last message. Templates can include placeholders for dynamic content and must be approved by WhatsApp before use.
How do I track WhatsApp message delivery status?
Track WhatsApp message delivery status by storing the MessageBird Conversation ID (
messageId) and checking the conversation's status in the MessageBird dashboard. MessageBird provides detailed conversation logs that include delivery status updates.Can I send WhatsApp messages to any phone number?
No, you can only send WhatsApp messages to users who opted-in to receive messages from your business. WhatsApp requires businesses to obtain explicit user consent before sending messages.
What happens if a WhatsApp user blocks my business?
If a WhatsApp user blocks your business, they won't receive any further messages from you. You can check the user's status in the MessageBird dashboard to see if they've blocked your business.
Can I send WhatsApp messages from a non-WhatsApp Business account?
No, WhatsApp Business API requires a provisioned WhatsApp Business channel. You cannot use a personal WhatsApp account to send business messages.
What happens if I send WhatsApp messages to a non-WhatsApp number?
If you send WhatsApp messages to a non-WhatsApp number, the messages will fail to deliver. WhatsApp only allows businesses to send messages to users who opted-in to receive messages from your business.
Can I send WhatsApp messages to multiple recipients at once?
Yes, you can send WhatsApp messages to multiple recipients by using the MessageBird Conversations API. You can send messages to up to 100 recipients in a single request.
Can I send WhatsApp messages from multiple channels?
Yes, you can send WhatsApp messages from multiple channels. Each channel has its own WhatsApp number and can be used to send messages to different recipients.