The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "bsTKD9MFb3sX0bnU",
"name": "Meta WhatsApp Cloud API - Webhook Fan-out (Duplicate)",
"active": true,
"isArchived": false,
"nodes": [
{
"id": "2610b067-dfa9-4a4c-9365-858f5f31c046",
"name": "Webhook - Verify (GET)",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
-800,
-300
],
"parameters": {
"httpMethod": "GET",
"path": "meta-wa-fanout",
"responseMode": "responseNode",
"options": {}
}
},
{
"id": "b35624d0-2d74-4bc5-8fa1-19ee8f47cf34",
"name": "Set - Verify Config",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
-680,
-300
],
"parameters": {
"mode": "manual",
"includeOtherFields": true,
"assignments": {
"assignments": [
{
"id": "assign-verify-token",
"name": "verify_token",
"value": "CHANGE_ME_VERIFY_TOKEN",
"type": "string"
}
]
},
"options": {}
}
},
{
"id": "56cad50f-443f-4cb6-9f15-f5c9140664f6",
"name": "IF - Verify Token Valid",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
-560,
-300
],
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 1
},
"conditions": [
{
"id": "cond-mode",
"leftValue": "={{ $json.query['hub.mode'] }}",
"rightValue": "subscribe",
"operator": {
"type": "string",
"operation": "equals"
}
},
{
"id": "cond-token",
"leftValue": "={{ $json.query['hub.verify_token'] }}",
"rightValue": "={{ $json.verify_token }}",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {}
}
},
{
"id": "468ef2b9-e28b-4002-93e9-c2fbadf6db8d",
"name": "Respond - Challenge (200)",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
-320,
-380
],
"parameters": {
"respondWith": "text",
"responseBody": "={{ $json.query['hub.challenge'] }}",
"options": {
"responseCode": 200
}
}
},
{
"id": "89bac256-87d5-43e4-865b-13c006eaa2b4",
"name": "Respond - Verify Failed (403)",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
-320,
-220
],
"parameters": {
"respondWith": "text",
"responseBody": "Forbidden",
"options": {
"responseCode": 403
}
}
},
{
"id": "313b9719-f159-4d1d-bee8-f923122e49b1",
"name": "Webhook - Events (POST)",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
-800,
200
],
"parameters": {
"httpMethod": "POST",
"path": "meta-wa-fanout",
"responseMode": "responseNode",
"options": {
"rawBody": true
}
}
},
{
"id": "4b6bc82c-8bc8-4ac7-9996-127906a90ede",
"name": "Set - Signature Config",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
-680,
200
],
"parameters": {
"mode": "manual",
"includeOtherFields": true,
"assignments": {
"assignments": [
{
"id": "assign-app-secret",
"name": "app_secret",
"value": "CHANGE_ME_APP_SECRET",
"type": "string"
}
]
},
"options": {}
}
},
{
"id": "df1e2f70-ffbe-4721-aaca-3158279eed06",
"name": "Code - Validate Signature",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-560,
200
],
"parameters": {
"jsCode": "const crypto = require('crypto');\nconst input = $input.first();\nconst item = input.json;\nconst binary = input.binary && input.binary.data;\nconst rawBody = binary ? Buffer.from(binary.data, 'base64').toString('utf8') : JSON.stringify(item.body || {});\nconst secret = item.app_secret;\nconst headerSig = (item.headers && item.headers['x-hub-signature-256']) || '';\nconst expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody, 'utf8').digest('hex');\nconst a = Buffer.from(headerSig);\nconst b = Buffer.from(expected);\nconst valid = a.length === b.length && crypto.timingSafeEqual(a, b);\n\nreturn [{ json: { valid, rawBody, sourceHeaders: item.headers || {} } }];"
}
},
{
"id": "7e64666e-2951-4358-9738-1208554799ee",
"name": "IF - Signature Valid",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
-320,
200
],
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 1
},
"conditions": [
{
"id": "cond-valid",
"leftValue": "={{ $json.valid }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {}
}
},
{
"id": "dc120c80-d9fb-4042-8979-8d5b8bd74348",
"name": "Respond - Ack Meta (200)",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
-80,
100
],
"parameters": {
"respondWith": "text",
"responseBody": "EVENT_RECEIVED",
"options": {
"responseCode": 200
}
}
},
{
"id": "8a895970-f392-4cad-87c0-a1f798c749e0",
"name": "Respond - Invalid Signature (401)",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
-80,
320
],
"parameters": {
"respondWith": "text",
"responseBody": "Invalid signature",
"options": {
"responseCode": 401
}
}
},
{
"id": "b9e2473f-cf2c-424f-8b97-342598a06db4",
"name": "Code - Destinations Config",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
160,
100
],
"parameters": {
"jsCode": "const prev = $input.first().json; // { valid, rawBody, sourceHeaders }\n\n// Edit this array to add/remove/enable destinations.\nconst destinations = [\n {\n name: 'chatwoot',\n url: 'https://YOUR-CHATWOOT-DOMAIN/webhooks/whatsapp/YOUR_PHONE_NUMBER_ID',\n method: 'POST',\n headers: {},\n enabled: false\n },\n {\n name: 'zap-crm-br',\n url: 'https://YOUR-ZAPCRM-DOMAIN/api/whatsapp/webhook',\n method: 'POST',\n headers: {},\n enabled: false\n },\n {\n name: 'evolution-api',\n url: 'https://YOUR-EVOLUTION-DOMAIN/webhook/meta/incoming',\n method: 'POST',\n headers: {},\n enabled: false\n }\n];\n\nreturn [{ json: { destinations, rawBody: prev.rawBody, sourceHeaders: prev.sourceHeaders } }];"
}
},
{
"id": "0cbf2a30-82c7-416a-962e-fd949cb2124c",
"name": "Split Out - Per Destination",
"type": "n8n-nodes-base.splitOut",
"typeVersion": 1,
"position": [
400,
100
],
"parameters": {
"fieldToSplitOut": "destinations",
"include": "allOtherFields",
"options": {}
}
},
{
"id": "dbe51bb8-d98a-436a-af65-bf28fae9708e",
"name": "Filter - Enabled Only",
"type": "n8n-nodes-base.filter",
"typeVersion": 2,
"position": [
640,
100
],
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 1
},
"conditions": [
{
"id": "cond-enabled",
"leftValue": "={{ $json.destinations.enabled }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {}
}
},
{
"id": "8750825a-db6e-45d9-96a3-eb16d47a5f4f",
"name": "HTTP Request - Forward Raw Body",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
880,
100
],
"onError": "continueRegularOutput",
"retryOnFail": true,
"maxTries": 2,
"waitBetweenTries": 1000,
"parameters": {
"method": "={{ $json.destinations.method || 'POST' }}",
"url": "={{ $json.destinations.url }}",
"sendHeaders": true,
"specifyHeaders": "json",
"jsonHeaders": "={{ JSON.stringify(Object.assign({ 'Content-Type': ($json.sourceHeaders && $json.sourceHeaders['content-type']) || 'application/json', 'X-Hub-Signature-256': ($json.sourceHeaders && $json.sourceHeaders['x-hub-signature-256']) || '' }, $json.destinations.headers || {})) }}",
"sendBody": true,
"contentType": "raw",
"rawContentType": "={{ ($json.sourceHeaders && $json.sourceHeaders['content-type']) || 'application/json' }}",
"body": "={{ $json.rawBody }}",
"options": {
"timeout": 10000
}
}
},
{
"id": "7f18fe61-7cc7-4fa5-976f-ce89df4fff18",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-800,
-560
],
"parameters": {
"content": "## Meta WhatsApp Cloud API \u2014 Webhook Fan-out\n\nRegister this Callback URL in Meta App Dashboard > WhatsApp > Configuration:\n`https://<YOUR-N8N-HOST>/webhook/meta-wa-fanout`\n\nSecrets: fill in 'Set - Verify Config' (verify_token) and 'Set - Signature Config' (app_secret) with real values \u2014 do not commit real values back to a public repo copy.\nDestinations: edit the 'Code - Destinations Config' node to add/enable your destinations. Ships with placeholders for Chatwoot, Zap CRM BR (https://github.com/brunopelatieri/zap-crm-br), and Evolution API \u2014 all three can run in parallel.\nSee SPEC.md and README.md in the repo for full details.\n\n\u26a0\ufe0f Avoid editing/saving this workflow from the n8n web editor UI when possible \u2014 several node options in this n8n version only take effect when set at very specific parameter paths (documented in SPEC.md \u00a713); a UI re-save has been observed to alter them. Prefer redeploying via MCP tooling for structural changes.",
"height": 300,
"width": 900,
"color": 5
}
}
],
"connections": {
"Webhook - Verify (GET)": {
"main": [
[
{
"node": "Set - Verify Config",
"type": "main",
"index": 0
}
]
]
},
"Set - Verify Config": {
"main": [
[
{
"node": "IF - Verify Token Valid",
"type": "main",
"index": 0
}
]
]
},
"IF - Verify Token Valid": {
"main": [
[
{
"node": "Respond - Challenge (200)",
"type": "main",
"index": 0
}
],
[
{
"node": "Respond - Verify Failed (403)",
"type": "main",
"index": 0
}
]
]
},
"Webhook - Events (POST)": {
"main": [
[
{
"node": "Set - Signature Config",
"type": "main",
"index": 0
}
]
]
},
"Set - Signature Config": {
"main": [
[
{
"node": "Code - Validate Signature",
"type": "main",
"index": 0
}
]
]
},
"Code - Validate Signature": {
"main": [
[
{
"node": "IF - Signature Valid",
"type": "main",
"index": 0
}
]
]
},
"IF - Signature Valid": {
"main": [
[
{
"node": "Respond - Ack Meta (200)",
"type": "main",
"index": 0
}
],
[
{
"node": "Respond - Invalid Signature (401)",
"type": "main",
"index": 0
}
]
]
},
"Respond - Ack Meta (200)": {
"main": [
[
{
"node": "Code - Destinations Config",
"type": "main",
"index": 0
}
]
]
},
"Code - Destinations Config": {
"main": [
[
{
"node": "Split Out - Per Destination",
"type": "main",
"index": 0
}
]
]
},
"Split Out - Per Destination": {
"main": [
[
{
"node": "Filter - Enabled Only",
"type": "main",
"index": 0
}
]
]
},
"Filter - Enabled Only": {
"main": [
[
{
"node": "HTTP Request - Forward Raw Body",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {},
"staticData": null,
"meta": null,
"versionId": "d3a50b35-3896-4f87-bfd5-b7b8d06b943d",
"tags": [
{
"id": "2Lx5qjEW55TRFEBD",
"name": "Cloud API Meta"
}
]
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Meta WhatsApp Cloud API - Webhook Fan-out (Duplicate). Uses httpRequest. Webhook trigger; 16 nodes.
Source: https://github.com/brunopelatieri/n8n-meta-whatsapp-webhook-duplicate/blob/main/workflow.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Flujowhatsapp. Uses @aldinokemal2104/n8n-nodes-gowa, postgres, httpRequest. Webhook trigger; 65 nodes.
HR teams, IT Operations, and System Administrators managing employee onboarding at scale. It’s perfect if you use Odoo 18 to trigger account requests and need Redmine + GitLab accounts created instant
This workflow is a complete, production-ready solution for recovering abandoned carts in Shopify stores using a multi-channel, multi-touch approach. It automates personalized follow-ups via Email, SMS
WF_UNIFIED_LEGAL_AUTOMATION. Uses googleSheets, httpRequest, telegram, telegramTrigger. Webhook trigger; 53 nodes.
Backbrief: transcripts (Zoom webhook -> Slack + vault). Uses httpRequest, slack. Webhook trigger; 52 nodes.