AutomationFlowsAI & RAG › Real Estate Chatbot with AI Property Matching and Automated Calendar Scheduling

Real Estate Chatbot with AI Property Matching and Automated Calendar Scheduling

ByGenzi @genzi12 on n8n.io

A comprehensive real estate chatbot automation system that handles customer inquiries, property searches, and appointment scheduling through intelligent conversation flows and email processing.

Webhook trigger★★★★★ complexityAI-powered33 nodesAgentMemory Postgres ChatPostgresOpenAI ChatTool Serp ApiGoogle Calendar ToolGmail ToolGmail Trigger
AI & RAG Trigger: Webhook Nodes: 33 Complexity: ★★★★★ AI nodes: yes Added:

This workflow corresponds to n8n.io template #7250 — we link there as the canonical source.

This workflow follows the Agent → Gmail Tool 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": "5AVHQCf6dHelWBYq",
  "name": "Prop_workflow",
  "tags": [],
  "nodes": [
    {
      "id": "d1147020-69b9-4f81-be58-8e37e78e5832",
      "name": "LLM conversation",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        -240,
        860
      ],
      "parameters": {
        "text": "={{ $json.originalMessage }}",
        "options": {
          "systemMessage": "=You are a real estate assistant named PropPanda. You MUST follow this EXACT step-by-step workflow with intelligent information extraction:\n\n## CONTENT FILTER (FIRST PRIORITY)\n\nIMMEDIATE CHECK: Before any other processing, check if the user's message is related to real estate services:\n\nALLOWED TOPICS:\n- Property rental/purchase inquiries (HDB, condo, apartment)\n- Location preferences and property searches\n- Budget discussions for properties\n- Viewing appointments and property tours\n- Nearby amenities (MRT, schools, restaurants)\n- Human agent requests for property matters\n\nFORBIDDEN TOPICS - END CONVERSATION GRACEFULLY:\n- Adult/sexual content, escort services\n- Non-property services (food delivery, transport, medical, technical support)\n- Spam, advertisements, investment schemes\n- Personal conversations unrelated to property\n- Any illegal or inappropriate requests\n\nIF FORBIDDEN TOPIC DETECTED:\nRespond: \"I'm sorry, but I can only assist with property-related inquiries such as finding HDB flats, condos, or apartments for rent or purchase. If you have any property questions, I'd be happy to help! Otherwise, have a great day.\"\nSTOP ALL PROCESSING AND WAIT FOR NEW MESSAGE\n\n---\n\n## INFORMATION EXTRACTION SYSTEM\n\nALWAYS FIRST: Before asking any questions, scan the user's message for ANY of the following information and save what you find:\n\nPersonal Information Keywords:\n- Name: \"I am [name]\", \"my name is [name]\", \"name is [name]\", or any clear name introduction\n- Phone: Phone numbers (8-12 digits, with or without country codes, +65, etc.)\n- Email: Email addresses (any text containing @ symbol with domain)\n\nProperty Requirements Keywords:\n- Type: \"HDB\", \"condo\", \"condominium\", \"apartment\", \"flat\", \"studio\"\n- Location: \"near [location]\", \"in [area]\", \"[district name]\", \"around [place]\"\n- Budget: Any number followed by \"budget\", \"price range\", \"afford\", \"$\", \"SGD\", currency mentions\n- Timeline: Months/years like \"June 2025\", \"next month\", \"ASAP\", \"immediately\", \"by [date]\"\n- Citizenship: \"citizen\", \"PR\", \"permanent resident\", \"foreigner\", \"non-citizen\", \"expat\"\n\nEXTRACTION EXAMPLES:\n- \"I am John looking for condo near Newton, budget 2500\" \u2192 Extract: name=John, type=condo, location=near Newton, budget=2500\n- \"My name is Sarah, phone 91234567, need HDB in Tampines by March 2025\" \u2192 Extract: name=Sarah, phone=91234567, type=HDB, location=Tampines, timeline=March 2025\n\n---\n\n## WORKFLOW STEPS\n\nSTEP 1: HUMAN AGENT HANDOFF (PRIORITY CHECK)\n\nFIRST, check if user message contains any of these keywords/phrases:\n- \"human agent\", \"talk to human\", \"speak to agent\", \"connect me to agent\", \"real person\", \"live agent\", \"customer service\", \"speak to someone\"\n\nIF DETECTED:\n- Check personal details completeness (name, phone, email)\n- IF MISSING personal details:\n  - Respond: \"I'd be happy to connect you with one of our human agents! To ensure they can contact you, I'll need a few details first.\"\n  - COLLECT ONLY missing information sequentially (skip already provided):\n    - If name missing: \"Could you please provide your Full Name?\"\n    - If phone missing: \"What's your Phone Number?\"\n    - If email missing: \"What's your Email Address?\"\n  - After collecting missing details, IMMEDIATELY ask for message:\n    - \"Thank you! Now, what specific message would you like me to pass on to our human agent?\"\n    - STOP and WAIT for user's message response - DO NOT PROCEED until user provides their message\n  \n- IF personal details already available:\n  - Immediately ask: \"What specific message would you like me to pass on to our human agent?\"\n  - STOP and WAIT for user's message response - DO NOT PROCEED until user provides their message\n  \n- ONLY AFTER receiving user's message:\n  - THEN use Human agent tool with this format:\n    - Subject: \"Customer Handoff Request - {name}\"\n    - Email Content: \n      \n      Customer Details:\n      - Name: {name}\n      - Phone: {phone}\n      - Email: {email}\n      \n      Customer Message: {user_message}\n      \n      Property Requirements (if any collected):\n      {include any property requirements already gathered}\n      \n  - AFTER sending email, confirm: \"Thank you! I've forwarded your message to our human agent. They will contact you within 2 days at {email} or {phone}.\"\n  - STOP workflow and wait for user response\n\nIF NOT DETECTED, continue to Step 2\n\nSTEP 2: COLLECT PERSONAL INFORMATION\n\nAfter extracting available personal info:\n- Mental checklist: [name: \u2713/\u2717] [phone: \u2713/\u2717] [email: \u2713/\u2717]\n- ONLY ask for missing information in this exact order:\n  - If name missing: \"Could you please provide your Full Name?\"\n  - If phone missing: \"What's your Phone Number?\"\n  - If email missing: \"What's your Email Address?\"\n- SKIP questions for already provided information\n- VALIDATE inputs:\n  - Phone: Must be 8-12 digits\n  - Email: Must contain @ and domain\n- NO CONFIRMATION STEP - proceed directly after collecting all personal details\n\nSTEP 3: COLLECT PROPERTY REQUIREMENTS\n\nAfter extracting available property requirements:\n- Mental checklist: [type: \u2713/\u2717] [locations: \u2713/\u2717] [budget: \u2713/\u2717] [timeline: \u2713/\u2717] [citizenship: \u2713/\u2717]\n- ONLY ask for missing information in this exact order:\n  - If type missing: \"What Property Type are you looking for? (HDB / Condo / Apartment)\"\n  - If locations missing: \"What are your Preferred Locations or Districts?\"\n  - If budget missing: \"What's your Budget range?\"\n  - If timeline missing: \"When is your preferred Move-in Timeline?\"\n  - If citizenship missing: \"What's your Citizenship Status? (Singapore Citizen / PR / Foreigner)\"\n- SKIP questions for already provided information\n- NO CONFIRMATION STEP - proceed directly after collecting all requirements\n\nSTEP 4: FINAL JSON OUTPUT\nAfter collecting all information:\njson\n{\n\"personal_details\": {\n\"name\": \"{name}\",\n\"phone\": \"{phone}\",\n\"email\": \"{email}\"\n},\n\"properties\": {\n\"type\": \"{type}\",\n\"locations\": \"{locations}\",\n\"budget\": \"{budget}\",\n\"timeline\": \"{timeline}\",\n\"citizenship\": \"{citizenship}\"\n}\n}\n\n\nSTEP 5: PROPERTY SEARCH & DISPLAY\n- Use property search system to find matching properties based on collected requirements\n- Display properties with details such as:\n  - Property name/address\n  - Price/rent\n  - Property features (bedrooms, bathrooms, size, etc.)\n  - Property images if available\n  - Contact information or listing details\n\n\nSTEP 6: APPOINTMENT BOOKING\nAsk: \"Would you like to schedule a viewing for any of these properties?\"\n\nIf yes:\n- Ask: \"Could you please suggest a preferred date for the appointment?\"\n- Wait for user's date suggestion\n- Use get_Calendar tool to check availability for that date\n- IF NO SLOTS AVAILABLE: \"I'm sorry, but that date isn't available. Could you please suggest another date for the appointment?\"\n- IF AVAILABLE: Confirm the slot and send Gmail confirmation\n\n---\n\n## CRITICAL RULES\n\n1. CONTENT FILTER FIRST: Always check for non-property inquiries before any other processing\n2. EXTRACT FIRST, ASK LATER: Always scan user messages for information before asking questions\n3. NO REDUNDANT QUESTIONS: Never ask for information the user already provided\n4. NO CONFIRMATIONS: Skip confirmation steps to avoid repetition\n5. SEQUENTIAL COLLECTION: Ask for missing information in exact specified order\n6. HANDLE BULK RESPONSES: If user provides multiple pieces of info in one response, extract all of it\n7. VALIDATION: Ensure phone numbers and emails are properly formatted\n8. USER-SUGGESTED DATES: Always ask user to suggest appointment dates instead of checking next 3 days\n9. HUMAN AGENT MESSAGE MANDATORY: For human agent requests, NEVER send email without first collecting the user's specific message. Always ask \"What specific message would you like me to pass on to our human agent?\" and WAIT for response before proceeding.\n\n## CONVERSATION MEMORY\n- Track what information has been provided to avoid repetition\n- Remember user's previous responses in the same conversation\n- Don't re-ask questions that were already answered\n\n## AVAILABLE TOOLS\n- Property Search System: For finding and displaying properties based on user requirements  \n- Gmail: For appointment confirmations\n- get_Calendar: For checking available slots on user-suggested dates\n- Human agent: For customer handoff requests\n\nUser input: {{ $json.originalMessage }}"
        },
        "promptType": "define"
      },
      "typeVersion": 1.9
    },
    {
      "id": "301553ac-7c05-4ca9-a4d9-03ac5209ab69",
      "name": "PostgreSQL Memory",
      "type": "@n8n/n8n-nodes-langchain.memoryPostgresChat",
      "position": [
        -240,
        1120
      ],
      "parameters": {
        "tableName": "user_details",
        "sessionKey": "=harshassession123098456",
        "sessionIdType": "customKey",
        "contextWindowLength": 5000
      },
      "typeVersion": 1.3
    },
    {
      "id": "ded5c99e-7b47-4b02-8a4b-66bad2da9a95",
      "name": "Parse Data",
      "type": "n8n-nodes-base.code",
      "position": [
        340,
        780
      ],
      "parameters": {
        "jsCode": "// Initialize default data structure\nlet data = {\n  personal: {\n    name: null,\n    phone: null,\n    email: null\n  },\n  property: {\n    type: null,\n    locations: null,\n    budget: null,\n    timeline: null,\n    citizenship: null\n  }\n};\n\n// Get input from webhook\nconst input = $input.first();\nif (!input || !input.json) {\n  return [{\n    json: {\n      sessionId: 'unknown',\n      personal: data.personal,\n      property: data.property,\n      ready: false\n    }\n  }];\n}\n\nconst sessionId = input.json.sessionId || 'unknown';\nconst rawText = input.json.output || '';\n\n// Attempt to parse JSON from text\ntry {\n  const jsonMatch = rawText.match(/{[\\s\\S]*}/);\n  const jsonString = jsonMatch ? jsonMatch[0] : '{}';\n  const parsedData = JSON.parse(jsonString);\n\n  // Personal info\n  if (parsedData.personal_details) {\n    data.personal.name = parsedData.personal_details.name || null;\n    data.personal.phone = parsedData.personal_details.phone || null;\n    data.personal.email = parsedData.personal_details.email || null;\n  }\n\n  // Property info\n  if (parsedData.properties) {\n    data.property.type = parsedData.properties.type || null;\n    data.property.timeline = parsedData.properties.timeline || null;\n    data.property.citizenship = parsedData.properties.citizenship || null;\n\n    // Clean \"locations\" value to extract just the MRT name\n    if (parsedData.properties.locations) {\n      data.property.locations = parsedData.properties.locations\n        .replace(/(near|beside|around|next to|opposite|close to)\\s+/gi, '')\n        .trim();\n    }\n\n    // Robust budget parsing (handles SGD 2,500 / $2500 / 2500 SGD etc.)\n    if (parsedData.properties.budget) {\n      const rawBudget = parsedData.properties.budget;\n      const cleanedBudget = rawBudget.replace(/[^\\d]/g, '');\n      data.property.budget = cleanedBudget ? parseInt(cleanedBudget, 10) : null;\n    }\n  }\n} catch (e) {\n  console.error('Error parsing JSON data:', e.message);\n}\n\n// Check readiness\nconst ready = Boolean(data.personal.name && data.personal.phone && data.personal.email);\n\n// Final output\nreturn [{\n  json: {\n    sessionId,\n    personal: data.personal,\n    property: data.property,\n    ready\n  }\n}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "caf89764-2c6f-43c7-8610-8db27d500b5f",
      "name": "Save Personal Info",
      "type": "n8n-nodes-base.postgres",
      "position": [
        740,
        920
      ],
      "parameters": {
        "query": "INSERT INTO user_info (name, phone_number, email) VALUES ($1, $2, $3)",
        "options": {
          "queryReplacement": "={{ $('Parse Data').item.json.personal.name }}{{ $('Parse Data').item.json.personal.phone }}{{ $('Parse Data').item.json.personal.email }}{{ $('Parse Data').item.json.sessionId }}"
        },
        "operation": "executeQuery"
      },
      "typeVersion": 2.6
    },
    {
      "id": "c6f368f7-d0f3-4d2c-93bd-b1c0fa982ffc",
      "name": "Query Properties",
      "type": "n8n-nodes-base.postgres",
      "position": [
        600,
        1040
      ],
      "parameters": {
        "query": "SELECT * FROM \"new_properties\"\nWHERE \"Property Type\" ILIKE '%' || $1 || '%'\n  AND \"Nearest MRT\" ILIKE '%' || $2 || '%'\n  AND \"Rental Price (SGD/month)\" <= CAST(regexp_replace($3, '[^0-9]', '', 'g') AS bigint)\nORDER BY \"Rental Price (SGD/month)\" ASC\nLIMIT 5;\n\n",
        "options": {
          "queryReplacement": "={{ $json.property.type }}{{ $json.property.locations }}{{ $json.property.budget }}"
        },
        "operation": "executeQuery"
      },
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.6
    },
    {
      "id": "8f1e928d-c0e1-42cd-bc7a-93f630e4256e",
      "name": "Ready Check",
      "type": "n8n-nodes-base.if",
      "position": [
        320,
        1060
      ],
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{ $json.ready }}",
              "value2": true
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "6841173f-de6c-476a-a343-dbc84bf528e9",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        -360,
        1080
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4",
          "cachedResultName": "gpt-4"
        },
        "options": {
          "temperature": 0
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "2acc09f6-d9bb-43f5-8045-35394f6384c5",
      "name": "Format Results with AI",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1120,
        940
      ],
      "parameters": {
        "text": "={{ $json }}",
        "options": {
          "systemMessage": "=You are a professional real estate assistant. Your task is to format property search results into a natural, engaging response for users.\n\nGiven property data, create a personalized response that:\n1. Acknowledges their search criteria\n2. Presents the properties in an organized, easy-to-read format\n3. Highlights key features like location, price, and property type\n4. Includes a friendly closing with next steps\n\nFormat each property with:\n- Property name/address\n- Property type\n- Monthly rental price\n- Key location details (nearest MRT, district)\n- Brief description of features\n- Include any image urls \n\nKeep the tone professional yet friendly, and make it easy for users to compare options.\n\n\nUser's search criteria: {{ $('Parse Data').item.json.property.type }} in {{ $('Parse Data').item.json.property.locations }} with budget {{ $('Parse Data').item.json.property.budget }}\nProperty results: {{ $json }} "
        },
        "promptType": "define"
      },
      "typeVersion": 1.9
    },
    {
      "id": "ee223706-e6d3-4891-94e0-3005d7a06a38",
      "name": "Format Response",
      "type": "n8n-nodes-base.set",
      "position": [
        1480,
        940
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "format-response-field",
              "name": "text",
              "type": "string",
              "value": "={{ $json.output }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "450403d8-776c-4359-890a-9729930c037a",
      "name": "Send Formatted Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1700,
        840
      ],
      "parameters": {
        "options": {},
        "respondWith": "allIncomingItems"
      },
      "typeVersion": 1
    },
    {
      "id": "650470f7-abfa-41f0-8746-947ad102b6a2",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -780,
        880
      ],
      "parameters": {
        "path": "d22c99cc-a257-4c69-9419-34bb82a14026",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "54ebd3c9-d3a9-46c0-99da-2e3a734459e0",
      "name": "SerpAPI",
      "type": "@n8n/n8n-nodes-langchain.toolSerpApi",
      "position": [
        -20,
        1320
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "295a3776-061c-4324-8639-af282d771072",
      "name": "update_Calendar",
      "type": "n8n-nodes-base.googleCalendarTool",
      "position": [
        2280,
        1600
      ],
      "parameters": {
        "eventId": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Event_ID', ``, 'string') }}",
        "calendar": {
          "__rl": true,
          "mode": "list",
          "value": "user@example.com",
          "cachedResultName": "ABA"
        },
        "operation": "update",
        "updateFields": {}
      },
      "typeVersion": 1.3
    },
    {
      "id": "d39c473d-4ee8-49af-84c9-07e5b2c89fac",
      "name": "OpenAI Chat Model1",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        1880,
        1600
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini"
        },
        "options": {}
      },
      "typeVersion": 1.2
    },
    {
      "id": "f0ad8e3e-6974-4f99-a271-96173bee391d",
      "name": "Gmail1",
      "type": "n8n-nodes-base.gmailTool",
      "position": [
        2420,
        1600
      ],
      "parameters": {
        "sendTo": "={{ $('Gmail Trigger').item.json.from.value[0].address }}",
        "message": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Message', ``, 'string') }}",
        "options": {
          "replyTo": "={{ $('Gmail Trigger').item.json.from.value[0].address }}"
        },
        "subject": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Subject', ``, 'string') }}",
        "emailType": "text"
      },
      "typeVersion": 2.1
    },
    {
      "id": "5157dd53-2ffd-49a5-80e8-893acc8a80bb",
      "name": "AI Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        2160,
        1380
      ],
      "parameters": {
        "text": "={{ $json.html }}",
        "options": {
          "systemMessage": "=You are a helpful assistantYou are an intelligent appointment management assistant that processes email communications to handle appointment confirmations, modifications, and scheduling. Your primary responsibilities include managing calendar events and maintaining clear communication with clients. \nwhenever creating or updating a appointment add title and other details including the name of the user\nmake use of create_Calender, update_Calender, get_Calender and gmail1 node\nget the event id from Google Calendar1 node\nCore Functions\n1. Appointment Confirmation Processing\n\nMonitor incoming emails for appointment-related communications\nIdentify confirmation signals such as:\n\n\"Yes, I confirm the appointment\"\n\"The time works for me\"\n\"I'll be there\"\n\"Confirmed\"\nSimilar affirmative responses\n\n\nExtract appointment details including:\n\nDate and time\nDuration\nParticipant information\nMeeting type/purpose\n\n\n\n2. Calendar Management\n\nCreate new appointments when confirmations are received\nUpdate existing appointments with confirmed details\nCheck availability before proposing new times\nMaintain calendar accuracy by updating event statuses\n\n3. Appointment Modification Handling\nWhen emails indicate schedule changes:\n\nParse modification requests such as:\n\n\"Can we reschedule to...\"\n\"I need to move our meeting\"\n\"Is [new time] available?\"\n\"Can we change the appointment to...\"\n\n\nCheck calendar availability for requested new times\nIdentify conflicts and suggest alternative times if needed\nRespond with availability confirmation or alternative options\n\n4. Email Communication Protocol\n\nSend confirmation emails when appointments are successfully scheduled\nRequest clarification when appointment details are unclear\nProvide availability options when requested times conflict\nSend follow-up emails for pending confirmations\nMaintain professional tone in all communications\n\nDecision Logic\nFor Appointment Confirmations:\nIF email contains confirmation language AND appointment details are clear\n  \u2192 Update calendar with confirmed appointment\n  \u2192 Send confirmation email to participant\nELSE IF confirmation unclear\n  \u2192 Request clarification via email\nFor Schedule Change Requests:\nIF email requests time change\n  \u2192 Extract proposed new time\n  \u2192 Check calendar availability\n  IF time available\n    \u2192 Propose confirmation of new time\n    \u2192 Wait for final confirmation\n  ELSE\n    \u2192 Suggest alternative available times\n    \u2192 Wait for selection and confirmation\nFor Ambiguous Communications:\nIF email intent unclear\n  \u2192 Send clarifying questions\n  \u2192 Wait for response\n  \u2192 Process based on clarified intent\nResponse Templates\nConfirmation Success:\n\"Thank you for confirming your appointment on [Date] at [Time]. Your appointment has been scheduled and you'll receive a calendar invitation shortly.\"\nAvailability Check:\n\"I see you'd like to reschedule to [Requested Time]. Let me check availability... [Available Times]. Please confirm which time works best for you.\"\nClarification Request:\n\"I received your message regarding the appointment. Could you please clarify [specific question] so I can assist you properly?\"\nAvailability Conflict:\n\"Unfortunately, [Requested Time] is not available. Here are some alternative times that work: [List Options]. Please let me know which option you prefer.\"\nWorkflow States\nState 1: Monitoring\n\nContinuously monitor incoming emails\nClassify email intent (confirmation, modification, cancellation, inquiry)\n\nState 2: Processing\n\nParse email content for appointment details\nCross-reference with existing calendar data\nDetermine required action\n\nState 3: Action Execution\n\nUpdate calendar as needed\nPrepare appropriate email response\nSend communication to participant\n\nState 4: Awaiting Response\n\nMonitor for follow-up communications\nSet appropriate timeouts for responses\nEscalate unresolved items after reasonable timeframe\n\nError Handling\n\nInvalid dates/times: Request clarification with valid format examples\nCalendar conflicts: Automatically suggest alternatives\nMissing information: Ask specific questions to gather required details\nAmbiguous requests: Break down into specific, answerable questions\n\nSuccess Criteria\n\nAppointments are accurately reflected in calendar\nAll confirmations receive timely responses\nSchedule conflicts are resolved efficiently\nCommunication remains professional and clear\nNo appointments are lost or double-booked\n\nYour goal is to create a seamless appointment management experience that reduces manual intervention while ensuring accuracy and professional communication standards."
        },
        "promptType": "define"
      },
      "typeVersion": 1.9
    },
    {
      "id": "f4e1a9d0-bc00-4ec5-88a7-961f0934d361",
      "name": "Google Calendar",
      "type": "n8n-nodes-base.googleCalendarTool",
      "position": [
        2540,
        1600
      ],
      "parameters": {
        "eventId": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Event_ID', ``, 'string') }}",
        "options": {},
        "calendar": {
          "__rl": true,
          "mode": "list",
          "value": "user@example.com",
          "cachedResultName": "ABA"
        },
        "operation": "delete"
      },
      "typeVersion": 1.3
    },
    {
      "id": "d4db75be-8980-4f4d-bf07-66814f9c54fe",
      "name": "Gmail Trigger",
      "type": "n8n-nodes-base.gmailTrigger",
      "position": [
        1860,
        1380
      ],
      "parameters": {
        "simple": false,
        "filters": {},
        "options": {},
        "pollTimes": {
          "item": [
            {
              "mode": "everyHour"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "7c53569c-f2b9-4f97-a2d4-c235e3336d9a",
      "name": "Google Calendar1",
      "type": "n8n-nodes-base.googleCalendarTool",
      "position": [
        2740,
        1580
      ],
      "parameters": {
        "options": {},
        "timeMax": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Before', `use the appointment end time when it is scheduled`, 'string') }}",
        "timeMin": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('After', `use the appointment start time when it is scheduled`, 'string') }}",
        "calendar": {
          "__rl": true,
          "mode": "list",
          "value": "user@example.com",
          "cachedResultName": "ABA"
        },
        "operation": "getAll",
        "returnAll": true
      },
      "typeVersion": 1.3
    },
    {
      "id": "afd24454-84a5-4565-b270-1ee37d3535d6",
      "name": "Gmail",
      "type": "n8n-nodes-base.gmailTool",
      "position": [
        -120,
        1140
      ],
      "parameters": {
        "sendTo": "={{ $fromAI('To', ``, 'string') }}",
        "message": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Message', `Please include the location details of property that appointment has been scheduled.`, 'string') }}",
        "options": {},
        "subject": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Subject', `This is a test mail`, 'string') }}"
      },
      "typeVersion": 2.1
    },
    {
      "id": "695bdf40-f667-423a-b437-bf8af335847a",
      "name": "get_Calendar",
      "type": "n8n-nodes-base.googleCalendarTool",
      "position": [
        100,
        1220
      ],
      "parameters": {
        "options": {},
        "timeMax": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Before', `Three days after the \"after\"`, 'string') }}",
        "calendar": {
          "__rl": true,
          "mode": "list",
          "value": "user@example.com",
          "cachedResultName": "ABA"
        },
        "operation": "getAll",
        "returnAll": true
      },
      "typeVersion": 1.3
    },
    {
      "id": "1eb80e21-84bc-4b81-a21d-669c90837a24",
      "name": "create_Calendar1",
      "type": "n8n-nodes-base.googleCalendarTool",
      "position": [
        2100,
        1620
      ],
      "parameters": {
        "end": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('End', `end the event an hour after the start of the event`, 'string') }}",
        "start": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Start', `start an event at the time of appointment scheduled in indian standard time`, 'string') }}",
        "calendar": {
          "__rl": true,
          "mode": "list",
          "value": "user@example.com",
          "cachedResultName": "ABA"
        },
        "descriptionType": "manual",
        "toolDescription": "create an event after the confirmation mail from the user, add title description about the property and user details and return the event id to the agent",
        "additionalFields": {
          "color": "7",
          "summary": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Summary', `with buyer name`, 'string') }}",
          "location": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Location', ``, 'string') }}"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "17fd2bbb-8cd9-4746-834e-c0680c390bc2",
      "name": "Human agent",
      "type": "n8n-nodes-base.gmailTool",
      "position": [
        180,
        1080
      ],
      "parameters": {
        "sendTo": "user@example.com",
        "message": "=<b>Dear Mark,</b><br><br>\n\nI hope this email finds you well.<br><br>\n\nCustomer Details:<br>\n- Name: <b>{{ $fromAI('customer_name', 'Customer Name', 'string') }}</b><br>\n- Phone: <b>{{ $fromAI('customer_phone', 'Phone Number', 'string') }}</b><br>\n- Email:  <b>{{ $fromAI('customer_email', 'Email Address', 'string') }}</b><br><br>\n\nCustomer Message:<br>\n<b>{{ $fromAI('customer_message', 'Customer Message', 'string') }}</b><br><br>\n\nProperty Requirements (if any collected):<br>\n<b>{{ $fromAI('property_requirements', 'None specified', 'string') }}</b><br><br>\n\n<b>Please let me know if you need any further information or clarification.</b><br><br>\n\n<b>Best\u00a0regards</b>",
        "options": {},
        "subject": "={{ $fromAI('subject', 'Customer Handoff Request', 'string') }}"
      },
      "typeVersion": 2.1
    },
    {
      "id": "e52b0389-eb41-4d9f-8dc8-9434e1957886",
      "name": "Code",
      "type": "n8n-nodes-base.code",
      "position": [
        -540,
        880
      ],
      "parameters": {
        "jsCode": "const input = $input.first();\nconst message = input.json.body?.message || input.json.message || \"\";\n\n// Simple URL regex\nconst urlRegex = /(https?:\\/\\/[^\\s]+)/g;\n\n// Extract links\nconst foundLinks = message.match(urlRegex);\n\nreturn [\n  {\n    json: {\n      originalMessage: message,\n      link: foundLinks ? foundLinks[0] : null, // Return the first found link\n      allLinks: foundLinks || [],\n    }\n  }\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "89b6f6be-f3aa-4981-8121-c8f4650e863c",
      "name": "If",
      "type": "n8n-nodes-base.if",
      "position": [
        -400,
        680
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "db9f1cb5-db2a-448d-82f0-6e5449d36411",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.link }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "8ea7c7bb-5692-4ef8-a08d-5baa0656ecb4",
      "name": "Postgres",
      "type": "n8n-nodes-base.postgres",
      "position": [
        -80,
        660
      ],
      "parameters": {
        "query": "SELECT *\nFROM new_properties\nWHERE propertyguru_url = $1 OR \"99.co_url\" = $1\nLIMIT 1;\n",
        "options": {
          "queryReplacement": "={{ $json.link }}"
        },
        "operation": "executeQuery"
      },
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.6
    },
    {
      "id": "1bc9824a-6d3c-47d5-ae61-74acfa78d167",
      "name": "Code1",
      "type": "n8n-nodes-base.code",
      "position": [
        460,
        660
      ],
      "parameters": {
        "jsCode": "const properties = $input.all().map((item) => item.json);\n\nconst propertySummaries = properties.map((property) => {\n  const {\n    \"Property Type\": propertyType,\n    \"Condo Name\": condoName,\n    \"Floor Level\": floorLevel,\n    \"Built Year\": builtYear,\n    \"Floor Area (sqft)\": floorArea,\n    Bedrooms: bedrooms,\n    Bathrooms: bathrooms,\n    \"Maid Room Available\": maidRoomAvailable,\n    \"Furnishing Status\": furnishingStatus,\n    Availability: availability,\n    \"Agency Fee Applicable\": agencyFeeApplicable,\n    \"Rental Price (SGD/month)\": rentalPrice,\n    \"Minimum Lease Period\": minimumLeasePeriod,\n    \"Security Deposit\": securityDeposit,\n    Street: street,\n    Level: level,\n    \"Unit No\": unitNo,\n    \"Postal Code\": postalCode,\n    City: city,\n    Country: country,\n    District: district,\n    \"Nearest MRT\": nearestMRT,\n    \"Distance from MRT\": distanceFromMRT,\n    \"MRT Line\": mrtLine,\n    \"Nearest Bus Stop\": nearestBusStop,\n    \"Nearest School\": nearestSchool,\n    \"Nearest University\": nearestUniversity,\n    \"Nearest Convenience Store\": nearestConvenienceStore,\n    Aircon: aircon,\n    Balcony: balcony,\n    Renovated: renovated,\n    \"Pet Friendly\": petFriendly,\n    \"Smoking Allowed\": smokingAllowed,\n    \"Cooking Allowed\": cookingAllowed,\n    Facing: facing,\n    \"BBQ Pits\": bbqPits,\n    Clubhouse: clubhouse,\n    Gym: gym,\n    \"Fitness Corner\": fitnessCorner,\n    Jacuzzi: jacuzzi,\n    \"Jogging Track\": joggingTrack,\n    \"Swimming Pool\": swimmingPool,\n    \"Gender Preferred\": genderPreferred,\n    \"Nationality Preference\": nationalityPreference,\n    \"Cooking Preference\": cookingPreference,\n    \"Visitors Allowed\": visitorsAllowed,\n    \"Group Size\": groupSize,\n    \"Preferred Profile\": preferredProfile,\n  } = property;\n\n  return `The property is a ${propertyType} named ${condoName} built in ${builtYear}. It is located at ${street}, ${city}, ${country} with postal code ${postalCode}. The condo is on the ${floorLevel} with a unit number ${unitNo}. It has a floor area of ${floorArea} sqft with ${bedrooms} bedrooms and ${bathrooms} bathrooms. Maid room is ${maidRoomAvailable ? \"available\" : \"not available\"}. The property is ${furnishingStatus} and is currently ${availability}. The rental price is SGD ${rentalPrice} per month with a minimum lease period of ${minimumLeasePeriod} and a security deposit of ${securityDeposit}. The property is ${renovated ? \"renovated\" : \"not renovated\"} with ${aircon ? \"air conditioning\" : \"no air conditioning\"} and ${balcony ? \"a balcony\" : \"no balcony\"}. The property is ${petFriendly ? \"pet friendly\" : \"not pet friendly\"} and ${smokingAllowed ? \"allows smoking\" : \"does not allow smoking\"}. Cooking is ${cookingAllowed ? \"allowed\" : \"not allowed\"} and the property faces ${facing}. The property has ${bbqPits ? \"BBQ pits\" : \"no BBQ pits\"}, ${clubhouse ? \"a clubhouse\" : \"no clubhouse\"}, ${gym ? \"a gym\" : \"no gym\"}, ${fitnessCorner ? \"a fitness corner\" : \"no fitness corner\"}, ${jacuzzi ? \"a jacuzzi\" : \"no jacuzzi\"}, ${joggingTrack ? \"a jogging track\" : \"no jogging track\"}, and ${swimmingPool ? \"a swimming pool\" : \"no swimming pool\"}. The preferred tenant profile is ${preferredProfile} with a group size of ${groupSize}. Visitors are ${visitorsAllowed ? \"allowed\" : \"not allowed\"}. The preferred gender is ${genderPreferred} and nationality is ${nationalityPreference}. Cooking preference is ${cookingPreference}. The nearest MRT station is ${nearestMRT} which is ${distanceFromMRT} away. The MRT line is ${mrtLine}. The nearest bus stop is ${nearestBusStop}, the nearest school is ${nearestSchool}, the nearest university is ${nearestUniversity}, and the nearest convenience store is ${nearestConvenienceStore}.`;\n});\n\nreturn { propertySummaries };\n"
      },
      "typeVersion": 2
    },
    {
      "id": "9aea30af-b6be-45aa-967f-58b9a0c24e62",
      "name": "Get Property Media",
      "type": "n8n-nodes-base.postgres",
      "position": [
        540,
        1260
      ],
      "parameters": {
        "query": "SELECT storage_path,property_id\nFROM property_media\nWHERE property_id = $1\nLIMIT 1;\n",
        "options": {
          "queryReplacement": "={{ $json.ID }}"
        },
        "operation": "executeQuery"
      },
      "typeVersion": 2.6
    },
    {
      "id": "d880d83c-1173-4cfd-9202-d38314090639",
      "name": "construct_image_url",
      "type": "n8n-nodes-base.code",
      "position": [
        760,
        1200
      ],
      "parameters": {
        "jsCode": "const baseUrl = 'https://ztsgwqqxffrvqoqwrsjn.supabase.co/YOUR_AWS_SECRET_KEY_HERE';\n\n// Use a Set to deduplicate, then take the first one\nconst urls = [...new Set(items.map(item => baseUrl + item.json.storage_path))];\n\nreturn [\n  {\n    json: {\n      image_url: urls[0] || null,  // If no image found, return null\n      id:$input.first().json.property_id\n    }\n  }\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "cb0d7cb8-2a83-43f2-a992-3b75ce0c4fc4",
      "name": "Merge",
      "type": "n8n-nodes-base.merge",
      "position": [
        960,
        1040
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "advanced": true,
        "joinMode": "keepEverything",
        "mergeByFields": {
          "values": [
            {
              "field1": "ID",
              "field2": "id"
            }
          ]
        }
      },
      "typeVersion": 3.1
    },
    {
      "id": "9d7a7def-ac90-4c44-a621-9740336bd7da",
      "name": "If1",
      "type": "n8n-nodes-base.if",
      "position": [
        140,
        640
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "81840824-4572-4acf-afe6-f684fe9e72fe",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.Availability }}",
              "rightValue": "Immediate"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "56c5c116-c26d-4fff-8854-9b0808602716",
      "name": "OpenAI Chat Model3",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        1120,
        1160
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini"
        },
        "options": {
          "temperature": 0
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "bdd306d9-d719-44d1-829c-68259d3fe461",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1300,
        -80
      ],
      "parameters": {
        "width": 460,
        "height": 1980,
        "content": "#### Description\n###### A comprehensive real estate chatbot automation system that handles customer inquiries, property searches, and appointment scheduling through intelligent conversation flows and email processing. \n\n##### Entry Point\n \ud83c\udf10 Webhook Trigger\n- Customer sends chat message\n- Extracts property links if shared\n- Routes to processing pipeline\n\n\ud83d\udd0d Link Detection  \n- Checks for property URLs\n- Fetches from database if found\n- Shows immediate results or continues chat\n\n##### \ud83e\udd16 AI Chat Processing\n\ud83d\udee1\ufe0f Content Filter (PRIORITY)\n- Blocks non-real estate queries\n- Allows: rentals, purchases, viewings\n- Rejects: spam, adult content, unrelated\n\n\ud83e\udde0 Smart Info Extraction\n- Scans for personal details first\n- Extracts property requirements\n- Never asks for provided info\n- Handles bulk responses intelligently\n\n\ud83d\udc64 Human Agent Handoff\n- Detects \"talk to human\" requests\n- Collects missing contact details\n- Gets customer's specific message\n- Sends handoff email with full context\n\n#### \ud83d\udcca Data Collection\n##### \ud83d\udccb Sequential Collection\nPersonal: Name \u2192 Phone \u2192 Email\nProperty: Type \u2192 Location \u2192 Budget \u2192 Timeline\n- Validates formats automatically\n- No redundant questions\n\ud83d\uddc4\ufe0f Database Operations\n- Saves to user_info table\n- Searches new_properties with filters\n- Returns top 5 matches by price\n- Handles citizenship requirements\n\n##### \ud83d\uddbc\ufe0f Media Enhancement\n- Fetches property images\n- Constructs storage URLs\n- Merges with property data\n- Enhanced visual experience\n\n##### \ud83d\udce4 Output Generation\n\u2728 AI-Formatted Results\n- GPT-4 creates engaging listings\n- Professional yet friendly tone\n- Highlights key features\n- Includes images and details\n\ud83d\udcf1 Response Delivery\n- Sends formatted response\n- Maintains conversation memory\n- Ready for follow-up questions\n- Contextual awareness\n##### \ud83d\uddd3\ufe0f Appointment Automation\n##### \ud83d\udce7 Gmail Monitoring\n- Checks emails every hour\n- Detects appointment confirmations\n- Processes schedule changes\n- Handles customer communications\n\n##### \ud83d\udcc5 Calendar Management\n- Creates confirmed appointments\n- Checks time availability\n- Updates/deletes as needed\n- Sends calendar invitations\n\ud83e\udd16 AI Appointment Agent\n- Processes email intelligently\n- Extracts dates and preferences\n- Responds with confirmations\n- Suggests alternatives if conflicts\n\n##### \ud83d\udd11 Key Features\n\n\ud83e\udde0 Memory Retention - PostgreSQL chat memory across sessions\n\ud83d\udd12 Content Filtering - Blocks inappropriate requests upfront\n\ud83d\udcca Smart Extraction - Never asks for already-provided information\n\ud83c\udfaf Targeted Search - Multi-criteria property matching\n\u2728 AI Formatting - Professional property presentations\n\ud83d\udcc5 Auto Scheduling - Email-triggered appointment management\n\ud83d\udc65 Human Handoff - Seamless agent escalation\n\ud83d\udcf1 Multi-channel - Webhook + Email processing\n"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "b83b3021-8e5a-4965-a71f-7ddf623463d1",
  "connections": {
    "If": {
      "main": [
        [
          {
            "node": "Postgres",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "LLM conversation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If1": {
      "main": [
        [
          {
            "node": "Code1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "LLM conversation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code": {
      "main": [
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code1": {
      "main": [
        [
          {
            "node": "Send Formatted Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gmail": {
      "ai_tool": [
        [
          {
            "node": "LLM conversation",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Merge": {
      "main": [
        [
          {
            "node": "Format Results with AI",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gmail1": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Webhook": {
      "main": [
        [
          {
            "node": "Code",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Postgres": {
      "main": [
        [
          {
            "node": "If1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Data": {
      "main": [
        [
          {
            "node": "Ready Check",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Human agent": {
      "ai_tool": [
        [
          {
            "node": "LLM conversation",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Ready Check": {
      "main": [
        [
          {
            "node": "Query Properties",
            "type": "main",
            "index": 0
          },
          {
            "node": "Save Personal Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "get_Calendar": {
      "ai_tool": [
        [
          {
            "node": "LLM conversation",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Gmail Trigger": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Response": {
      "main": [
        [
          {
            "node": "Send Formatted Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Calendar": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "update_Calendar": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Google Calendar1": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "LLM conversation": {
      "main": [
        [
          {
            "node": "Parse Data",
            "type": "main",
            "index": 0
          },
          {
            "node": "Send Formatted Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Query Properties": {
      "main": [
        [
          {
            "node": "Get Property Media",
            "type": "main",
            "index": 0
          },
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "create_Calendar1": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "LLM conversation",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "PostgreSQL Memory": {
      "ai_memory": [
        [
          {
            "node": "LLM conversation",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Get Property Media": {
      "main": [
        [
          {
            "node": "construct_image_url",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model1": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model3": {
      "ai_languageModel": [
        [
          {
            "node": "Format Results with AI",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "construct_image_url": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Format Results with AI": {
      "main": [
        [
          {
            "node": "Format Response",
            "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

A comprehensive real estate chatbot automation system that handles customer inquiries, property searches, and appointment scheduling through intelligent conversation flows and email processing.

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

L&D_AgentsAI_ATIVO. Uses httpRequest, agent, googleCalendarTool, toolSerpApi. Webhook trigger; 93 nodes.

HTTP Request, Agent, Google Calendar Tool +9
AI & RAG

This workflow integrates multiple productivity tools into a single AI-powered assistant using n8n, acting as a centralized control hub to receive and execute tasks across Google Calendar, Gmail, Googl

Agent, Discord, OpenAI Chat +12
AI & RAG

This workflow transforms WhatsApp into a powerful personal AI using n8n + Green-API. Send text or voice messages — the assistant understands intent and handles daily tasks automatically. 💰 Expense & i

Tool Calculator, Google Sheets Tool, OpenAI Chat +10
AI & RAG

📝 Description

HTTP Request, OpenAI, Google Docs Tool +6
AI & RAG

✨ Intro This workflow shows how to go beyond a “plain” AI chatbot by:

Telegram, OpenAI, OpenAI Chat +13