Tenant requests AI agent on WhatsApp

Tenants report repairs, ask about rent and building rules on WhatsApp; the agent logs every request for your team.

AI agentAdvanced Saves ~15 hours/month AI AgentsBy Flowngn team

Works with n8n · Make · Zapier

How it works

Trigger: WhatsApp — a tenant sends a message
  1. A tenant reports a problem or asks a question.
  2. The agent checks their unit record and the building info.
  3. For repairs, it asks the right questions and logs a maintenance request.
  4. It alerts your team, and sends urgent cases to your emergency number.

What it can do

Unlike a fixed flow, an agent decides which of its tools to use, in what order — and remembers the conversation.

  • Logs maintenance requests with problem, urgency and visit time
  • Tells tenants their rent, due day and lease end
  • Answers building rules and payment questions

System prompt

The instructions that shape the agent. It's already inside the n8n template — copy it into Make or Zapier, and adjust the YOUR_… parts.

System prompt
You are the WhatsApp assistant for YOUR_PROPERTY_COMPANY, talking to tenants. Reply in the customer's language and dialect (Egyptian Arabic, Gulf Arabic, Modern Standard Arabic or English). Be warm and brief.

Today is {{ $now.toFormat('cccc d LLLL yyyy') }}. The tenant's phone is {{ $('Get question').item.json.from }}.

Tools:
- "My unit": this tenant's record (building, unit, rent, due day, lease end, balance). It only returns the person who is messaging.
- "Building info": rules, payment methods, parking, garbage days, emergency contacts.
- "Log maintenance request": logs a repair request. Ask what's wrong, where in the unit, since when, and when someone can visit, before logging.
- "Notify team": alerts the property team about every maintenance request, payment questions, complaints and lease questions.

Rules:
- If "My unit" returns nothing, say the number isn't registered and use "Notify team".
- For urgent issues (water leak, no electricity, gas smell, broken door lock), tell them to call YOUR_EMERGENCY_PHONE now and use "Notify team".
- Never agree to rent changes, late-payment exceptions or lease terms; the team decides.
- Never share other tenants' details.

Safety rules

Built into the prompt and the tools:

  • Only shows a tenant their own unit
  • Never agrees to rent or lease changes
  • Sends leaks, power and gas issues to the emergency line

Uses your own AI key (Claude, OpenAI or another model). Cost depends on the model and conversation length — a small, fast model keeps most conversations to a fraction of a cent.

Diagram

WIncoming messageWhatsApp Trigger{ }Get questionCodeTenant agentAI AgentClaude modelAnthropic Chat Mo…◷MemorySimple MemoryGMy unitGoogle Sheets ToolGBuilding infoGoogle Sheets ToolGLog maintenanc…Google Sheets ToolTNotify teamTelegram ToolWReply on WhatsAppWhatsApp Business Cloud
Trigger App Code AI Agent tool

Code

JavaScript used in the Code step — already included in the template below.

Get question · Code node
// Keeps only text messages and pulls out who sent it and what they asked.
const msg = $input.first().json.messages?.[0];
if (!msg || msg.type !== "text") return [];

return [{ json: { from: msg.from, question: msg.text.body } }];

Build it

Pick your tool — same automation, step by step.

Copy and paste straight into an n8n canvas (Ctrl+V), or download and use Import from File. Then connect your own credentials and replace every YOUR_… placeholder. AI steps use a Claude model node — swap it for OpenAI, Gemini or Ollama if you prefer.

Workflow JSON
Show code (341 lines)
{
  "name": "Tenant requests AI agent on WhatsApp (Flowngn)",
  "nodes": [
    {
      "parameters": {
        "content": "## Tenant requests AI agent on WhatsApp\nTenants report repairs, ask about rent and building rules on WhatsApp; the agent logs every request for your team.\n\n**Setup**\n1. Open each node and connect your own credentials.\n2. Replace every YOUR_… placeholder.\n3. Test once, then activate.\n\nFree template from Flowngn",
        "height": 260,
        "width": 340
      },
      "id": "3da33d1f-b5bd-449b-aacb-2636d9dfa052",
      "name": "Setup notes",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -420,
        -60
      ]
    },
    {
      "parameters": {
        "updates": [
          "messages"
        ]
      },
      "id": "3da33d1f-b5bd-449b-aacb-2636d9dfa052",
      "name": "Incoming message",
      "type": "n8n-nodes-base.whatsAppTrigger",
      "typeVersion": 1,
      "position": [
        0,
        0
      ],
      "webhookId": "3da33d1f-b5bd-449b-aacb-2636d9dfa052"
    },
    {
      "parameters": {
        "jsCode": "// Keeps only text messages and pulls out who sent it and what they asked.\nconst msg = $input.first().json.messages?.[0];\nif (!msg || msg.type !== \"text\") return [];\n\nreturn [{ json: { from: msg.from, question: msg.text.body } }];"
      },
      "id": "3da33d1f-b5bd-449b-aacb-2636d9dfa052",
      "name": "Get question",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        300,
        0
      ]
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "={{ $json.question }}",
        "options": {
          "systemMessage": "=You are the WhatsApp assistant for YOUR_PROPERTY_COMPANY, talking to tenants. Reply in the customer's language and dialect (Egyptian Arabic, Gulf Arabic, Modern Standard Arabic or English). Be warm and brief.\n\nToday is {{ $now.toFormat('cccc d LLLL yyyy') }}. The tenant's phone is {{ $('Get question').item.json.from }}.\n\nTools:\n- \"My unit\": this tenant's record (building, unit, rent, due day, lease end, balance). It only returns the person who is messaging.\n- \"Building info\": rules, payment methods, parking, garbage days, emergency contacts.\n- \"Log maintenance request\": logs a repair request. Ask what's wrong, where in the unit, since when, and when someone can visit, before logging.\n- \"Notify team\": alerts the property team about every maintenance request, payment questions, complaints and lease questions.\n\nRules:\n- If \"My unit\" returns nothing, say the number isn't registered and use \"Notify team\".\n- For urgent issues (water leak, no electricity, gas smell, broken door lock), tell them to call YOUR_EMERGENCY_PHONE now and use \"Notify team\".\n- Never agree to rent changes, late-payment exceptions or lease terms; the team decides.\n- Never share other tenants' details."
        }
      },
      "id": "3da33d1f-b5bd-449b-aacb-2636d9dfa052",
      "name": "Tenant agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 1.9,
      "position": [
        600,
        0
      ]
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "claude-sonnet-5",
          "mode": "list"
        },
        "options": {}
      },
      "id": "3da33d1f-b5bd-449b-aacb-2636d9dfa052",
      "name": "Claude model",
      "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
      "typeVersion": 1.3,
      "position": [
        175,
        220
      ]
    },
    {
      "parameters": {
        "sessionIdType": "customKey",
        "sessionKey": "={{ $('Get question').item.json.from }}",
        "contextWindowLength": 10
      },
      "id": "3da33d1f-b5bd-449b-aacb-2636d9dfa052",
      "name": "Memory",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "typeVersion": 1.3,
      "position": [
        345,
        220
      ]
    },
    {
      "parameters": {
        "descriptionType": "manual",
        "toolDescription": "Returns the record of the tenant who is messaging.",
        "operation": "read",
        "documentId": {
          "__rl": true,
          "value": "YOUR_SPREADSHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Tenants",
          "mode": "name"
        },
        "filtersUI": {
          "values": [
            {
              "lookupColumn": "phone",
              "lookupValue": "={{ $('Get question').item.json.from }}"
            }
          ]
        },
        "options": {}
      },
      "id": "3da33d1f-b5bd-449b-aacb-2636d9dfa052",
      "name": "My unit",
      "type": "n8n-nodes-base.googleSheetsTool",
      "typeVersion": 4.5,
      "position": [
        515,
        220
      ]
    },
    {
      "parameters": {
        "descriptionType": "manual",
        "toolDescription": "Returns building rules, payment methods, parking, garbage days and emergency contacts.",
        "operation": "read",
        "documentId": {
          "__rl": true,
          "value": "YOUR_SPREADSHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Building info",
          "mode": "name"
        },
        "options": {}
      },
      "id": "3da33d1f-b5bd-449b-aacb-2636d9dfa052",
      "name": "Building info",
      "type": "n8n-nodes-base.googleSheetsTool",
      "typeVersion": 4.5,
      "position": [
        685,
        220
      ]
    },
    {
      "parameters": {
        "descriptionType": "manual",
        "toolDescription": "Logs a maintenance request.",
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "YOUR_SPREADSHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Maintenance",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "date": "={{ $now.toISO() }}",
            "phone": "={{ $('Get question').item.json.from }}",
            "unit": "={{ $fromAI('unit', \"Building and unit\", 'string') }}",
            "problem": "={{ $fromAI('problem', \"What's wrong and where\", 'string') }}",
            "urgency": "={{ $fromAI('urgency', \"urgent, soon or whenever\", 'string') }}",
            "visit_time": "={{ $fromAI('visit_time', \"When someone can visit\", 'string') }}",
            "status": "open"
          }
        },
        "options": {}
      },
      "id": "3da33d1f-b5bd-449b-aacb-2636d9dfa052",
      "name": "Log maintenance request",
      "type": "n8n-nodes-base.googleSheetsTool",
      "typeVersion": 4.5,
      "position": [
        855,
        220
      ]
    },
    {
      "parameters": {
        "descriptionType": "manual",
        "toolDescription": "Alerts the property team about maintenance, payments, complaints and lease questions.",
        "chatId": "YOUR_TEAM_CHAT_ID",
        "text": "={{ $fromAI('message', \"What the team needs to know, including the customer's phone\", 'string') }}",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "id": "3da33d1f-b5bd-449b-aacb-2636d9dfa052",
      "name": "Notify team",
      "type": "n8n-nodes-base.telegramTool",
      "typeVersion": 1.2,
      "position": [
        1025,
        220
      ]
    },
    {
      "parameters": {
        "operation": "send",
        "phoneNumberId": "YOUR_PHONE_NUMBER_ID",
        "recipientPhoneNumber": "={{ $('Get question').item.json.from }}",
        "textBody": "={{ $json.output }}"
      },
      "id": "3da33d1f-b5bd-449b-aacb-2636d9dfa052",
      "name": "Reply on WhatsApp",
      "type": "n8n-nodes-base.whatsApp",
      "typeVersion": 1,
      "position": [
        900,
        0
      ]
    }
  ],
  "connections": {
    "Incoming message": {
      "main": [
        [
          {
            "node": "Get question",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get question": {
      "main": [
        [
          {
            "node": "Tenant agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Tenant agent": {
      "main": [
        [
          {
            "node": "Reply on WhatsApp",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Claude model": {
      "ai_languageModel": [
        [
          {
            "node": "Tenant agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Memory": {
      "ai_memory": [
        [
          {
            "node": "Tenant agent",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "My unit": {
      "ai_tool": [
        [
          {
            "node": "Tenant agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Building info": {
      "ai_tool": [
        [
          {
            "node": "Tenant agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Log maintenance request": {
      "ai_tool": [
        [
          {
            "node": "Tenant agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Notify team": {
      "ai_tool": [
        [
          {
            "node": "Tenant agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "tags": []
}

Open in the playground to edit →

Tips

  • Pair it with the rent due reminders flow, which uses the same Tenants sheet.

Related flows