How to Integrate WhatsApp Cloud API in Node.js: A Complete Guide
Step-by-step tutorial on integrating Meta's WhatsApp Cloud API with Node.js for sending OTPs, notifications, and template messages.
Introduction
WhatsApp Cloud API opened the door for businesses to programmatically send and receive messages without relying on third-party providers. If you're building a Node.js application that needs WhatsApp messaging — whether for OTP verification, order notifications, or customer support — this guide walks you through the entire integration.
Prerequisites
- A Meta Developer account
- A registered WhatsApp Business phone number
- Node.js 18+ installed
- An Express server (or similar framework)
Step 1: Setting Up Your Meta App
Head to the Meta Developer Portal and create a new app. Select "Business" as the type, then add WhatsApp as a product. You'll receive a temporary access token and a phone number ID for testing.
Environment Variables
WHATSAPP_TOKEN=your_permanent_token
WHATSAPP_PHONE_ID=your_phone_number_id
WHATSAPP_VERIFY_TOKEN=your_webhook_verify_token
Step 2: Sending Template Messages
WhatsApp requires pre-approved templates for business-initiated conversations. Here's a utility function for sending template messages:
const axios = require('axios');
async function sendWhatsAppTemplate(to, templateName, components = []) {
const url = `https://graph.facebook.com/v18.0/${process.env.WHATSAPP_PHONE_ID}/messages`;
const payload = {
messaging_product: 'whatsapp',
to,
type: 'template',
template: {
name: templateName,
language: { code: 'en' },
components
}
};
const response = await axios.post(url, payload, {
headers: {
Authorization: `Bearer ${process.env.WHATSAPP_TOKEN}`,
'Content-Type': 'application/json'
}
});
return response.data;
}
Step 3: Webhook Configuration
Meta sends incoming messages and delivery status updates to your webhook. You need two endpoints — one for verification and one for receiving events:
// Webhook verification (GET)
app.get('/webhook', (req, res) => {
const mode = req.query['hub.mode'];
const token = req.query['hub.verify_token'];
const challenge = req.query['hub.challenge'];
if (mode === 'subscribe' && token === process.env.WHATSAPP_VERIFY_TOKEN) {
return res.status(200).send(challenge);
}
res.sendStatus(403);
});
// Incoming messages (POST)
app.post('/webhook', (req, res) => {
const entry = req.body.entry?.[0];
const change = entry?.changes?.[0];
const message = change?.value?.messages?.[0];
if (message) {
console.log(`Received from ${message.from}: ${message.text?.body}`);
// Process the message
}
res.sendStatus(200); // Always respond 200
});
Important: Always return a 200 status code quickly. Meta will retry if your webhook doesn't respond within 20 seconds, causing duplicate processing.
Step 4: Sending OTP Messages
For OTP verification, create a template with a variable parameter:
async function sendOTP(phoneNumber, otpCode) {
const components = [{
type: 'body',
parameters: [{
type: 'text',
text: otpCode
}]
}];
return sendWhatsAppTemplate(phoneNumber, 'otp_verification', components);
}
Step 5: Handling International Phone Numbers
One pitfall is phone number formatting. WhatsApp expects numbers in E.164 format (e.g., 6591234567 for Singapore). Strip all spaces, dashes, and the leading +:
function normalizePhone(phone, countryCode = '65') {
let cleaned = phone.replace(/[\s\-\+\(\)]/g, '');
if (!cleaned.startsWith(countryCode)) {
cleaned = countryCode + cleaned;
}
return cleaned;
}
Common Pitfalls
- Template approval takes time — submit templates early in your development cycle. Rejection means starting over.
- 24-hour messaging window — you can only send free-form messages within 24 hours of the customer's last message. Outside that window, only template messages work.
- Rate limits — new accounts start with lower throughput limits. Request an increase before going to production.
- Webhook reliability — use a message queue (like Bull or BullMQ) to process incoming webhooks asynchronously.
Production Considerations
For production deployments, implement:
- Permanent access tokens via System Users in Meta Business Manager
- Webhook signature verification to ensure requests genuinely come from Meta
- Idempotency — deduplicate webhook events using the message ID
- Logging — store all sent and received messages for debugging and compliance
Conclusion
WhatsApp Cloud API is a powerful channel for customer communication in regions where WhatsApp dominates. The integration is straightforward with Node.js, but attention to detail around templates, phone number formatting, and webhook reliability makes the difference between a demo and a production-ready system.
Related Project
Inlinex Booking SystemA full-featured appointment booking system with WhatsApp OTP verification, intelligent slot management, and automated reminders for a premium inline skate retail store in Singapore.