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
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.