by InlinexDev

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.

WhatsApp APINode.jstutorialMeta Cloud API

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:

  1. Permanent access tokens via System Users in Meta Business Manager
  2. Webhook signature verification to ensure requests genuinely come from Meta
  3. Idempotency — deduplicate webhook events using the message ID
  4. 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 System

A full-featured appointment booking system with WhatsApp OTP verification, intelligent slot management, and automated reminders for a premium inline skate retail store in Singapore.