AutomationFlowsAI & RAG › Ecotrustia — Whatsapp AI Agent

Ecotrustia — Whatsapp AI Agent

Ecotrustia — WhatsApp AI Agent. Uses httpRequest, googleSheets. Webhook trigger; 13 nodes.

Webhook trigger★★★★☆ complexity13 nodesHTTP RequestGoogle Sheets
AI & RAG Trigger: Webhook Nodes: 13 Complexity: ★★★★☆ Added:

This workflow follows the Google Sheets → HTTP Request recipe pattern — see all workflows that pair these two integrations.

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 →

Download .json
{
  "name": "Ecotrustia \u2014 WhatsApp AI Agent",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "whatsapp-inbound",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "node_webhook",
      "name": "WhatsApp Inbound Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        240,
        400
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// \u2500\u2500 Meta Cloud API Webhook Verification & Message Extraction \u2500\u2500\nconst body = $input.item.json.body || $input.item.json;\n\n// Handle GET hub challenge (verification)\nif ($input.item.json.query && $input.item.json.query['hub.mode'] === 'subscribe') {\n  return [{ json: { type: 'verification', challenge: $input.item.json.query['hub.challenge'] } }];\n}\n\n// Parse incoming WhatsApp message\nconst entry = body?.entry?.[0];\nconst change = entry?.changes?.[0];\nconst value = change?.value;\nconst messageObj = value?.messages?.[0];\nconst contact = value?.contacts?.[0];\n\nif (!messageObj) {\n  return [{ json: { type: 'no_message', skip: true } }];\n}\n\nconst messageType = messageObj.type;\nlet messageText = '';\n\nif (messageType === 'text') {\n  messageText = messageObj.text?.body || '';\n} else if (messageType === 'interactive') {\n  messageText = messageObj.interactive?.button_reply?.title || messageObj.interactive?.list_reply?.title || '';\n} else {\n  // Non-text (audio, image, etc.) \u2014 escalate by default\n  messageText = '[NON_TEXT_MESSAGE]';\n}\n\nconst timestamp = new Date(parseInt(messageObj.timestamp) * 1000).toISOString();\n\nreturn [{\n  json: {\n    type: 'message',\n    skip: false,\n    from: messageObj.from,\n    waMessageId: messageObj.id,\n    customerName: contact?.profile?.name || 'Unknown',\n    messageText: messageText,\n    messageType: messageType,\n    timestamp: timestamp,\n    phoneNumberId: value?.metadata?.phone_number_id\n  }\n}];"
      },
      "id": "node_parse_message",
      "name": "Parse WhatsApp Payload",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        460,
        400
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": false,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "cond_skip",
              "leftValue": "={{ $json.skip }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equal"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "node_skip_check",
      "name": "Skip if No Message",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        680,
        400
      ]
    },
    {
      "parameters": {
        "respondWith": "text",
        "responseBody": "OK",
        "options": {
          "responseCode": 200
        }
      },
      "id": "node_webhook_ack",
      "name": "Acknowledge Meta (200 OK)",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [
        900,
        280
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// \u2500\u2500 Knowledge Base Injection \u2500\u2500\n// Product info, pricing, and FAQs for Ecotrustia Solutions\n// Update this JSON object to reflect real offerings\n\nconst knowledgeBase = {\n  company: {\n    name: \"Ecotrustia Solutions\",\n    tagline: \"Digital Agency \u2014 Web, AI, SEO & Beyond\",\n    location: \"Dubai, UAE\",\n    contact_email: \"hello@ecotrustia.com\",\n    website: \"https://ecotrustia.com\",\n    working_hours: \"Mon\u2013Fri, 9 AM \u2013 6 PM GST\"\n  },\n  services: [\n    {\n      name: \"Web Development\",\n      description: \"Custom websites, landing pages, and web apps built for performance and conversion.\",\n      starting_price: \"AED 2,500\",\n      delivery_time: \"2\u20134 weeks\",\n      popular_packages: [\n        { name: \"Starter Site\", price: \"AED 2,500\", includes: \"5 pages, mobile responsive, contact form, basic SEO\" },\n        { name: \"Business Site\", price: \"AED 5,000\", includes: \"10 pages, CMS, blog, analytics integration\" },\n        { name: \"Custom Web App\", price: \"AED 10,000+\", includes: \"Custom backend, user auth, dashboard, API integrations\" }\n      ]\n    },\n    {\n      name: \"AI Automation\",\n      description: \"WhatsApp bots, chatbots, voice agents, and n8n workflow automation for UAE businesses.\",\n      starting_price: \"AED 3,000\",\n      delivery_time: \"1\u20133 weeks\",\n      popular_packages: [\n        { name: \"WhatsApp Bot\", price: \"AED 3,000\", includes: \"AI reply agent, FAQ handling, escalation logic, Google Sheets logging\" },\n        { name: \"Full Automation Suite\", price: \"AED 8,000\", includes: \"WhatsApp + chatbot + voice agent + email automation\" }\n      ]\n    },\n    {\n      name: \"SEO\",\n      description: \"On-page SEO, technical audits, content strategy, and local UAE SEO.\",\n      starting_price: \"AED 1,500/month\",\n      delivery_time: \"Results in 2\u20133 months\",\n      popular_packages: [\n        { name: \"SEO Starter\", price: \"AED 1,500/month\", includes: \"10 pages optimised, monthly report, keyword tracking\" },\n        { name: \"SEO Growth\", price: \"AED 3,000/month\", includes: \"Full site audit, content creation, backlink building\" }\n      ]\n    },\n    {\n      name: \"Social Media Marketing\",\n      description: \"Content creation, scheduling, and paid ads management across Instagram, Facebook, TikTok.\",\n      starting_price: \"AED 2,000/month\",\n      delivery_time: \"Ongoing monthly retainer\"\n    },\n    {\n      name: \"Branding\",\n      description: \"Logo, brand identity, style guide, and brand strategy.\",\n      starting_price: \"AED 1,800\",\n      delivery_time: \"1\u20132 weeks\"\n    },\n    {\n      name: \"App Development\",\n      description: \"Mobile apps for iOS and Android.\",\n      starting_price: \"AED 15,000\",\n      delivery_time: \"6\u201312 weeks\"\n    },\n    {\n      name: \"E-commerce\",\n      description: \"Shopify, WooCommerce, and custom e-commerce solutions.\",\n      starting_price: \"AED 4,000\",\n      delivery_time: \"3\u20135 weeks\"\n    }\n  ],\n  faqs: [\n    { q: \"Do you work with businesses outside UAE?\", a: \"Yes, we work with clients across UAE, Saudi Arabia, and globally. We operate remotely and can meet via video call.\" },\n    { q: \"Do you offer payment plans?\", a: \"Yes. We typically split projects into 50% upfront and 50% on delivery. Custom plans available for larger projects.\" },\n    { q: \"How do I get started?\", a: \"Send us your project details here on WhatsApp or email hello@ecotrustia.com and we'll send you a free proposal within 24 hours.\" },\n    { q: \"Do you offer maintenance after delivery?\", a: \"Yes. We offer monthly maintenance retainers starting at AED 500/month depending on the project scope.\" },\n    { q: \"Can I see past work?\", a: \"Absolutely. Check our portfolio at https://ecotrustia.com or ask us to share specific case studies.\" },\n    { q: \"How long does a website take?\", a: \"Most websites are delivered within 2\u20134 weeks depending on complexity and how quickly you provide content.\" }\n  ],\n  escalation_triggers: [\n    \"refund\", \"complaint\", \"unhappy\", \"disappointed\", \"urgent\", \"asap\", \"problem\",\n    \"issue\", \"not working\", \"broken\", \"legal\", \"scam\", \"fraud\", \"threatening\",\n    \"human\", \"agent\", \"speak to someone\", \"call me\"\n  ]\n};\n\nconst systemPrompt = `You are Eco, an AI assistant for Ecotrustia Solutions, a Dubai-based digital agency. \nYour job is to answer inbound WhatsApp messages professionally, concisely, and warmly.\n\nHere is the knowledge base you must use to answer questions:\n${JSON.stringify(knowledgeBase, null, 2)}\n\nRULES:\n1. Always respond in the same language the customer used (Arabic or English).\n2. Keep replies under 200 words. Use bullet points for lists of services or packages.\n3. For pricing, always give the starting price and mention a free proposal is available.\n4. If the question is outside your knowledge base, say: \"Great question! Let me connect you with our team for a detailed answer.\"\n5. NEVER make up information not in the knowledge base.\n6. At the end of every response, add one of these CTAs depending on context:\n   - If they asked about pricing: \"Want a free custom quote? Just reply YES.\"\n   - If they want to start: \"Ready to kick things off? Reply START and we'll get the ball rolling.\"\n   - If you couldn't fully answer: \"I'll get someone from our team to follow up shortly.\"\n7. Return ONLY a JSON object with this exact structure \u2014 no markdown, no explanation:\n{\n  \"reply\": \"<your WhatsApp reply here>\",\n  \"intent\": \"<one of: pricing_query | service_inquiry | order_status | general_faq | escalation_required | greeting | non_text>\",\n  \"confidence\": <number between 0 and 1>,\n  \"escalate\": <true or false>,\n  \"escalation_reason\": \"<brief reason if escalate is true, else empty string>\"\n}`;\n\nreturn [{\n  json: {\n    ...($input.item.json),\n    systemPrompt: systemPrompt,\n    knowledgeBase: knowledgeBase\n  }\n}];"
      },
      "id": "node_build_prompt",
      "name": "Build System Prompt + KB",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        900,
        520
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.anthropic.com/v1/messages",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "anthropic-version",
              "value": "2023-06-01"
            },
            {
              "name": "content-type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": []
        },
        "specifyBody": "json",
        "jsonBody": "={\n  \"model\": \"claude-sonnet-4-6\",\n  \"max_tokens\": 800,\n  \"system\": {{ JSON.stringify($json.systemPrompt) }},\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": {{ JSON.stringify($json.messageText) }}\n    }\n  ]\n}",
        "options": {
          "timeout": 30000
        }
      },
      "id": "node_claude_api",
      "name": "Claude AI \u2014 Intent + Response",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1120,
        520
      ],
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// \u2500\u2500 Parse Claude Response \u2500\u2500\nconst upstream = $input.item.json;\nconst contentBlocks = upstream.content || [];\n\nlet rawText = '';\nfor (const block of contentBlocks) {\n  if (block.type === 'text') rawText += block.text;\n}\n\nlet parsed;\ntry {\n  // Strip markdown code fences if Claude adds them\n  const clean = rawText.replace(/```json|```/gi, '').trim();\n  parsed = JSON.parse(clean);\n} catch (e) {\n  // Fallback: escalate on parse failure\n  parsed = {\n    reply: \"Thanks for reaching out to Ecotrustia Solutions! Let me connect you with our team right away.\",\n    intent: \"escalation_required\",\n    confidence: 0,\n    escalate: true,\n    escalation_reason: \"Claude response parse failure: \" + e.message\n  };\n}\n\n// Also check escalation_triggers from KB as a safety net\nconst msgLower = (upstream.messageText || '').toLowerCase();\nconst triggerPhrases = upstream.knowledgeBase?.escalation_triggers || [];\nconst manualEscalate = triggerPhrases.some(t => msgLower.includes(t));\n\nconst shouldEscalate = parsed.escalate || parsed.confidence < 0.65 || manualEscalate;\n\nreturn [{\n  json: {\n    from: upstream.from,\n    customerName: upstream.customerName,\n    waMessageId: upstream.waMessageId,\n    phoneNumberId: upstream.phoneNumberId,\n    messageText: upstream.messageText,\n    timestamp: upstream.timestamp,\n    reply: parsed.reply,\n    intent: parsed.intent,\n    confidence: parsed.confidence,\n    escalate: shouldEscalate,\n    escalation_reason: shouldEscalate\n      ? (parsed.escalation_reason || (manualEscalate ? 'Trigger phrase detected' : 'Low confidence'))\n      : ''\n  }\n}];"
      },
      "id": "node_parse_claude",
      "name": "Parse Claude Response",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1340,
        520
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": false,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "cond_escalate",
              "leftValue": "={{ $json.escalate }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equal"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "node_escalation_check",
      "name": "Should Escalate?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1560,
        520
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://graph.facebook.com/v20.0/{{ $json.phoneNumberId }}/messages",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"messaging_product\": \"whatsapp\",\n  \"to\": \"{{ $json.from }}\",\n  \"type\": \"text\",\n  \"text\": {\n    \"body\": {{ JSON.stringify($json.reply) }}\n  }\n}",
        "options": {}
      },
      "id": "node_send_ai_reply",
      "name": "Send AI Reply to Customer",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1780,
        400
      ],
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://graph.facebook.com/v20.0/{{ $json.phoneNumberId }}/messages",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"messaging_product\": \"whatsapp\",\n  \"to\": \"{{ $json.from }}\",\n  \"type\": \"text\",\n  \"text\": {\n    \"body\": \"Our team has been notified and will follow up with you shortly. Thank you for your patience! \ud83d\ude4f\"\n  }\n}",
        "options": {}
      },
      "id": "node_send_escalation_reply",
      "name": "Send Escalation Message to Customer",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1780,
        640
      ],
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://graph.facebook.com/v20.0/{{ $json.phoneNumberId }}/messages",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"messaging_product\": \"whatsapp\",\n  \"to\": \"HUMAN_AGENT_WHATSAPP_NUMBER\",\n  \"type\": \"text\",\n  \"text\": {\n    \"body\": \"\ud83d\udea8 *ESCALATION ALERT \u2014 Ecotrustia AI Agent*\\n\\n*Customer:* {{ $json.customerName }}\\n*Number:* +{{ $json.from }}\\n*Time:* {{ $json.timestamp }}\\n*Intent:* {{ $json.intent }}\\n*Confidence:* {{ $json.confidence }}\\n*Reason:* {{ $json.escalation_reason }}\\n\\n*Message:*\\n{{ $json.messageText }}\\n\\n*AI Draft Reply:*\\n{{ $json.reply }}\\n\\n_Reply directly to the customer at +{{ $json.from }}_\"\n  }\n}",
        "options": {}
      },
      "id": "node_notify_human",
      "name": "Notify Human Agent via WhatsApp",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2000,
        640
      ],
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "YOUR_GOOGLE_SHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Sheet1",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "Timestamp": "={{ $json.timestamp }}",
            "Customer Name": "={{ $json.customerName }}",
            "Phone Number": "={{ $json.from }}",
            "Message": "={{ $json.messageText }}",
            "Intent": "={{ $json.intent }}",
            "Confidence": "={{ $json.confidence }}",
            "AI Reply Sent": "={{ $json.reply }}",
            "Escalated": "={{ $json.escalate }}",
            "Escalation Reason": "={{ $json.escalation_reason }}",
            "Message ID": "={{ $json.waMessageId }}"
          }
        },
        "options": {
          "cellFormat": "USER_ENTERED"
        }
      },
      "id": "node_log_to_sheets",
      "name": "Log to Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        2220,
        520
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "respondWith": "text",
        "responseBody": "OK",
        "options": {
          "responseCode": 200
        }
      },
      "id": "node_final_ack",
      "name": "Final Webhook Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [
        2440,
        520
      ]
    }
  ],
  "connections": {
    "WhatsApp Inbound Webhook": {
      "main": [
        [
          {
            "node": "Parse WhatsApp Payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse WhatsApp Payload": {
      "main": [
        [
          {
            "node": "Skip if No Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Skip if No Message": {
      "main": [
        [
          {
            "node": "Acknowledge Meta (200 OK)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build System Prompt + KB",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build System Prompt + KB": {
      "main": [
        [
          {
            "node": "Claude AI \u2014 Intent + Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Claude AI \u2014 Intent + Response": {
      "main": [
        [
          {
            "node": "Parse Claude Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Claude Response": {
      "main": [
        [
          {
            "node": "Should Escalate?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Should Escalate?": {
      "main": [
        [
          {
            "node": "Send Escalation Message to Customer",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send AI Reply to Customer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Escalation Message to Customer": {
      "main": [
        [
          {
            "node": "Notify Human Agent via WhatsApp",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Notify Human Agent via WhatsApp": {
      "main": [
        [
          {
            "node": "Log to Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send AI Reply to Customer": {
      "main": [
        [
          {
            "node": "Log to Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log to Google Sheets": {
      "main": [
        [
          {
            "node": "Final Webhook Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "saveManualExecutions": true,
    "callerPolicy": "workflowsFromSameOwner",
    "errorWorkflow": ""
  },
  "staticData": null,
  "tags": [
    {
      "createdAt": "2026-06-27T00:00:00.000Z",
      "updatedAt": "2026-06-27T00:00:00.000Z",
      "id": "tag_ecotrustia_wa",
      "name": "ecotrustia-whatsapp-agent"
    }
  ],
  "triggerCount": 0,
  "updatedAt": "2026-06-27T00:00:00.000Z",
  "versionId": "v1.0.0"
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Ecotrustia — WhatsApp AI Agent. Uses httpRequest, googleSheets. Webhook trigger; 13 nodes.

Source: https://github.com/ahmed-ali-codes/n8n-whatsapp-ai-agent/blob/main/ecotrustia_whatsapp_agent.json — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

Automate the entire product return process with an intelligent AI-powered agent that navigates return portals on your behalf 🤖. This workflow receives customer return requests, analyzes portal structu

HTTP Request, Gmail, Google Sheets
AI & RAG

Legal AI Agent for WhatsApp. Uses httpRequest, googleSheets. Webhook trigger; 12 nodes.

HTTP Request, Google Sheets
AI & RAG

Sistema Automação Jurídica - Workflow Principal. Uses googleDrive, httpRequest, googleDocs, googleSheets. Webhook trigger; 11 nodes.

Google Drive, HTTP Request, Google Docs +2
AI & RAG

AI Lead Generation & Outreach Agent. Uses httpRequest, googleSheets, gmail. Webhook trigger; 6 nodes.

HTTP Request, Google Sheets, Gmail
AI & RAG

AGA Complaint Agent (LINE). Uses httpRequest, googleSheets. Webhook trigger; 13 nodes.

HTTP Request, Google Sheets