This workflow corresponds to n8n.io template #15491 — we link there as the canonical source.
This workflow follows the Agent → Google Sheets 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 →
{
"nodes": [
{
"id": "db7f15db-71af-4ad5-9148-a1c855a58d09",
"name": "Main",
"type": "n8n-nodes-base.stickyNote",
"position": [
-496,
2032
],
"parameters": {
"width": 944,
"height": 1000,
"content": "# \ud83e\udd16 WhatsApp AI Chatbot with Evolution API + Notion CRM\n\n**Who's it for**\nService businesses, agencies, and SMBs that get inbound WhatsApp messages and want a 24/7 AI assistant \u2014 without paying for third-party chatbot platforms.\n\n## What it does\nTurns your WhatsApp Business number into an AI-powered customer assistant that handles **text + voice messages**, filters out automatic replies from other bots, looks up leads in your **Notion CRM**, generates contextual responses with **Claude**, escalates to **Telegram** when human attention is needed, and keeps your CRM updated automatically.\n\n## How it works\n1. **Receive** \u2014 Evolution API webhook receives the WhatsApp message\n2. **Filter** \u2014 Voice messages are transcribed (Whisper); auto-replies are silently discarded\n3. **Lookup** \u2014 The lead is found in Notion CRM (or created if new). If their bot status is \"Paused\", the workflow stops\n4. **Generate** \u2014 Claude builds a contextual response using your knowledge base + lead context\n5. **Send & Log** \u2014 Reply is sent via Evolution API, the conversation is logged to Google Sheets\n6. **Escalate** \u2014 When a human is needed, the bot pauses itself for that contact and alerts you on Telegram\n\n## Setup checklist\n- \u2705 Evolution API instance (URL + API key)\n- \u2705 Anthropic API key (Claude Haiku)\n- \u2705 OpenAI API key (Whisper, optional for voice)\n- \u2705 Google Sheets OAuth (knowledge base + conversation log)\n- \u2705 Notion API (CRM lookup + updates)\n- \u2705 Telegram Bot token + Chat ID\n\n## Templates included with this workflow\n\ud83d\udce5 [Google Sheets knowledge base template](https://docs.google.com/spreadsheets/d/1O1hSVLTL-yfugolm_y22-67lV0i59R0sRM0UPPq2Dlk/edit?usp=sharing) \u2014 free\n\ud83d\uddc3\ufe0f [Notion CRM template](https://cifral.gumroad.com/l/notion-crm-template) \u2014 pre-configured for this workflow"
},
"typeVersion": 1
},
{
"id": "cc7eb408-026c-42f5-8094-ede3ffef3b6f",
"name": "Section 1",
"type": "n8n-nodes-base.stickyNote",
"position": [
528,
2020
],
"parameters": {
"color": 5,
"width": 1856,
"height": 280,
"content": "## \ud83d\udce5 STEP 1 \u2014 Receive & Filter Messages\n\nReceives WhatsApp messages from Evolution API, normalizes the payload, transcribes voice notes, and filters out automatic replies (out-of-office bots, delivery confirmations).\n\n**Evolution webhook setup:**\n- URL: `https://YOUR-N8N-DOMAIN/webhook/evo-inbound`\n- Events: MESSAGES_UPSERT, CONNECTION_UPDATE\n- webhookByEvents: OFF\n- Webhook Base64: ON (required for voice support)\n\nIf you don't need voice support, disable the audio branch."
},
"typeVersion": 1
},
{
"id": "fd31f5c5-25c3-400e-a828-189f11af8e2c",
"name": "Section 2",
"type": "n8n-nodes-base.stickyNote",
"position": [
2448,
2016
],
"parameters": {
"color": 4,
"width": 592,
"height": 424,
"content": "## \ud83d\uddc3\ufe0f STEP 2 \u2014 Lookup Lead in CRM\n\nChecks your Notion CRM for the incoming phone number:\n- **Known lead** \u2192 reads bot status + lead context (personalization note, pain point)\n- **Unknown lead** \u2192 flagged for creation later\n- If `WA ChatBot Status` = \"Paused\", the workflow stops silently \u2014 letting you take over manually\n\n---\n\n### \ud83d\uddc3\ufe0f Need a pre-built CRM?\n\nGet the **Notion CRM template** already configured to work with this workflow:\n\u2192 [cifral.gumroad.com/l/notion-crm-template](https://cifral.gumroad.com/l/notion-crm-template)\n\nIncludes all required fields, pre-built views for WhatsApp + email pipelines, and the lead schema this workflow expects."
},
"typeVersion": 1
},
{
"id": "8c5ad581-d373-41e5-b9cf-a8e706ea7fbc",
"name": "Section 3",
"type": "n8n-nodes-base.stickyNote",
"position": [
3168,
2032
],
"parameters": {
"color": 7,
"width": 1696,
"height": 328,
"content": "## \ud83e\udde0 STEP 3 \u2014 AI Processing\n\nThe AI pipeline:\n1. **Information Extractor** detects intent, sentiment, urgency, and whether a human is needed\n2. **Knowledge Base** (Google Sheets) provides business info, products, and FAQs\n3. **Build Context** combines all this with the lead context from Notion\n4. **Wait 10s** to avoid replying mid-typing\n5. **Generate Response** uses Claude Haiku with conversation memory (last 10 messages)\n6. **Format Cleaner** strips markdown for clean WhatsApp rendering\n\n\ud83d\udcda [Google Sheets template](https://docs.google.com/spreadsheets/d/1O1hSVLTL-yfugolm_y22-67lV0i59R0sRM0UPPq2Dlk/edit?usp=sharing) \u2014 3 tabs required: `Business_Info`, `Products`, `FAQs`\n\nCustomize the **system prompt** in `Generate Response` to match your business voice."
},
"typeVersion": 1
},
{
"id": "6e5922a6-a07b-4e6b-88f1-595a5fdcb329",
"name": "Section 4",
"type": "n8n-nodes-base.stickyNote",
"position": [
4912,
2032
],
"parameters": {
"color": 6,
"width": 560,
"height": 312,
"content": "## \ud83d\udce4 STEP 4 \u2014 Send Reply & Log\n\nSends the AI response via Evolution API and logs the full conversation to your `Conversation_Log` Google Sheets tab.\n\n**Send WhatsApp Reply node:**\n- URL: `https://YOUR-EVOLUTION-DOMAIN/message/sendText/YOUR-INSTANCE-NAME`\n- Header `apikey`: your Evolution API instance key\n\nThe instance name is read dynamically from the incoming webhook payload."
},
"typeVersion": 1
},
{
"id": "9003d60d-c452-4a8d-9e51-3e226d51e384",
"name": "Section 5",
"type": "n8n-nodes-base.stickyNote",
"position": [
5520,
2048
],
"parameters": {
"color": 2,
"width": 1584,
"height": 312,
"content": "## \ud83d\udea8 STEP 5 \u2014 Handoff & CRM Update\n\nWhen the AI detects buying intent, frustration, or a question it can't answer:\n1. Sends a **Telegram alert** with full conversation context\n2. Sets `WA ChatBot Status = Paused` in Notion (bot stops auto-replying)\n3. Updates the lead: `Last Contact`, `WA Status` (Positive/Negative/Neutral)\n\nIf the contact is new, a lead is **created automatically** with phone number and `Lead Source = WhatsApp`.\n\n**To resume the bot for a paused contact:** manually set `WA ChatBot Status` back to `Active` in Notion."
},
"typeVersion": 1
},
{
"id": "c82063b5-3fb1-4e9f-ba30-74e53b7f177a",
"name": "Evolution Webhook1",
"type": "n8n-nodes-base.webhook",
"notes": "SETUP: In Evolution Manager \u2192 your instance \u2192 Webhook\nURL: https://YOUR-N8N-DOMAIN/webhook/evo-inbound\n\nEnable events: MESSAGES_UPSERT, CONNECTION_UPDATE, QRCODE_UPDATED\nwebhookByEvents: OFF \u2705 (keeps URL path fixed \u2014 CRITICAL)\nWebhook Base64: ON \u2705 (required for voice message support)",
"position": [
576,
2480
],
"parameters": {
"path": "evo-inbound",
"options": {},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "0a39f3d7-fb83-4112-9f3a-590fe0c664d9",
"name": "Detect Message Type1",
"type": "n8n-nodes-base.code",
"position": [
800,
2480
],
"parameters": {
"jsCode": "// ============================================\n// EVOLUTION API PAYLOAD NORMALIZER\n// Evolution sends: { event, instance, data: { key, pushName, message, messageType, ... } }\n// With Base64 enabled, media comes as data.base64 or data.media\n// ============================================\nconst payload = items[0].json.body;\n\n// Solo procesamos mensajes entrantes (no los que enviamos nosotros)\nconst event = payload.event || '';\nif (event !== 'messages.upsert') {\n return [{ json: { skip: true, reason: 'not a message event', event } }];\n}\n\nconst data = payload.data || {};\nconst key = data.key || {};\n\n// Ignorar mensajes enviados por nosotros\nif (key.fromMe === true) {\n return [{ json: { skip: true, reason: 'fromMe message' } }];\n}\n\n// Extraer n\u00famero limpio (viene como 'user@example.com' o 'user@example.com')\nconst remoteJid = key.remoteJid || '';\nconst phone = remoteJid.replace(/@s\\.whatsapp\\.net|@c\\.us|@g\\.us/g, '');\n\n// Ignorar mensajes de grupos (tienen @g.us)\nif (remoteJid.includes('@g.us')) {\n return [{ json: { skip: true, reason: 'group message' } }];\n}\n\nconst senderName = data.pushName || 'Customer';\nconst messageType = data.messageType || 'conversation';\nconst instanceName = payload.instance || 'cifral-test';\n\n// Detectar tipo de mensaje\nconst isAudio = messageType === 'audioMessage' || messageType === 'audio';\nconst isText = messageType === 'conversation' || messageType === 'extendedTextMessage';\n\n// Extraer texto\nlet text = '';\nif (isText) {\n text = data.message?.conversation \n || data.message?.extendedTextMessage?.text \n || '';\n}\n\n// Audio viene como base64 en el payload (porque activamos Webhook Base64)\n// Evolution lo pone en data.base64 o data.message.base64\nconst audioBase64 = isAudio \n ? (data.base64 || data.media || data.message?.base64 || '')\n : '';\n\nconst messageId = key.id || String(Date.now());\nconst timestamp = data.messageTimestamp \n ? new Date(data.messageTimestamp * 1000).toISOString()\n : new Date().toISOString();\n\nreturn [{\n json: {\n skip: false,\n phone,\n sender_name: senderName,\n message_type: isAudio ? 'voice' : 'text',\n text,\n audio_base64: audioBase64,\n message_id: messageId,\n timestamp,\n instance_name: instanceName,\n raw_type: messageType\n }\n}];"
},
"typeVersion": 2
},
{
"id": "0889f728-0297-4d12-90ae-f4d25e8f363f",
"name": "Respond OK (skip)3",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
1232,
2320
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={{ { status: 'ok', reason: $('Detect Message Type1').item.json.reason } }}"
},
"typeVersion": 1.1
},
{
"id": "3b92667e-feb2-4cc7-b7b3-a2d9a27de66c",
"name": "Is Voice?1",
"type": "n8n-nodes-base.if",
"position": [
1232,
2620
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "voice-check",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $('Detect Message Type1').item.json.message_type }}",
"rightValue": "voice"
}
]
}
},
"typeVersion": 2.3
},
{
"id": "725d2b17-51cb-4e2c-a247-1e44995275ac",
"name": "Prepare Audio Binary1",
"type": "n8n-nodes-base.code",
"notes": "Convierte el base64 del audio a binario para que OpenAI Whisper pueda transcribirlo.\nNo necesita llamada HTTP extra \u2014 el audio ya vino en el webhook payload.",
"position": [
1456,
2496
],
"parameters": {
"jsCode": "// ============================================\n// PREPARE AUDIO FOR OPENAI TRANSCRIPTION\n// Evolution sends audio as base64 when 'Webhook Base64' is enabled\n// We need to convert it to binary for the OpenAI node\n// ============================================\nconst base64Audio = items[0].json.audio_base64 || '';\n\nif (!base64Audio) {\n // Si no hay base64, devuelve texto vac\u00edo para no romper el flujo\n return [{ json: { ...items[0].json, text: '[audio no disponible]' } }];\n}\n\n// Limpiar el base64 por si viene con el prefijo data:audio/ogg;base64,\nconst cleanBase64 = base64Audio.replace(/^data:audio\\/[^;]+;base64,/, '');\n\n// Convertir a buffer binario\nconst buffer = Buffer.from(cleanBase64, 'base64');\n\nreturn [{\n json: { ...items[0].json },\n binary: {\n data: {\n data: buffer.toString('base64'),\n mimeType: 'audio/ogg',\n fileName: 'audio.ogg'\n }\n }\n}];"
},
"typeVersion": 2
},
{
"id": "e4216116-2c05-4cce-88d2-ab214e2934a2",
"name": "Transcribe Audio1",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
1680,
2496
],
"parameters": {
"options": {},
"resource": "audio",
"operation": "transcribe"
},
"typeVersion": 2.1
},
{
"id": "fd255bb7-e56a-4079-9137-8a8ac5a8afa9",
"name": "Information Extractor1",
"type": "@n8n/n8n-nodes-langchain.informationExtractor",
"position": [
3264,
2592
],
"parameters": {
"text": "={{ $('Normalize and Look Match1').item.json.text }}",
"options": {},
"schemaType": "manual",
"inputSchema": "={\n \"type\": \"object\",\n \"properties\": {\n \"intent\": {\n \"type\": \"string\",\n \"description\": \"Main intent of the message. Use: interested, not_interested, asking_question, wrong_person, inquiry_price, inquiry_product, inquiry_schedule, inquiry_availability, request_quote, request_contact, greeting, other\"\n },\n \"reply_sentiment\": {\n \"type\": \"string\",\n \"description\": \"Sentiment toward a B2B outreach offer. 'positive': interested, curious, open to a call, asking for more info. 'negative': not interested, asks to stop, wrong person, dismissive. 'neutral': unclear or cannot be determined. Use 'neutral' for new inbound contacts who were not previously contacted.\"\n },\n \"product_mentioned\": {\n \"type\": \"string\",\n \"description\": \"Product or service mentioned by the person, if any. Empty if none.\"\n },\n \"urgency\": {\n \"type\": \"string\",\n \"description\": \"Urgency level: high, medium, low, none\"\n },\n \"needs_human\": {\n \"type\": \"boolean\",\n \"description\": \"True if the person asks about pricing, wants a quote, wants to speak with someone, shows buying interest, or expresses frustration. Always true for price-related questions.\"\n }\n },\n \"required\": [\"intent\", \"reply_sentiment\", \"needs_human\"]\n}"
},
"typeVersion": 1.2
},
{
"id": "57ad78b5-161d-4d00-9585-e2f337333803",
"name": "Anthropic Model (Extractor)1",
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
"position": [
3264,
2752
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "claude-haiku-4-5-20251001",
"cachedResultName": "Claude Haiku 4.5"
},
"options": {
"temperature": 0.1,
"maxTokensToSample": 150
}
},
"typeVersion": 1.3
},
{
"id": "79da27f5-8ad9-4027-ba27-075c09cfb3f0",
"name": "Read Business Info1",
"type": "n8n-nodes-base.googleSheets",
"position": [
3552,
2592
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "",
"cachedResultName": "Business_Info"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "YOUR_GOOGLE_SHEET_ID",
"cachedResultUrl": "",
"cachedResultName": "YOUR_SHEET"
}
},
"executeOnce": true,
"typeVersion": 4.7
},
{
"id": "ce06c8e2-30ec-4bb4-9328-f8f6d3ecf164",
"name": "Read Products1",
"type": "n8n-nodes-base.googleSheets",
"position": [
3712,
2592
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "list",
"value": 985832111,
"cachedResultUrl": "",
"cachedResultName": "Products"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "YOUR_GOOGLE_SHEET_ID",
"cachedResultUrl": "",
"cachedResultName": "YOUR_SHEET"
}
},
"executeOnce": true,
"typeVersion": 4.7
},
{
"id": "3007a6cd-50c9-4329-8419-7f45436907e5",
"name": "Read FAQs1",
"type": "n8n-nodes-base.googleSheets",
"position": [
3872,
2592
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "list",
"value": 374181838,
"cachedResultUrl": "",
"cachedResultName": "FAQs"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "YOUR_GOOGLE_SHEET_ID",
"cachedResultUrl": "",
"cachedResultName": "YOUR_SHEET"
}
},
"executeOnce": true,
"typeVersion": 4.7
},
{
"id": "d224a401-581c-4254-a620-108c0149f1e7",
"name": "Build Context for AI Agent1",
"type": "n8n-nodes-base.code",
"position": [
4048,
2592
],
"parameters": {
"jsCode": "// ============================================\n// BUILD CONTEXT FOR AI AGENT\n// Pulls: message data, business KB, lead context from Notion\n// ============================================\n\nconst userMessage = $('Transcribe Audio1').isExecuted \n ? $('Transcribe Audio1').first().json.text \n : $('Detect Message Type1').first().json.text || '';\n\nconst userName = $('Detect Message Type1').first().json.sender_name || 'Customer';\nconst userPhone = $('Detect Message Type1').first().json.phone || '';\nconst messageType = $('Detect Message Type1').first().json.message_type || 'text';\nconst instanceName = $('Detect Message Type1').first().json.instance_name || 'cifral-v1';\n\n// --- Knowledge base ---\nconst businessInfoItems = $('Read Business Info1').all();\nconst productsItems = $('Read Products1').all();\nconst faqsItems = $('Read FAQs1').all();\n\nconst business = {};\nbusinessInfoItems.forEach(item => {\n const d = item.json;\n if (d.business_info && d.value) business[d.business_info] = d.value;\n});\n\nconst productList = productsItems\n .filter(i => i.json.product_id)\n .map(i => {\n const p = i.json;\n const available = p.available === 'SI' ? 'AVAILABLE' : 'NOT AVAILABLE';\n const highlight = p.highlight ? ` [${p.highlight}]` : '';\n return `- ${p.name} (${p.product_id}): ${p.description}\\n Status: ${available}\\n Category: ${p.category}${highlight}`;\n })\n .join('\\n\\n');\n\nconst faqList = faqsItems\n .filter(i => i.json.question)\n .map(i => `Q: ${i.json.question}\\nA: ${i.json.answer}\\nCategory: ${i.json.category}`)\n .join('\\n\\n');\n\n// --- Extractor output ---\nconst extractor = $('Information Extractor1').first().json.output || {};\n\n// --- Notion lead context (from Check Leads node) ---\nconst notionLead = $('Check Leads1').first().json;\n\nconst outreach_context = notionLead.is_known_lead\n ? {\n is_outreach_lead: true,\n personalization_note: notionLead.personalization_note || '',\n pain_point: notionLead.pain_point || '',\n lead_status: notionLead.lead_status || '',\n notion_page_id: notionLead.page_id || ''\n }\n : {\n is_outreach_lead: false,\n notion_page_id: notionLead.page_id || ''\n };\n\nreturn [{\n json: {\n context: {\n business_name: business.business_name || 'Your Business Name',\n business_description: business.business_description || '',\n phone: business.phone || '',\n email: business.email || '',\n hours: business.hours || '',\n coverage_area: business.coverage_area || '',\n response_tone: business.response_tone || 'professional and friendly',\n language: business.language || 'same language as customer',\n products: productList || 'No products configured',\n faqs: faqList || 'No FAQs configured'\n },\n user: {\n name: userName,\n phone: userPhone,\n message: userMessage,\n message_type: messageType,\n instance_name: instanceName,\n intent: extractor.intent || 'unknown',\n product_mentioned: extractor.product_mentioned || 'none',\n reply_sentiment: extractor.reply_sentiment || 'neutral',\n urgency: extractor.urgency || 'none',\n needs_human: extractor.needs_human || false,\n outreach_context\n }\n }\n}];"
},
"typeVersion": 2
},
{
"id": "434acad4-6485-4aec-b479-f1702acd62b0",
"name": "Generate Response1",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
4400,
2568
],
"parameters": {
"text": "={{ $json.user.message }}",
"options": {
"systemMessage": "You are the virtual assistant for {{ $json.context.business_name }}. {{ $json.context.business_description }}\n\nABOUT THE BUSINESS:\n- Website: {{ $json.context.website || 'See our website' }}\n- Email: {{ $json.context.email }}\n- Hours: {{ $json.context.hours }}\n- Coverage area: {{ $json.context.coverage_area }}\n- Booking: {{ $json.context.booking_url || 'Contact us to schedule' }}\n\nSERVICES (for your reference \u2014 never list all of them at once):\n{{ $json.context.products }}\n\nFREQUENTLY ASKED QUESTIONS:\n{{ $json.context.faqs }}\n\n---\n\nFORMATTING RULES \u2014 non-negotiable:\n- No markdown: no **bold**, no _italic_, no # headers\n- No em dashes (\u2014). Use commas or periods instead\n- No bullet lists. Use plain sentences or line breaks\n- Never list all services at once with numbered descriptions\n- Short paragraphs. WhatsApp style, conversational\n- Maximum 2 emojis per message, only when natural\n\n---\n\nCONVERSATION RULES \u2014 non-negotiable:\n- One idea per message. One question per message. Never stack two questions\n- Never present all services at once. If someone asks what you do, describe the most relevant one for their context\n- If someone picks a service, describe only that service in 1-2 lines, then ask one question about their situation\n- Your goal is to understand their problem, not to present a catalog\n- Escalate to human if: they ask for a price, want to get started, ask something you cannot answer with certainty, or show clear buying intent\n\n---\n\nLANGUAGE:\nMatch the customer's language exactly. If they write in Spanish, respond in Spanish. If English, respond in English.\n\n---\n\nOUTREACH CONTEXT:\n{{ $json.user.outreach_context.is_outreach_lead ? 'This contact was previously reached via cold outreach. Use the context below to personalize your response. Do NOT introduce the business generically \u2014 they already know who we are.\\n\\nLead context: ' + $json.user.outreach_context.personalization_note + '\\nProblem identified: ' + $json.user.outreach_context.pain_point : 'This appears to be a new inbound contact with no prior outreach history. Introduce the business naturally if needed.' }}\n\nIf the person seems surprised to receive a message or asks how you got their number:\n- Acknowledge the outreach transparently (e.g. \"We found your business online and thought we could help\")\n- Never pretend the message was not cold outreach if asked directly\n\nIf reply_sentiment is \"negative\": acknowledge politely, wish them well, end the conversation. Never insist.\n\n---\n\nPRICING:\nNever quote specific prices. If asked, send them to the pricing page or invite them to book a free call.\nExample (ES): \"Los precios de cada paquete los tienes en nuestra web. Si quieres que hablemos de cu\u00e1l encaja mejor, agenda una llamada gratuita.\"\nExample (EN): \"You can check all package pricing on our website. To talk through which one fits, book a free call.\"\n\n---\n\nBOOKING:\nWhen someone wants to schedule, speak with someone, or get a recommendation:\nDirect them to the booking link configured in your Business Info sheet.\n\n---\n\nHANDOFF TO TEAM:\nRedirect warmly when:\n- They ask something complex not covered here\n- They express frustration or explicitly ask for a human\n- They want a custom quote or proposal\n\nWhen redirecting: tell them the team will follow up shortly and invite them to share their situation briefly.\n\n---\n\nVOICE NOTES:\nAcknowledge naturally at the start: \"Escuch\u00e9 tu mensaje...\" / \"Got your voice note...\""
},
"promptType": "define"
},
"typeVersion": 1.8
},
{
"id": "c92f8395-f502-4d9f-82ea-efedf3c4f450",
"name": "Anthropic Model (Response)1",
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
"position": [
4408,
2792
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "claude-haiku-4-5-20251001",
"cachedResultName": "Claude Haiku 4.5"
},
"options": {
"temperature": 0.5,
"maxTokensToSample": 250
}
},
"typeVersion": 1.3
},
{
"id": "79b02113-15b2-414d-8e1e-201d383d6d02",
"name": "Conversation Memory1",
"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
"position": [
4536,
2792
],
"parameters": {
"sessionKey": "={{ $('Detect Message Type1').first().json.phone }}",
"sessionIdType": "customKey",
"contextWindowLength": 10
},
"typeVersion": 1.3
},
{
"id": "af26f93c-40d6-44b4-b1dd-8d5988306d9b",
"name": "Send WhatsApp Reply (Evolution)1",
"type": "n8n-nodes-base.httpRequest",
"notes": "Evolution API endpoint:\nPOST /message/sendText/{instanceName}\nHeaders: apikey (no Bearer prefix \u2014 Evolution usa apikey directa)\nBody: { number, text }\n\nEl n\u00famero puede ir con o sin @s.whatsapp.net \u2014 Evolution lo resuelve.",
"position": [
4976,
2568
],
"parameters": {
"url": "=https://YOUR-EVOLUTION-DOMAIN.com/message/sendText/{{ $('Detect Message Type1').first().json.instance_name }}",
"method": "POST",
"options": {
"timeout": 10000
},
"jsonBody": "={\n \"number\": \"{{ $('Detect Message Type1').first().json.phone }}\",\n \"text\": {{ JSON.stringify(\n ($('Detect Message Type1').first().json.message_type === 'voice' ? '\ud83c\udfa4 ' : '') + $json.output\n ) }}\n}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"headerParameters": {
"parameters": [
{
"name": "apikey",
"value": "=Add your instance API KEY Here"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "154d02a4-608b-49c0-ae29-ad4b74dad694",
"name": "Format for Log1",
"type": "n8n-nodes-base.set",
"position": [
5200,
2568
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "f001",
"name": "timestamp",
"type": "string",
"value": "={{ $now }}"
},
{
"id": "f002",
"name": "channel",
"type": "string",
"value": "whatsapp"
},
{
"id": "f003",
"name": "user_id",
"type": "string",
"value": "={{ $('Detect Message Type1').first().json.phone }}"
},
{
"id": "f004",
"name": "username",
"type": "string",
"value": "={{ $('Detect Message Type1').first().json.sender_name }}"
},
{
"id": "f005",
"name": "user_name",
"type": "string",
"value": "={{ $('Detect Message Type1').first().json.phone }}"
},
{
"id": "f006",
"name": "message_type",
"type": "string",
"value": "={{ $('Detect Message Type1').first().json.message_type }}"
},
{
"id": "f007",
"name": "message",
"type": "string",
"value": "={{ $('Build Context for AI Agent1').item.json.user.message }}"
},
{
"id": "f008",
"name": "intent",
"type": "string",
"value": "={{ $('Information Extractor1').first().json.output.intent }}"
},
{
"id": "f009",
"name": "response",
"type": "string",
"value": "={{ $('Generate Response1').item.json.output }}"
},
{
"id": "f010",
"name": "needs_human",
"type": "string",
"value": "={{ String($('Information Extractor1').first().json.output.needs_human) }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "e405b452-2988-4bf5-b9a2-81a7062af1d9",
"name": "Log Conversation1",
"type": "n8n-nodes-base.googleSheets",
"position": [
5584,
2576
],
"parameters": {
"columns": {
"value": {
"intent": "={{ $json.intent }}",
"channel": "={{ $json.channel }}",
"message": "={{ $json.message }}",
"user_id": "={{ $json.user_id }}",
"response": "={{ $json.response }}",
"username": "={{ $json.username }}",
"timestamp": "={{ $json.timestamp }}",
"user_name": "={{ $json.user_name }}",
"needs_human": "={{ $json.needs_human }}",
"message_type": "={{ $json.message_type }}"
},
"schema": [
{
"id": "timestamp",
"type": "string",
"display": true,
"required": false,
"displayName": "timestamp",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "channel",
"type": "string",
"display": true,
"required": false,
"displayName": "channel",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "sender",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "sender",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "message",
"type": "string",
"display": true,
"required": false,
"displayName": "message",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "response",
"type": "string",
"display": true,
"required": false,
"displayName": "response",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "needs_human",
"type": "string",
"display": true,
"required": false,
"displayName": "needs_human",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "user_id",
"type": "string",
"display": true,
"required": false,
"displayName": "user_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "username",
"type": "string",
"display": true,
"required": false,
"displayName": "username",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "user_name",
"type": "string",
"display": true,
"required": false,
"displayName": "user_name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "message_type",
"type": "string",
"display": true,
"required": false,
"displayName": "message_type",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "intent",
"type": "string",
"display": true,
"required": false,
"displayName": "intent",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": 1112054313,
"cachedResultUrl": "",
"cachedResultName": "Conversation_Log"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "YOUR_GOOGLE_SHEET_ID",
"cachedResultUrl": "",
"cachedResultName": "YOUR_SHEET"
}
},
"typeVersion": 4.7
},
{
"id": "a43e9b37-c6c8-4f23-828b-03353325a434",
"name": "Alert Owner?1",
"type": "n8n-nodes-base.if",
"position": [
5808,
2576
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "human-check",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.needs_human }}",
"rightValue": "true"
}
]
}
},
"typeVersion": 2.3
},
{
"id": "2d7e4f62-767c-4b5a-8b63-3f4d60be742c",
"name": "Alert Owner (Telegram)1",
"type": "n8n-nodes-base.telegram",
"notes": "Get your Chat ID by sending a message to @userinfobot on Telegram.\nSet it directly in this node or use an n8n environment variable.",
"position": [
6032,
2496
],
"parameters": {
"text": "=\ud83d\udea8 *WhatsApp \u2014 Customer needs attention*\n\n\ud83d\udc64 *Name:* {{ $json.username }}\n\ud83d\udcf1 *Phone:* {{ $json.user_id }}\n\ud83d\udce9 *Type:* {{ $json.message_type }}\n\ud83c\udfaf *Intent:* {{ $json.intent }}\n\n*Message:*\n{{ $json.message }}\n\n*BOT RESPONSE:*\n{{ $json.response }}\n\n---\n\ud83d\udd50 {{ $json.timestamp }}",
"chatId": "=ADD_YOUR_TELEGRAM_CHAT_ID",
"additionalFields": {
"parse_mode": "HTML",
"appendAttribution": false
}
},
"typeVersion": 1.2
},
{
"id": "b3d554f9-9420-431b-84bc-1e94edf92844",
"name": "Wait1",
"type": "n8n-nodes-base.wait",
"position": [
4224,
2592
],
"parameters": {
"amount": 10
},
"typeVersion": 1.1
},
{
"id": "c8534b1c-864c-4c16-b0cf-78d7350e21f3",
"name": "Format Cleaner1",
"type": "n8n-nodes-base.code",
"position": [
4752,
2568
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "// Strip markdown formatting from AI response\nlet text = $input.item.json.output || '';\n\n// Remove bold/italic\ntext = text.replace(/\\*\\*(.*?)\\*\\*/g, '$1');\ntext = text.replace(/\\*(.*?)\\*/g, '$1');\ntext = text.replace(/_(.*?)_/g, '$1');\n\n// Replace em dashes with comma\ntext = text.replace(/ \u2014 /g, ', ');\ntext = text.replace(/\u2014/g, ', ');\n\n// Remove markdown headers\ntext = text.replace(/^#{1,3}\\s+/gm, '');\n\n// Clean up extra blank lines (max 1)\ntext = text.replace(/\\n{3,}/g, '\\n\\n');\n\nreturn { json: { ...$input.item.json, output: text.trim() } };\n"
},
"typeVersion": 2
},
{
"id": "4eca12e6-2f1b-4820-beca-b4ec624ddb8b",
"name": "Skip Event1",
"type": "n8n-nodes-base.if",
"position": [
1008,
2464
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "or",
"conditions": [
{
"id": "59df61c1-eed2-452c-bbdb-ee44dcfe22d4",
"operator": {
"type": "boolean",
"operation": "equals"
},
"leftValue": "={{ $json.skip }}",
"rightValue": true
},
{
"id": "f26cad4c-ca7f-478b-8f0d-23b6b2844db5",
"operator": {
"type": "string",
"operation": "empty",
"singleValue": true
},
"leftValue": "={{ $json.text }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.3
},
{
"id": "9b0e79f0-44fe-45c9-b888-51fcd57c6e91",
"name": "Update Lead Status1",
"type": "n8n-nodes-base.notion",
"position": [
6704,
2480
],
"parameters": {
"pageId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Normalize and Look Match1').first().json.page_id }}"
},
"options": {},
"resource": "databasePage",
"operation": "update",
"propertiesUi": {
"propertyValues": [
{
"key": "Last Contact|date",
"date": "={{ $now }}"
},
{
"key": "WA Status|select",
"selectValue": "={{ $('Information Extractor1').first().json.reply_sentiment === 'positive' ? 'Positive Reply' : $('Information Extractor1').first().json.reply_sentiment === 'negative' ? 'Negative Reply' : 'Neutral Reply' }}"
},
{
"key": "Status|status",
"statusValue": "In Contact"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "f7ea0462-b7d1-47a1-b051-b4d4762df934",
"name": "Respond 1",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
6928,
2576
],
"parameters": {
"options": {
"responseCode": 200
},
"respondWith": "json",
"responseBody": "={{ { status: 'ok' } }}"
},
"typeVersion": 1.1
},
{
"id": "12d91158-530b-484a-b29c-f8521580fcae",
"name": "Phone Match1",
"type": "n8n-nodes-base.if",
"position": [
6480,
2576
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "63f5d6c9-d9bd-417a-8c6c-669dfe172776",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $('Normalize and Look Match1').first().json.matched }}",
"rightValue": "={{ $json.matched }}"
}
]
}
},
"typeVersion": 2.3
},
{
"id": "2a113cff-bafe-4545-9760-bfe61fc3dc31",
"name": "Sentiment Analysis1",
"type": "@n8n/n8n-nodes-langchain.sentimentAnalysis",
"position": [
1888,
2640
],
"parameters": {
"options": {
"categories": "Automatic reply, Human message"
},
"inputText": "={{ $json.text }}"
},
"typeVersion": 1.1
},
{
"id": "3268891e-33cf-4448-8f7a-cb85a4ad7436",
"name": "Anthropic Chat Model1",
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
"position": [
1904,
2832
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "claude-haiku-4-5-20251001",
"cachedResultName": "Claude Haiku 4.5"
},
"options": {
"temperature": 0.4
}
},
"typeVersion": 1.3
},
{
"id": "18031833-35ea-4035-aedb-6fc1ce63704f",
"name": "Create a New Lead1",
"type": "n8n-nodes-base.notion",
"position": [
6704,
2672
],
"parameters": {
"title": "={{ $('Detect Message Type1').first().json.sender_name }}",
"options": {},
"resource": "databasePage",
"databaseId": {
"__rl": true,
"mode": "list",
"value": "YOUR_NOTION_DATABASE_ID",
"cachedResultUrl": "",
"cachedResultName": "YOUR_DATABASE_NAME"
},
"propertiesUi": {
"propertyValues": [
{
"key": "Phone|phone_number",
"phoneValue": "={{ $('Detect Message Type1').first().json.phone }}"
},
{
"key": "Status|status",
"statusValue": "Lead"
},
{
"key": "Lead Source|select",
"selectValue": "WhatsApp"
},
{
"key": "Last Contact|date",
"date": "={{ $now }}"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "abf54eea-476e-4ed3-b9a3-5cb902d49c4e",
"name": "Check Leads1",
"type": "n8n-nodes-base.notion",
"position": [
2256,
2716
],
"parameters": {
"filters": {
"conditions": [
{
"key": "Phone|phone_number",
"condition": "is_not_empty"
}
]
},
"options": {},
"resource": "databasePage",
"operation": "getAll",
"returnAll": true,
"databaseId": {
"__rl": true,
"mode": "list",
"value": "YOUR_NOTION_DATABASE_ID",
"cachedResultUrl": "",
"cachedResultName": "YOUR_DATABASE_NAME"
},
"filterType": "manual"
},
"typeVersion": 2.2
},
{
"id": "7c93f297-1a9a-467c-82b2-c86d3e01cb91",
"name": "Bot Status1",
"type": "n8n-nodes-base.if",
"position": [
2704,
2716
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "80a59ea4-0d28-4d54-a57f-9094f7b3dbc4",
"operator": {
"type": "string",
"operation": "notEquals"
},
"leftValue": "={{ $json.bot_status }}",
"rightValue": "Paused"
}
]
}
},
"typeVersion": 2.3
},
{
"id": "80354c1e-c740-40d1-bf2f-b8a00c11f2d0",
"name": "Normalize Phone and Look Match1",
"type": "n8n-nodes-base.code",
"position": [
2480,
2716
],
"parameters": {
"jsCode": "// ============================================\n// NORMALIZE AND LOOK MATCH \u2014 Get Lead Early\n// Reads n8n Notion node output (flattened: property_*)\n// ============================================\n\nconst webhookPhone = $('Detect Message Type1').first().json.phone;\nconst notionLeads = $input.all();\n\nconst messageData = {\n phone: $('Detect Message Type1').first().json.phone,\n sender_name: $('Detect Message Type1').first().json.sender_name,\n message_type: $('Detect Message Type1').first().json.message_type,\n instance_name: $('Detect Message Type1').first().json.instance_name,\n text: $('Sentiment Analysis1').first().json.text\n || $('Detect Message Type1').first().json.text\n || ''\n};\n\nconst normalize = (p) => {\n let n = String(p || '').replace(/[^0-9]/g, '');\n // Add country-specific phone normalization here if needed\n return n;\n};\n\nconst normalizedWebhook = normalize(webhookPhone);\n\nconst match = notionLeads.find(item => {\n const notionPhone = normalize(item.json.property_phone || '');\n return notionPhone.length >= 10 && notionPhone === normalizedWebhook;\n});\n\nif (match) {\n return [{\n json: {\n ...messageData,\n is_known_lead: true,\n matched: true,\n page_id: match.json.id || '',\n bot_status: match.json.property_wa_chat_bot_status || 'Active',\n lead_status: match.json.property_status || '',\n personalization_note: match.json.property_ai_personalization_note || '',\n pain_point: match.json.property_ai_notes || '',\n }\n }];\n} else {\n return [{\n json: {\n ...messageData,\n is_known_lead: false,\n matched: false,\n page_id: '',\n bot_status: 'Active',\n }\n }];\n}"
},
"typeVersion": 2
},
{
"id": "4d731b71-884a-402b-b525-6a852fbbc12e",
"name": "Respond OK (skip)4",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
2096,
2352
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={{ { status: 'ok', reason: $('Detect Message Type1').item.json.reason } }}"
},
"typeVersion": 1.1
},
{
"id": "5b9408ba-e17f-47f1-8ab3-ab16a7b1db58",
"name": "Respond OK (skip)5",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
2880,
2864
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={{ { status: 'ok', reason: $('Detect Message Type1').item.json.reason } }}"
},
"typeVersion": 1.1
},
{
"id": "4d658378-4f36-4a08-b00b-7600c5cd092f",
"name": "Pause ChatBot1",
"type": "n8n-nodes-base.notion",
"position": [
6256,
2496
],
"parameters": {
"pageId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Normalize and Look Match1').first().json.page_id }}"
},
"options": {},
"resource": "databasePage",
"operation": "update",
"propertiesUi": {
"propertyValues": [
{
"key": "WA ChatBot Status|select",
"selectValue": "=Paused"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "1dc8ceee-ab12-416f-8a04-efe793930a6a",
"name": "No Operation, do nothing3",
"type": "n8n-nodes-base.noOp",
"position": [
3056,
2864
],
"parameters": {},
"typeVersion": 1
},
{
"id": "7c995f97-9eb1-40c1-9387-1c518985f2e1",
"name": "No Operation, do nothing4",
"type": "n8n-nodes-base.noOp",
"position": [
1456,
2320
],
"parameters": {},
"typeVersion": 1
},
{
"id": "910d569a-fbbf-40d7-b2f8-b61b7f129bbd",
"name": "No Operation, do nothing5",
"type": "n8n-nodes-base.noOp",
"position": [
2272,
2352
],
"parameters": {},
"typeVersion": 1
}
],
"connections": {
"Wait1": {
"main": [
[
{
"node": "Generate Response1",
"type": "main",
"index": 0
}
]
]
},
"Is Voice?1": {
"main": [
[
{
"node": "Prepare Audio Binary1",
"type": "main",
"index": 0
}
],
[
{
"node": "Sentiment Analysis1",
"type": "main",
"index": 0
}
]
]
},
"Read FAQs1": {
"main": [
[
{
"node": "Build Context for AI Agent1",
"type": "main",
"index": 0
}
]
]
},
"Bot Status1": {
"main": [
[
{
"node": "Information Extractor1",
"type": "main",
"index": 0
}
],
[
{
"node": "Respond OK (skip)5",
"type": "main",
"index": 0
}
]
]
},
"Skip Event1": {
"main": [
[
{
"node": "Respond OK (skip)3",
"type": "main",
"index": 0
}
],
[
{
"node": "Is Voice?1",
"type": "main",
"index": 0
}
]
]
},
"Check Leads1": {
"main": [
[
{
"node": "Normalize Phone and Look Match1",
"type": "main",
"index": 0
}
]
]
},
"Phone Match1": {
"main": [
[
{
"node": "Update Lead Status1",
"type": "main",
"index": 0
}
],
[
{
"node": "Create a New Lead1",
"type": "main",
"index": 0
}
]
]
},
"Alert Owner?1": {
"main": [
[
{
"node": "Alert Owner (Telegram)1",
"type": "main",
"index": 0
}
],
[
{
"node": "Phone Match1",
"type": "main",
"index": 0
}
]
]
},
"Pause ChatBot1": {
"main": [
[
{
"node": "Phone Match1",
"type": "main",
"index": 0
}
]
]
},
"Read Products1": {
"main": [
[
{
"node": "Read FAQs1",
"type": "main",
"index": 0
}
]
]
},
"Format Cleaner1": {
"main": [
[
{
"node": "Send WhatsApp Reply (Evolution)1",
"type": "main",
"index": 0
}
]
]
},
"Format for Log1": {
"main": [
[
{
"node": "Log Conversation1",
"type": "main",
"index": 0
}
]
]
},
"Log Conversation1": {
"main": [
[
{
"node": "Alert Owner?1",
"type": "main",
"index": 0
}
]
]
},
"Transcribe Audio1": {
"main": [
[
{
"node": "Sentiment Analysis1",
"type": "main",
"index": 0
}
]
]
},
"Create a New Lead1": {
"main": [
[
{
"node": "Respond 1",
"type": "main",
"index": 0
}
]
]
},
"Evolution Webhook1": {
"main": [
[
{
"node": "Detect Message Type1",
"type": "main",
"index": 0
}
]
]
},
"Generate Response1": {
"main": [
[
{
"node": "Format Cleaner1",
"type": "main",
"index": 0
}
]
]
},
"Respond OK (skip)3": {
"main": [
[
{
"node": "No Operation, do nothing4",
"type": "main",
"index": 0
}
]
]
},
"Respond OK (skip)4": {
"main": [
[
{
"node": "No Operation, do nothing5",
"type": "main",
"index": 0
}
]
]
},
"Respond OK (skip)5": {
"main": [
[
{
"node": "No Operation, do nothing3",
"type": "main",
"index": 0
}
]
]
},
"Read Business Info1": {
"main": [
[
{
"node": "Read Products1",
"type": "main",
"index": 0
}
]
]
},
"Sentiment Analysis1": {
"main": [
[
{
"node": "Respond OK (skip)4",
"type": "main",
"index": 0
}
],
[
{
"node": "Check Leads1",
"type": "main",
"index": 0
}
]
]
},
"Update Lead Status1": {
"main": [
[
{
"node": "Respond 1",
"type": "main",
"index": 0
}
]
]
},
"Conversation Memory1": {
"ai_memory": [
[
{
"node": "Generate Response1",
"type": "ai_memory",
"index": 0
}
]
]
},
"Detect Message Type1": {
"main": [
[
{
"node": "Skip Event1",
"type": "main",
"index": 0
}
]
]
},
"Anthropic Chat Model1": {
"ai_languageModel": [
[
{
"node": "Sentiment Analysis1",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Prepare Audio Binary1": {
"main": [
[
{
"node": "Transcribe Audio1",
"type": "main",
"index": 0
}
]
]
},
"Information Extractor1": {
"main": [
[
{
"node": "Read Business Info1",
"type": "main",
"index": 0
}
]
]
},
"Alert Owner (Telegram)1": {
"main": [
[
{
"node": "Pause ChatBot1",
"type": "main",
"index": 0
}
]
]
},
"Anthropic Model (Response)1": {
"ai_languageModel": [
[
{
"node": "Generate Response1",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Build Context for AI Agent1": {
"main": [
[
{
"node": "Wait1",
"type": "main",
"index": 0
}
]
]
},
"Anthropic Model (Extractor)1": {
"ai_languageModel": [
[
{
"node": "Information Extractor1",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Normalize Phone and Look Match1": {
"main": [
[
{
"node": "Bot Status1",
"type": "main",
"index": 0
}
]
]
},
"Send WhatsApp Reply (Evolution)1": {
"main": [
[
{
"node": "Format for Log1",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow turns your WhatsApp Business number into a 24/7 AI-powered customer assistant — without any third-party chatbot platform. It receives incoming WhatsApp messages via Evolution API, understands the customer's intent, generates a conversational response using Claude…
Source: https://n8n.io/workflows/15491/ — 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.
Universal Expense tracker. Uses telegram, httpRequest, openAi, googleSheets. Webhook trigger; 33 nodes.
Are you drowning in daily operational chaos, desperately trying to juggle sales, projects, content, and client communication? Imagine an AI brain that handles it all, freeing you to lead your business
This n8n workflow orchestrates a powerful suite of AI Agents and automations to manage and optimize various aspects of an e-commerce operation, particularly for platforms like Shopify. It leverages La
Resume Screening & Behavioral Interviews with Gemini, Elevenlabs, & Notion ATS copy. Uses outputParserStructured, chainLlm, googleDrive, stickyNote. Webhook trigger; 67 nodes.
Candidate Engagement | Resume Screening | AI Voice Interviews | Applicant Insights