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)