Skip to content
Learn Agentic AI12 min read0 views

AI Tenant Support Agent: Maintenance Requests, Rent Inquiries, and Lease Questions

Build an AI tenant support agent that handles maintenance ticket creation, rent balance lookups, lease question answering, and smart escalation to property management staff.

The Property Management Communication Problem

Property managers spend 60-70% of their time answering repetitive tenant questions: "When is my rent due?", "What is the status of my maintenance request?", "Can I have a pet?" An AI tenant support agent handles these inquiries instantly while creating proper tickets for issues that need human attention.

This guide walks through building a tenant support agent with maintenance ticket creation, rent inquiry handling, lease lookups, and intelligent escalation.

Tenant Data Models

We start with the data layer that the agent needs to access.

from dataclasses import dataclass, field
from datetime import datetime, date
from enum import Enum
from typing import Optional

class TicketPriority(Enum):
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"
    EMERGENCY = "emergency"

class TicketStatus(Enum):
    OPEN = "open"
    IN_PROGRESS = "in_progress"
    SCHEDULED = "scheduled"
    COMPLETED = "completed"

@dataclass
class MaintenanceTicket:
    ticket_id: str
    tenant_id: str
    unit: str
    category: str  # plumbing, electrical, hvac, appliance, etc.
    description: str
    priority: TicketPriority
    status: TicketStatus
    created_at: datetime
    scheduled_date: Optional[date] = None

@dataclass
class TenantAccount:
    tenant_id: str
    name: str
    unit: str
    lease_start: date
    lease_end: date
    monthly_rent: float
    balance_due: float
    pet_policy: str
    parking_spot: Optional[str] = None

Building the Maintenance Ticket System

The ticket creation tool needs to classify urgency automatically. A burst pipe is an emergency; a squeaky door is low priority.

from agents import function_tool
import uuid

EMERGENCY_KEYWORDS = ["flood", "fire", "gas leak", "no heat", "burst pipe", "sewage", "electrical fire"]
HIGH_PRIORITY_KEYWORDS = ["no hot water", "ac broken", "heater broken", "leak", "mold"]

def classify_priority(description: str) -> TicketPriority:
    desc_lower = description.lower()
    for kw in EMERGENCY_KEYWORDS:
        if kw in desc_lower:
            return TicketPriority.EMERGENCY
    for kw in HIGH_PRIORITY_KEYWORDS:
        if kw in desc_lower:
            return TicketPriority.HIGH
    return TicketPriority.MEDIUM

@function_tool
async def create_maintenance_ticket(
    tenant_id: str,
    category: str,
    description: str,
) -> str:
    """Create a maintenance request ticket for a tenant."""
    priority = classify_priority(description)
    ticket_id = str(uuid.uuid4())[:8]

    # In production, this writes to a database
    ticket = MaintenanceTicket(
        ticket_id=ticket_id,
        tenant_id=tenant_id,
        unit="auto-resolved",  # looked up from tenant_id
        category=category,
        description=description,
        priority=priority,
        status=TicketStatus.OPEN,
        created_at=datetime.now(),
    )

    response = f"Ticket {ticket_id} created (Priority: {priority.value})."
    if priority == TicketPriority.EMERGENCY:
        response += " EMERGENCY: Maintenance team has been paged immediately."
    return response

@function_tool
async def check_ticket_status(ticket_id: str) -> str:
    """Look up the status of an existing maintenance ticket."""
    # In production, this queries the database
    return (
        f"Ticket {ticket_id}: Status is IN_PROGRESS. "
        f"Scheduled for Tuesday between 9 AM and 12 PM. "
        f"Technician: Mike R."
    )

The priority classification is intentionally keyword-based rather than LLM-based. For safety-critical routing like emergency maintenance, deterministic rules are more reliable than probabilistic model outputs.

See AI Voice Agents Handle Real Calls

Book a free demo or calculate how much you can save with AI voice automation.

Rent and Lease Inquiry Tools

@function_tool
async def get_rent_info(tenant_id: str) -> str:
    """Get rent balance, due date, and payment history for a tenant."""
    # In production, this queries the accounting system
    return (
        "Monthly rent: $1,850.00\n"
        "Current balance: $0.00 (paid through March 2026)\n"
        "Next due date: April 1, 2026\n"
        "Payment method: Auto-pay (Chase checking ending 4521)"
    )

@function_tool
async def lookup_lease_terms(tenant_id: str, question: str) -> str:
    """Answer a question about a tenant's lease terms."""
    # In production, this searches a parsed lease document
    lease_data = {
        "pet_policy": "Cats and small dogs (under 35 lbs) allowed with $500 deposit.",
        "guest_policy": "Guests may stay up to 14 consecutive days without notification.",
        "subletting": "Subletting is not permitted without written landlord approval.",
        "early_termination": "60-day notice required. Early termination fee: 2 months rent.",
        "parking": "One assigned spot included. Additional spots $75/month if available.",
    }
    q_lower = question.lower()
    for key, answer in lease_data.items():
        if any(word in q_lower for word in key.split("_")):
            return answer
    return "I could not find that specific clause. Let me connect you with property management."

Escalation Logic

Not every issue should stay with the AI. We build an explicit escalation tool.

@function_tool
async def escalate_to_manager(
    tenant_id: str,
    reason: str,
    urgency: str = "normal",
) -> str:
    """Escalate an issue to the property manager when AI cannot resolve it."""
    return (
        f"Your request has been escalated to the property manager. "
        f"Reason: {reason}. "
        f"Expected response time: {'1 hour' if urgency == 'urgent' else '24 hours'}."
    )

Assembling the Agent

from agents import Agent

tenant_agent = Agent(
    name="TenantSupportAgent",
    instructions="""You are a tenant support assistant for Oakwood Apartments.
    Identify the tenant by their unit number or tenant ID first.
    Handle maintenance requests by creating tickets.
    Answer rent and lease questions from the system.
    Escalate to a manager for: complaints about neighbors, legal disputes,
    lease negotiations, or anything you are unsure about.
    Be empathetic and professional.""",
    tools=[
        create_maintenance_ticket,
        check_ticket_status,
        get_rent_info,
        lookup_lease_terms,
        escalate_to_manager,
    ],
)

FAQ

How does the agent handle emergency maintenance requests after hours?

The priority classifier detects emergency keywords and automatically pages the on-call maintenance team. The agent confirms to the tenant that emergency staff have been notified and provides safety instructions when applicable (e.g., "shut off the water main valve").

Should rent payment processing go through the AI agent?

No. The agent should only provide balance information and payment status. Actual payment processing should happen through a secure payment portal. The agent can share a link to that portal but should never collect payment card details directly.

How do you prevent tenants from accessing other tenants' information?

Authentication happens before the agent conversation begins. The tenant's ID is injected into the session context, and all tool calls are scoped to that ID. The agent never accepts a tenant ID from the conversation — it uses only the authenticated session identity.


#TenantSupport #PropertyManagement #AgenticAI #Python #MaintenanceAutomation #LearnAI #AIEngineering

Share this article
C

CallSphere Team

Expert insights on AI voice agents and customer communication automation.

Try CallSphere AI Voice Agents

See how AI voice agents work for your industry. Live demo available -- no signup required.