DEV Community

L.
L.

Posted on

🟒 Build a WhatsApp Webhook Server Using the Official Facebook Business SDK in TypeScript πŸš€

We'll build a webhook server that:

  • Receives incoming messages and status updates
  • Verifies signatures securely
  • Uses the official SDK for parsing and handling events
  • Is ready to be extended into a chatbot or customer support tool

TL;DR: Learn how to create a secure, production-ready webhook server in Node.js + TypeScript that receives messages from WhatsApp using the official Facebook Node.js Business SDK. This setup works directly with WhatsApp Business API (via Meta/Facebook), so it’s perfect for chatbots, automation, and customer messaging integrations.


πŸ’¬ Why Use the Facebook Business SDK?

Instead of manually parsing WhatsApp webhook payloads, you can use the officially supported SDK:

npm install --save facebook-nodejs-business-sdk 
Enter fullscreen mode Exit fullscreen mode

This gives you:

  • Verified request signature validation πŸ”
  • Built-in message/status parsing βœ…
  • Consistent event types 🧩
  • Better error handling πŸ›‘οΈ

Perfect for building scalable WhatsApp integrations.


🧰 Tech Stack

We'll use:

  • Node.js + Express.js
  • TypeScript
  • Express middleware
  • facebook-nodejs-business-sdk
  • Optional: Zod for schema validation
  • Optional: dotenv for environment variables

πŸ“¦ Step 1: Setup Your Project

mkdir whatsapp-webhook-server cd whatsapp-webhook-server npm init -y npm install express body-parser dotenv cors helmet morgan npm install --save facebook-nodejs-business-sdk npm install --save-dev typescript ts-node @types/express zod 
Enter fullscreen mode Exit fullscreen mode

Create tsconfig.json:

{ "compilerOptions": { "target": "ES2020", "module": "CommonJS", "esModuleInterop": true, "strict": true, "outDir": "./dist" }, "include": ["src/**/*"] } 
Enter fullscreen mode Exit fullscreen mode

πŸ—οΈ Step 2: Basic Server Setup

Create src/index.ts:

import express from 'express'; import bodyParser from 'body-parser'; import dotenv from 'dotenv'; dotenv.config(); const app = express(); const PORT = process.env.PORT || 3000; // Middleware app.use(bodyParser.json()); app.use(express.json()); // Health check route app.get('/health', (req, res) => { res.status(200).send('βœ… WhatsApp webhook server is running!'); }); app.listen(PORT, () => { console.log(`πŸš€ WhatsApp webhook server is listening on port ${PORT}`); }); 
Enter fullscreen mode Exit fullscreen mode

Run it with:

npx ts-node src/index.ts 
Enter fullscreen mode Exit fullscreen mode

Test:

curl http://localhost:3000/health 
Enter fullscreen mode Exit fullscreen mode

Output: βœ… WhatsApp webhook server is running!


πŸͺ Step 3: Create WhatsApp Webhook Endpoint

WhatsApp sends JSON payloads to your webhook URL when users send messages or message statuses change.

Let’s create /whatsapp endpoint using the SDK.

Create src/webhookHandler.ts:

import { Request, Response } from 'express'; import { Webhook, Message } from 'facebook-nodejs-business-sdk'; const APP_SECRET = process.env.WHATSAPP_APP_SECRET as string; export const handleWhatsAppWebhook = (req: Request, res: Response) => { try { // Initialize Webhook class with app secret const webhook = new Webhook(APP_SECRET); // Validate and parse the request const isValid = webhook.validateRequest(req); if (!isValid) { return res.status(400).send('Invalid signature'); } const payload = webhook.getPayload(); // Handle challenge for initial setup if (payload.object === 'whatsapp_business_account') { payload.entry.forEach((entry: any) => { entry.changes.forEach((change: any) => { const value = change.value; const message = value.messages?.[0]; if (message) { console.log("πŸ’¬ Incoming message:", message); // You can now reply using WhatsApp Cloud API } const status = value.statuses?.[0]; if (status) { console.log("πŸ”„ Message status updated:", status); } }); }); // Confirm receipt return res.status(200).send('EVENT_RECEIVED'); } res.status(400).send('Unknown object type'); } catch (err) { console.error("⚠️ Error handling webhook:", err); res.status(500).send('Internal Server Error'); } }; 
Enter fullscreen mode Exit fullscreen mode

Add route in index.ts:

import { handleWhatsAppWebhook } from './webhookHandler'; app.post('/whatsapp', handleWhatsAppWebhook); 
Enter fullscreen mode Exit fullscreen mode

🌍 Step 4: Expose Locally for Testing

Use ngrok to get a public URL:

npx ngrok http 3000 
Enter fullscreen mode Exit fullscreen mode

You’ll get something like https://abc123.ngrok.io.

Use this URL when setting up your webhook in the Meta Developer Portal under your WhatsApp Business App settings.

Set the callback URL to:

https://abc123.ngrok.io/whatsapp 
Enter fullscreen mode Exit fullscreen mode

And verify token to match your app logic.


πŸ§ͺ Step 5: Add Schema Validation (Optional)

Validate the shape of incoming WhatsApp events before processing.

Example schema for message object:

// src/schemas/whatsappSchema.ts import { z } from 'zod'; export const WhatsAppMessageSchema = z.object({ from: z.string(), id: z.string(), timestamp: z.string(), text: z.object({ body: z.string() }).optional(), type: z.enum(['text', 'image', 'video', 'document', 'audio']), }); 
Enter fullscreen mode Exit fullscreen mode

In handler:

import { WhatsAppMessageSchema } from '../schemas/whatsappSchema'; if (message) { const parsed = WhatsAppMessageSchema.safeParse(message); if (parsed.success) { console.log("βœ… Valid message received:", parsed.data); } else { console.warn("❌ Invalid message structure"); } } 
Enter fullscreen mode Exit fullscreen mode

Now malformed messages are caught early ⚠️.


πŸ”„ Step 6: Acknowledge Fast, Process Later

Always respond quickly to avoid retries.

Refactor to process asynchronously:

setTimeout(async () => { await processIncomingMessage(parsed.data); }, 0); res.status(200).send("EVENT_RECEIVED"); 
Enter fullscreen mode Exit fullscreen mode

Or better yet, push to a queue system like BullMQ or Redis.


🧼 Step 7: Prepare for Production

  • Store logs securely (use Winston/Pino)
  • Set up rate limiting (express-rate-limit)
  • Rotate secrets regularly
  • Deploy to Vercel, Render, AWS, or Heroku πŸš€
  • Use HTTPS (required by WhatsApp)

βœ… Summary: What You’ve Built

Feature Description
βœ”οΈ Webhook Receiver /whatsapp endpoint accepting POSTs
βœ”οΈ Signature Verification Uses Facebook SDK for HMAC validation
βœ”οΈ Event Parsing Parses messages/statuses out-of-the-box
βœ”οΈ Async Processing Acknowledge fast, process later
βœ”οΈ External Integration Works with WhatsApp Business API
βœ”οΈ Secure by Default Uses SDK, logging, secret checks

🚨 Final Tips

  • Always respond within seconds ⚑
  • Never throw unhandled errors ⚠️
  • Log everything during dev πŸ“œ
  • Store events for audit/retry (optional) πŸ—‚οΈ
  • Rotate secrets regularly πŸ”

πŸ“’ Share This Post

If you found this useful, share it with your fellow devs and help others build secure, robust WhatsApp webhook servers too!

Top comments (0)