Back to Blog
WhatsApp APINode.jsIntegrationTutorial

How to Integrate WhatsApp API in Node.js

A comprehensive guide to integrating WhatsApp API in your Node.js application. Learn how to get your API key, send your first message, receive webhooks, and handle media — with full code examples.

Vesper Team8 min read

Integrating WhatsApp messaging into your application unlocks one of the most powerful communication channels on the planet. With over 2 billion active users, WhatsApp gives businesses and developers a direct line to customers — for notifications, support, marketing, and more. In this guide, we will walk through a complete WhatsApp API integration using Node.js, from obtaining your API credentials to sending messages and processing incoming webhooks.

Prerequisites

Before you begin, make sure you have the following:

  • Node.js 18 or later installed on your machine
  • A Vesper account (sign up at vespergateway.com for a free 7-day trial)
  • Basic familiarity with REST APIs and async/await in JavaScript
  • A code editor like VS Code

Step 1: Getting Your API Key

Every interaction with the WhatsApp API starts with authentication. After creating your Vesper account, navigate to the dashboard and create a new App. Each app receives a unique API key (prefixed with vsp_) that authenticates all your requests.

// Your API key will look something like this:
const API_KEY = 'vsp_1a2b3c4d5e6f7g8h9i0j';
const BASE_URL = 'https://api.vespergateway.com/v1';

Store this key securely — never commit it to version control. Use environment variables instead:

// .env
VESPER_API_KEY=vsp_1a2b3c4d5e6f7g8h9i0j
VESPER_BASE_URL=https://api.vespergateway.com/v1

Step 2: Setting Up Your Node.js Project

Let us create a new Node.js project and install the dependencies we need:

mkdir whatsapp-integration
cd whatsapp-integration
npm init -y
npm install express dotenv

Create the entry file index.js with the basic structure:

import 'dotenv/config';
import express from 'express';

const app = express();
app.use(express.json());

const API_KEY = process.env.VESPER_API_KEY;
const BASE_URL = process.env.VESPER_BASE_URL;

// Helper function for API calls
async function vesperRequest(method, path, body) {
  const res = await fetch(`${BASE_URL}${path}`, {
    method,
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: body ? JSON.stringify(body) : undefined,
  });
  return res.json();
}

app.listen(3000, () => console.log('Server running on port 3000'));

Step 3: Creating a WhatsApp Session

Before sending messages, you need to establish a WhatsApp session. This involves creating a session on the API and then scanning a QR code with your WhatsApp mobile app to link the device.

// Create a new session
async function createSession(sessionId) {
  const result = await vesperRequest('POST', '/sessions', {
    sessionId: sessionId,
  });
  console.log('Session created:', result);
  return result;
}

// Get the QR code for linking
async function getQRCode(sessionId) {
  const result = await vesperRequest('GET', `/sessions/${sessionId}/qr`);
  console.log('Scan this QR code with your WhatsApp app');
  return result;
}

// Check session status
async function getSessionStatus(sessionId) {
  const result = await vesperRequest('GET', `/sessions/${sessionId}/status`);
  console.log('Session status:', result.status);
  return result;
}

After scanning the QR code, the session enters a connected state. Vesper handles automatic reconnection, so you do not need to re-scan the QR code every time your server restarts.

Step 4: Sending Your First Message

With the session connected, you can now send messages. The API supports text, images, documents, audio, video, and location messages.

// Send a text message
async function sendTextMessage(sessionId, to, text) {
  const result = await vesperRequest('POST', '/messages/send/text', {
    sessionId,
    to,       // Phone number with country code, e.g. '905551234567'
    text,
  });
  console.log('Message sent:', result.messageId);
  return result;
}

// Send an image message
async function sendImageMessage(sessionId, to, imageUrl, caption) {
  const result = await vesperRequest('POST', '/messages/send/image', {
    sessionId,
    to,
    url: imageUrl,
    caption,
  });
  return result;
}

// Usage
await sendTextMessage('my-session', '905551234567', 'Hello from Node.js!');

The API returns a messageId for every sent message, which you can use to track delivery status through webhooks.

Step 5: Receiving Messages via Webhooks

Webhooks let your application react to incoming messages and status updates in real time. You configure a webhook URL in your Vesper dashboard, and the API sends HTTP POST requests to that URL whenever an event occurs.

// Webhook endpoint
app.post('/webhook', (req, res) => {
  const event = req.body;

  switch (event.type) {
    case 'message.received':
      console.log(`New message from ${event.data.from}: ${event.data.text}`);
      // Process the incoming message
      handleIncomingMessage(event.data);
      break;

    case 'message.sent':
      console.log(`Message ${event.data.messageId} was sent`);
      break;

    case 'message.delivered':
      console.log(`Message ${event.data.messageId} was delivered`);
      break;

    case 'message.read':
      console.log(`Message ${event.data.messageId} was read`);
      break;

    case 'session.connected':
      console.log(`Session ${event.data.sessionId} connected`);
      break;

    case 'session.disconnected':
      console.log(`Session ${event.data.sessionId} disconnected`);
      break;

    default:
      console.log('Unknown event:', event.type);
  }

  // Always respond with 200 to acknowledge receipt
  res.status(200).json({ received: true });
});

Verifying Webhook Signatures

For security, every webhook request includes an HMAC signature in the x-vesper-signature header. Always verify this signature to ensure the request is genuinely from Vesper:

import crypto from 'crypto';

function verifyWebhookSignature(payload, signature, secret) {
  const computed = crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(payload))
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(computed),
    Buffer.from(signature)
  );
}

app.post('/webhook', (req, res) => {
  const signature = req.headers['x-vesper-signature'];
  const isValid = verifyWebhookSignature(
    req.body,
    signature,
    process.env.WEBHOOK_SECRET
  );

  if (!isValid) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  // Process event...
  res.status(200).json({ received: true });
});

Step 6: Building a Simple Auto-Reply Bot

Let us combine everything into a practical example — an auto-reply bot that responds to incoming messages with relevant information:

async function handleIncomingMessage(data) {
  const { sessionId, from, text } = data;
  const lowerText = text.toLowerCase().trim();

  let reply;

  if (lowerText === 'hello' || lowerText === 'hi') {
    reply = 'Hello! Welcome to our service. How can I help you today?';
  } else if (lowerText === 'hours') {
    reply = 'We are open Monday to Friday, 9 AM to 6 PM (UTC+3).';
  } else if (lowerText === 'pricing') {
    reply = 'Check out our pricing plans at https://vespergateway.com/#pricing';
  } else {
    reply = 'Thanks for your message! Our team will get back to you shortly.';
  }

  await sendTextMessage(sessionId, from, reply);
}

Error Handling and Best Practices

Production-grade integrations need robust error handling. Here are key best practices to follow:

  • Rate limiting: Vesper enforces rate limits per plan. Implement exponential backoff when you receive 429 responses.
  • Retry logic: Network failures happen. Wrap API calls in retry logic with 3 attempts and exponential delay.
  • Logging: Log every API call and webhook event with timestamps for debugging and audit trails.
  • Queue messages: For high-volume sending, use a message queue (like BullMQ or RabbitMQ) to manage throughput.
  • Environment separation: Use separate Vesper apps for development, staging, and production environments.
// Retry wrapper with exponential backoff
async function withRetry(fn, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await fn();
    } catch (err) {
      if (attempt === maxRetries) throw err;
      const delay = Math.pow(2, attempt) * 1000;
      console.log(`Attempt ${attempt} failed, retrying in ${delay}ms...`);
      await new Promise(r => setTimeout(r, delay));
    }
  }
}

// Usage
await withRetry(() =>
  sendTextMessage('my-session', '905551234567', 'Hello!')
);

Conclusion

You now have a fully functional WhatsApp API integration in Node.js. From session management to message sending and webhook processing, these building blocks let you create sophisticated WhatsApp-powered applications — customer support bots, notification systems, marketing campaigns, and more.

Vesper makes this process straightforward with a clean REST API, automatic session reconnection, HMAC-signed webhooks, and multi-session support. If you have not already, sign up for a free trial and start building in minutes.

Ready to get started?

Start integrating WhatsApp into your application today with Vesper. Free 7-day trial, no credit card required.

Start Free Trial