AutomationFlowsAI & RAG › Qualify Real Estate Whatsapp Leads with Groq, Google Sheets, and Twilio

Qualify Real Estate Whatsapp Leads with Groq, Google Sheets, and Twilio

ByChijioke Ogbonna @cjaey5 on n8n.io

This workflow captures real estate leads from a Lovable webhook, stores them in Google Sheets, qualifies them via a Groq-powered AI agent, and uses Twilio WhatsApp messaging to route HOT/WARM/COLD leads into agent assignment, property matching, and nurture follow-ups. Receives a…

Webhook trigger★★★★★ complexityAI-powered45 nodesGoogle SheetsTwilioAgentGroq ChatMemory Buffer Window
AI & RAG Trigger: Webhook Nodes: 45 Complexity: ★★★★★ AI nodes: yes Added:

This workflow corresponds to n8n.io template #17941 — 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 →

Download .json
{
  "id": "84FvMrAo0y5CM1x8",
  "name": "Real Estate Lead Automation \u2014 AI Agent + Groq + Twilio",
  "tags": [],
  "nodes": [
    {
      "id": "7fe3e9e1-2557-4a86-83b4-f42474d80493",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        0
      ],
      "parameters": {
        "width": 480,
        "height": 896,
        "content": "## Real Estate Lead Automation \u2014 AI Agent + Groq + Twilio\n\n### How it works\n\n1. The workflow is triggered by a lovable incoming webhook.\n2. It responds to the webhook and saves the lead to Google Sheets.\n3. It sends a greeting message via WhatsApp and engages an AI agent.\n4. The AI agent extracts the reply and checks if the lead is qualified.\n5. If qualified, it sends an AI reply and updates the lead score.\n6. It then switches to different paths based on the lead's status.\n7. For HOT leads, it assigns an agent and notifies them.\n8. For WARM leads, it sends a follow-up reminder after a wait period.\n9. For COLD leads, it sends a weekly nurture message.\n\n### Setup steps\n\n- - [ ] Set up the lovable incoming webhook\n- - [ ] Configure the Google Sheets nodes\n- - [ ] Set up the AI agent and its dependencies\n- - [ ] Configure the Twilio nodes for sending messages\n\n### Customization\n\nCustomize the AI agent's responses and the nurture messages to fit your specific use case."
      },
      "typeVersion": 1
    },
    {
      "id": "d716fe4a-3668-4214-839c-9804357fe1fe",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        560,
        304
      ],
      "parameters": {
        "color": 7,
        "height": 272,
        "content": "## Webhook Trigger\n\nInitial trigger lovable"
      },
      "typeVersion": 1
    },
    {
      "id": "598bacb9-72fb-43f1-9479-a78ef6434e2d",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        832,
        160
      ],
      "parameters": {
        "color": 7,
        "height": 512,
        "content": "## Respond and Save\n\nRespond to webhook and save lead"
      },
      "typeVersion": 1
    },
    {
      "id": "ac54880e-537c-434e-9ab4-67ebc79eb982",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1104,
        304
      ],
      "parameters": {
        "color": 7,
        "width": 560,
        "height": 512,
        "content": "## Send Greeting and AI\n\nSend greeting and engage AI"
      },
      "typeVersion": 1
    },
    {
      "id": "c904356e-72aa-4e27-a4a8-ee70d94cf231",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1696,
        304
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 272,
        "content": "## Extract and Check\n\nExtract reply and check qualification"
      },
      "typeVersion": 1
    },
    {
      "id": "ee50a81c-a910-4369-9b80-6ddf0ae9f233",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2160,
        96
      ],
      "parameters": {
        "color": 7,
        "height": 640,
        "content": "## Send AI Reply and Update\n\nSend AI reply and update lead score"
      },
      "typeVersion": 1
    },
    {
      "id": "263101be-e6af-4c3f-8134-11355f73c8e2",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2432,
        0
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 400,
        "content": "## Switch and Get Agents\n\nSwitch and get agents sheet"
      },
      "typeVersion": 1
    },
    {
      "id": "385e8bf8-b384-4f46-b4fd-182962493a4a",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2944,
        0
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 272,
        "content": "## Assign Agent and Notify\n\nAssign agent and notify"
      },
      "typeVersion": 1
    },
    {
      "id": "49f5b848-0f52-4a75-86f9-61a7d64317e2",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3408,
        0
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 272,
        "content": "## Wait and Follow-up\n\nWait and send follow-up reminder"
      },
      "typeVersion": 1
    },
    {
      "id": "aaeed3bb-51a3-4192-a94f-2ae144406347",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2464,
        432
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 272,
        "content": "## Get Properties and Match\n\nGet properties sheet and match properties"
      },
      "typeVersion": 1
    },
    {
      "id": "f94cb992-eeef-4473-b192-539f570b68f6",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2944,
        304
      ],
      "parameters": {
        "color": 7,
        "width": 1152,
        "height": 272,
        "content": "## Send Intro and Properties\n\nSend intro message and properties"
      },
      "typeVersion": 1
    },
    {
      "id": "132af0f8-54b2-4d0f-9879-4de2cf7293d0",
      "name": "Sticky Note11",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        560,
        848
      ],
      "parameters": {
        "color": 7,
        "width": 2576,
        "height": 576,
        "content": "## WARM and COLD Nurture\n\nWARM day 1 and COLD weekly nurture"
      },
      "typeVersion": 1
    },
    {
      "id": "3629e5cf-7e16-4310-8976-16050c3c79d3",
      "name": "Sticky Note12",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4144,
        160
      ],
      "parameters": {
        "color": 7,
        "height": 272,
        "content": "## Update Pipeline\n\nUpdate pipeline stage"
      },
      "typeVersion": 1
    },
    {
      "id": "53b5fd60-f21f-4c5d-8f18-1fb466b9db59",
      "name": "Respond OK",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        880,
        288
      ],
      "parameters": {
        "options": {},
        "respondWith": "text",
        "responseBody": "OK"
      },
      "typeVersion": 1
    },
    {
      "id": "039b22c6-30f4-4aa1-8761-b552ff213665",
      "name": "Save to Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        880,
        496
      ],
      "parameters": {
        "columns": {
          "value": {
            "Name": "={{ $json.ProfileName || $json.name || 'Unknown' }}",
            "Email": "=",
            "Phone": "={{ $json.From || $json.from || '' }}",
            "Score": "=Unscored",
            "Intent": "=",
            "Source": "=WhatsApp",
            "Status": "=New",
            "Lead ID": "={{ $now.toMillis() }}",
            "Location": "=",
            "Timeline": "=",
            "Timestamp": "={{ $now.toISO() }}",
            "Budget (\u20a6)": "=",
            "Assigned Agent": "=",
            "Close Probability": "=",
            "Expected Value (\u20a6)": "="
          },
          "schema": [
            {
              "id": "Lead ID",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Lead ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Phone",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Phone",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Email",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Budget (\u20a6)",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Budget (\u20a6)",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Location",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Location",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Source",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Source",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Score",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Score",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Intent",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Intent",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Timeline",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Timeline",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Assigned Agent",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Assigned Agent",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Close Probability",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Close Probability",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Expected Value (\u20a6)",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Expected Value (\u20a6)",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Leads"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "1727UUNDuHNqrDzCHXP65WZOeNcuqKj6o0vk3Gw_Io2c"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "1301f248-046d-46eb-95bb-75a949195d53",
      "name": "Send Greeting",
      "type": "n8n-nodes-base.twilio",
      "position": [
        1152,
        496
      ],
      "parameters": {
        "options": {},
        "resource": "message"
      },
      "typeVersion": 1
    },
    {
      "id": "0f85ab9e-524c-4594-a107-506570803f84",
      "name": "AI Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1360,
        416
      ],
      "parameters": {
        "text": "={{ $json.Body || $json.body || '' }}",
        "options": {
          "systemMessage": "You are Aria, a warm and professional real estate sales assistant for PrimeRealty Nigeria.\n\nYour goal is to qualify leads by naturally collecting:\n1. Intent \u2014 are they buying, renting, or investing?\n2. Budget \u2014 in Naira (ask if not given)\n3. Preferred location \u2014 which city or area in Nigeria?\n4. Timeline \u2014 when do they want to move or buy?\n\nRules:\n- Ask ONE question at a time, never multiple\n- Sound human and conversational, never robotic\n- Keep all replies under 80 words\n- Once you have collected all 4 answers, append this JSON block on a new line at the very end of your reply:\n{\"score\":\"HOT\",\"intent\":\"buy\",\"budget\":\"50000000\",\"location\":\"Lekki\",\"timeline\":\"30 days\"}\n- Score HOT if timeline is within 30 days, WARM if 1-3 months, COLD if just browsing\n- Never reveal you are an AI unless directly asked\n- Always be encouraging and positive about their property search"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "b95a4652-aa8a-4360-a526-8f22a22a7ba1",
      "name": "Groq Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatGroq",
      "position": [
        1392,
        624
      ],
      "parameters": {
        "options": {
          "temperature": 0.7
        }
      },
      "typeVersion": 1
    },
    {
      "id": "f06a5ee3-1624-4ef2-b063-e8a7b819f2e8",
      "name": "Conv Memory",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "position": [
        1520,
        672
      ],
      "parameters": {
        "sessionKey": "={{ $json.From || $json.from || 'default' }}",
        "contextWindowLength": 10
      },
      "typeVersion": 1
    },
    {
      "id": "22341e0c-6587-4e1b-8015-37b40ef61476",
      "name": "Extract Reply",
      "type": "n8n-nodes-base.code",
      "position": [
        1744,
        416
      ],
      "parameters": {
        "jsCode": "const agentOut = $input.first().json;\nconst reply = agentOut.output || agentOut.text || '';\nconst from = $('When lead submit lovable form').first().json.From || \n             $('When lead submit lovable form').first().json.from || '';\n\n// Check if agent included the qualification JSON block\nconst jsonMatch = reply.match(/\\{\\s*\"score\"[^}]*\\}/s);\nlet qualified = false;\nlet scoreData = {};\n\nif (jsonMatch) {\n  try {\n    scoreData = JSON.parse(jsonMatch[0]);\n    qualified = true;\n  } catch(e) { qualified = false; }\n}\n\nconst cleanMsg = reply.replace(/\\{\\s*\"score\"[^}]*\\}/s, '').trim();\n\nreturn [{ json: {\n  message: cleanMsg,\n  qualified: qualified,\n  recipient: from,\n  score: scoreData.score || 'COLD',\n  intent: scoreData.intent || 'unknown',\n  budget: scoreData.budget || '',\n  location: scoreData.location || '',\n  timeline: scoreData.timeline || '',\n  rawPhone: from\n}}];"
      },
      "typeVersion": 2
    },
    {
      "id": "36a7798f-88f3-4abc-9217-d9806d773691",
      "name": "If Qualified",
      "type": "n8n-nodes-base.if",
      "position": [
        1984,
        416
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "0d48c48b-e59c-4b9b-aa6e-6b2b284410af",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.qualified }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "44c56352-07a1-4e8e-8396-a87bec926f14",
      "name": "Send AI Reply",
      "type": "n8n-nodes-base.twilio",
      "position": [
        2208,
        576
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "f628e2cc-8c54-41e2-8115-3061405bcd7e",
      "name": "Update Lead",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2208,
        272
      ],
      "parameters": {
        "columns": {
          "value": {
            "Phone": "={{ $json.rawPhone }}",
            "Score": "={{ $json.score }}",
            "Intent": "={{ $json.intent }}",
            "Status": "=Qualified",
            "Location": "={{ $json.location }}",
            "Timeline": "={{ $json.timeline }}",
            "row_number": 0,
            "Budget (\u20a6)": "={{ $json.budget }}",
            "Close Probability": "={{ $json.score === 'HOT' ? '80%' : $json.score === 'WARM' ? '45%' : '15%' }}",
            "Expected Value (\u20a6)": "={{ $json.budget }}"
          },
          "schema": [
            {
              "id": "Lead ID",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Lead ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Name",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Phone",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Phone",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Email",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Budget (\u20a6)",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Budget (\u20a6)",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Location",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Location",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Source",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Source",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Score",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Score",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Intent",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Intent",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Timeline",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Timeline",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Assigned Agent",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Assigned Agent",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Close Probability",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Close Probability",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Expected Value (\u20a6)",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Expected Value (\u20a6)",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Timestamp",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": false,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "Lead ID"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Leads"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "1727UUNDuHNqrDzCHXP65WZOeNcuqKj6o0vk3Gw_Io2c"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "f9415d60-efd3-410c-acbb-4f44a11d7038",
      "name": "Get Agents",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2768,
        112
      ],
      "parameters": {
        "operation": "getAll",
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "1727UUNDuHNqrDzCHXP65WZOeNcuqKj6o0vk3Gw_Io2c"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "560b2900-6652-4e68-8442-f59f7be21607",
      "name": "Assign Agent",
      "type": "n8n-nodes-base.code",
      "position": [
        2992,
        112
      ],
      "parameters": {
        "jsCode": "const agents = $input.all().map(a => a.json);\nconst lead = $('Extract Reply').first().json;\n\nconst available = agents.filter(a => \n  (a.Availability || '').toLowerCase() === 'available'\n);\n\nif (!available.length) {\n  return [{ json: { ...lead, assignedAgent: 'Unassigned', agentPhone: '' }}];\n}\n\navailable.sort((a, b) => \n  Number(a['Lead Count'] || 0) - Number(b['Lead Count'] || 0)\n);\n\nconst agent = available[0];\nreturn [{ json: {\n  ...lead,\n  assignedAgent: agent['Agent Name'] || '',\n  agentPhone: (agent['Phone'] || '').replace(/\\D/g,'').replace(/^0/,'+234'),\n  agentRow: agent._rowNumber || 2\n}}];"
      },
      "typeVersion": 2
    },
    {
      "id": "62e6ccaf-2194-4651-ac7b-89801cdcd0e4",
      "name": "Notify Agent",
      "type": "n8n-nodes-base.twilio",
      "position": [
        3232,
        112
      ],
      "parameters": {
        "options": {},
        "resource": "message"
      },
      "typeVersion": 1
    },
    {
      "id": "37fa1dbe-9608-411e-94a5-b8492f9765a7",
      "name": "Get Props",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2512,
        544
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1761263887,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1727UUNDuHNqrDzCHXP65WZOeNcuqKj6o0vk3Gw_Io2c/edit#gid=1761263887",
          "cachedResultName": "Properties"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "1727UUNDuHNqrDzCHXP65WZOeNcuqKj6o0vk3Gw_Io2c"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "b7660b09-c3f1-4c5b-9ae3-b3011a9b3fa4",
      "name": "Match Props",
      "type": "n8n-nodes-base.code",
      "position": [
        2752,
        544
      ],
      "parameters": {
        "jsCode": "const props = $input.all().map(p => p.json);\nconst lead = $('Extract Reply').first().json;\nconst budget = Number((lead.budget || '0').toString().replace(/[^0-9]/g, ''));\nconst loc = (lead.location || '').toLowerCase();\n\n// Match using exact column names from Prime-Reality Google Sheet\nlet matches = props.filter(p => {\n  const price = Number((p['Price (\u20a6)'] || p.Price || 0).toString().replace(/[^0-9]/g, ''));\n  const pLoc = (p.Location || '').toLowerCase();\n  const locMatch = !loc || pLoc.includes(loc) || loc.includes(pLoc.split(',')[0].trim());\n  const budgetMatch = !budget || price <= budget * 1.25; // 25% over budget tolerance\n  return locMatch && budgetMatch;\n}).slice(0, 3);\n\n// Fallback: top 3 if no match\nif (!matches.length) matches = props.slice(0, 3);\n\nconst propertyCards = matches.map((p, i) => {\n  const price = Number((p['Price (\u20a6)'] || p.Price || 0).toString().replace(/[^0-9]/g, ''));\n  return {\n    caption: `${i+1}. *${p.Name || 'Property'}*\\n` +\n             `\ud83d\udccd ${p.Location}\\n` +\n             `\ud83d\udcb0 \u20a6${price.toLocaleString()}\\n` +\n             `\ud83c\udfe0 ${p.Type} \u2022 ${p.Bedrooms} Beds\\n` +\n             `\u2728 ${(p.Features || '').split(',').slice(0,3).join(', ')}\\n` +\n             `\ud83d\udd17 ${p['WhatsApp Link'] || p.Link || 'Contact us'}`,\n    imageUrl: p['Image URL'] || ''\n  };\n});\n\nconst introMsg = '\ud83c\udfd8\ufe0f *Here are properties matched for you:*\\n\\nSending you each one with photos now \ud83d\udc47';\nconst outroMsg = '\ud83d\udcac Interested in any? Reply with the property number e.g. *YES 2* to book a viewing \ud83d\udcc5\\n\\nOr reply *MORE* to see other options!';\n\nreturn [{ json: {\n  ...lead,\n  introMsg, outroMsg,\n  card1Caption: propertyCards[0]?.caption || '',\n  card1Image:   propertyCards[0]?.imageUrl || '',\n  card2Caption: propertyCards[1]?.caption || '',\n  card2Image:   propertyCards[1]?.imageUrl || '',\n  card3Caption: propertyCards[2]?.caption || '',\n  card3Image:   propertyCards[2]?.imageUrl || '',\n}}];"
      },
      "typeVersion": 2
    },
    {
      "id": "3045101b-cf70-426c-abe7-0e6ce8b6b174",
      "name": "Send Intro",
      "type": "n8n-nodes-base.twilio",
      "position": [
        2992,
        416
      ],
      "parameters": {
        "options": {},
        "resource": "message"
      },
      "typeVersion": 1
    },
    {
      "id": "07fc9c90-5aa3-4b84-b70d-76923bb99e46",
      "name": "Wait 1 Hour",
      "type": "n8n-nodes-base.wait",
      "position": [
        3456,
        112
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "1e405f56-5696-4a7a-8ada-d7b59cd47695",
      "name": "HOT Reminder",
      "type": "n8n-nodes-base.twilio",
      "position": [
        3696,
        112
      ],
      "parameters": {
        "options": {},
        "resource": "message"
      },
      "typeVersion": 1
    },
    {
      "id": "c05fb457-9be4-440f-be76-3c2e25ba9b1e",
      "name": "WARM Day1",
      "type": "n8n-nodes-base.twilio",
      "position": [
        2512,
        960
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "700a53b7-45ec-4807-9ae2-3178ff438d74",
      "name": "Wait 2 Days",
      "type": "n8n-nodes-base.wait",
      "position": [
        2752,
        960
      ],
      "parameters": {
        "unit": "days",
        "amount": 2
      },
      "typeVersion": 1
    },
    {
      "id": "f0263c29-4c56-4853-9cd7-4c16ce9ecf21",
      "name": "WARM Day5",
      "type": "n8n-nodes-base.twilio",
      "position": [
        2992,
        960
      ],
      "parameters": {
        "options": {},
        "resource": "message"
      },
      "typeVersion": 1
    },
    {
      "id": "56b07ba2-00f8-4cd6-a03a-24b33ff280ef",
      "name": "COLD Nurture",
      "type": "n8n-nodes-base.twilio",
      "position": [
        2512,
        1168
      ],
      "parameters": {
        "options": {},
        "resource": "message"
      },
      "typeVersion": 1
    },
    {
      "id": "47125dfb-220e-4df6-8030-ecf21b44ceb1",
      "name": "Reengage",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        608,
        1264
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "daysInterval": 30
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "deda8f2d-eb6b-4edc-beca-b0154bc47e4c",
      "name": "Find Inactives",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        864,
        1264
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 2098460604,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1727UUNDuHNqrDzCHXP65WZOeNcuqKj6o0vk3Gw_Io2c/edit#gid=2098460604",
          "cachedResultName": "Leads"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "1727UUNDuHNqrDzCHXP65WZOeNcuqKj6o0vk3Gw_Io2c"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "b4b3603a-d16b-4bd2-8b23-c9d5f19c80b7",
      "name": "Reengage WhatsApp",
      "type": "n8n-nodes-base.twilio",
      "position": [
        1136,
        1264
      ],
      "parameters": {
        "options": {},
        "resource": "message"
      },
      "typeVersion": 1
    },
    {
      "id": "f3fe84ca-e88e-487d-83eb-b9766cc517a8",
      "name": "Update Stage",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        4192,
        272
      ],
      "parameters": {
        "columns": {
          "value": {
            "Phone": "={{ $json.rawPhone }}",
            "Status": "=Viewing Scheduled",
            "Expected Value (\u20a6)": "={{ $json.budget }}"
          },
          "mappingMode": "defineBelow"
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Leads"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "1727UUNDuHNqrDzCHXP65WZOeNcuqKj6o0vk3Gw_Io2c"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "7e072066-3970-4526-8c84-9cd3eea05ca5",
      "name": "Send Prop1",
      "type": "n8n-nodes-base.twilio",
      "position": [
        3264,
        416
      ],
      "parameters": {
        "options": {},
        "resource": "message"
      },
      "typeVersion": 1
    },
    {
      "id": "0ab242a4-5048-4fc2-bb15-01766af0c1dd",
      "name": "Send Prop2",
      "type": "n8n-nodes-base.twilio",
      "position": [
        3488,
        416
      ],
      "parameters": {
        "options": {},
        "resource": "message"
      },
      "typeVersion": 1
    },
    {
      "id": "844d2da3-fb0a-466f-987c-b6fb56315ccd",
      "name": "Send Prop3",
      "type": "n8n-nodes-base.twilio",
      "position": [
        3696,
        416
      ],
      "parameters": {
        "options": {},
        "resource": "message"
      },
      "typeVersion": 1
    },
    {
      "id": "b425c247-9f68-4e7e-bb90-3e1748ee5b17",
      "name": "Send Booking",
      "type": "n8n-nodes-base.twilio",
      "position": [
        3952,
        416
      ],
      "parameters": {
        "options": {},
        "resource": "message"
      },
      "typeVersion": 1
    },
    {
      "id": "68ac1164-ffd5-4dda-a60d-e78a42e86bb9",
      "name": "Route Leads",
      "type": "n8n-nodes-base.switch",
      "position": [
        2480,
        208
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "HOT",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "acb71367-71cf-4263-98b6-a79dad7fb3d1",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.score }}",
                    "rightValue": "HOT"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "WARM",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "e37e90e0-ef6b-4d73-a906-aec31137065e",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.score }}",
                    "rightValue": "WARM"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "COLD",
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "0e0e0aab-68f4-4226-8b4c-5615a71300e1",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.score }}",
                    "rightValue": "COLD"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3.4
    },
    {
      "id": "e4894361-45e8-42bb-a3a2-423599e8e82e",
      "name": "When lead submit lovable form",
      "type": "n8n-nodes-base.webhook",
      "position": [
        608,
        416
      ],
      "parameters": {
        "path": "real-estate-lead",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "10d1553b-3f30-4c85-8390-b342ad98fab0",
  "nodeGroups": [],
  "connections": {
    "AI Agent": {
      "main": [
        [
          {
            "node": "Extract Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Reengage": {
      "main": [
        [
          {
            "node": "Find Inactives",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Props": {
      "main": [
        [
          {
            "node": "Match Props",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "WARM Day1": {
      "main": [
        [
          {
            "node": "Wait 2 Days",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Agents": {
      "main": [
        [
          {
            "node": "Assign Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Groq Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Send Intro": {
      "main": [
        [
          {
            "node": "Send Prop1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Prop1": {
      "main": [
        [
          {
            "node": "Send Prop2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Prop2": {
      "main": [
        [
          {
            "node": "Send Prop3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Prop3": {
      "main": [
        [
          {
            "node": "Send Booking",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Conv Memory": {
      "ai_memory": [
        [
          {
            "node": "AI Agent",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Match Props": {
      "main": [
        [
          {
            "node": "Send Intro",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route Leads": {
      "main": [
        [
          {
            "node": "Get Agents",
            "type": "main",
            "index": 0
          },
          {
            "node": "Get Props",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "WARM Day1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "COLD Nurture",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Lead": {
      "main": [
        [
          {
            "node": "Route Leads",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait 1 Hour": {
      "main": [
        [
          {
            "node": "HOT Reminder",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait 2 Days": {
      "main": [
        [
          {
            "node": "WARM Day5",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Assign Agent": {
      "main": [
        [
          {
            "node": "Notify Agent",
            "type": "main",
            "index": 0
          },
          {
            "node": "Wait 1 Hour",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Qualified": {
      "main": [
        [
          {
            "node": "Update Lead",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send AI Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Notify Agent": {
      "main": [
        [
          {
            "node": "Update Stage",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Booking": {
      "main": [
        [
          {
            "node": "Update Stage",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Reply": {
      "main": [
        [
          {
            "node": "If Qualified",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Greeting": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Find Inactives": {
      "main": [
        [
          {
            "node": "Reengage WhatsApp",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save to Sheets": {
      "main": [
        [
          {
            "node": "Send Greeting",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When lead submit lovable form": {
      "main": [
        [
          {
            "node": "Respond OK",
            "type": "main",
            "index": 0
          },
          {
            "node": "Save to Sheets",
            "type": "main",
            "index": 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

This workflow captures real estate leads from a Lovable webhook, stores them in Google Sheets, qualifies them via a Groq-powered AI agent, and uses Twilio WhatsApp messaging to route HOT/WARM/COLD leads into agent assignment, property matching, and nurture follow-ups. Receives a…

Source: https://n8n.io/workflows/17941/ — 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

case 2 - curso n8n. Uses agent, lmChatGroq, memoryBufferWindow, toolCalculator. Webhook trigger; 15 nodes.

Agent, Groq Chat, Memory Buffer Window +5
AI & RAG

VEP WAPP. Uses openAi, lmChatOpenAi, toolCalculator, agent. Webhook trigger; 100 nodes.

OpenAI, OpenAI Chat, Tool Calculator +7
AI & RAG

BoomerBobBot.TP. Uses agent, telegramTrigger, telegram, memoryBufferWindow. Event-driven trigger; 95 nodes.

Agent, Telegram Trigger, Telegram +10
AI & RAG

AI Customer Service Automation - Portfolio. Uses googleSheets, httpRequest, agent, memoryBufferWindow. Webhook trigger; 91 nodes.

Google Sheets, HTTP Request, Agent +9
AI & RAG

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

Google Sheets, HTTP Request, Slack +10