{
  "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"
    }
  ]
}