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
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
Create tsconfig.json
:
{ "compilerOptions": { "target": "ES2020", "module": "CommonJS", "esModuleInterop": true, "strict": true, "outDir": "./dist" }, "include": ["src/**/*"] }
ποΈ 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}`); });
Run it with:
npx ts-node src/index.ts
Test:
curl http://localhost:3000/health
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'); } };
Add route in index.ts
:
import { handleWhatsAppWebhook } from './webhookHandler'; app.post('/whatsapp', handleWhatsAppWebhook);
π Step 4: Expose Locally for Testing
Use ngrok to get a public URL:
npx ngrok http 3000
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
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']), });
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"); } }
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");
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)