cd /news/ai-agents/follow-up-timers-for-property-leads-… · home › topics › ai-agents › article
[ARTICLE · art-152720] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=↑ positive

Follow-Up Timers for Property Leads: A Small Scheduler With Stop Rules

A co-founder of NxFlowAI (Mumbai) outlined a small scheduler pattern for real-estate lead follow-up automation built around explicit stop rules, using a per-lead FollowUp data model, a three-step sequence, a should_stop function, and a periodic tick worker loop. The design halts automation and alerts a human agent whenever a lead replies, and recommends making advance and stop atomic with the send or using an outbox table to prevent duplicate nudges after a crash.

by read2 min views1 publishedOct 19, 2026

Follow-up is where property leads are won, and where bots turn into spam. The difference is almost always the stop rules. This post shows a small scheduler pattern for AI automation for real estate agencies with follow-up timers that stop: a data model, a sequence, the stop logic, and a worker loop.

One row per lead in an active sequence.

from dataclasses import dataclass
from datetime import datetime
from typing import Optional

@dataclass
class FollowUp:
    lead_id: str
    agent_id: str
    step: int                  # 0 = first reply already sent
    next_at: datetime
    status: str                # "active" | "d" | "stopped"
    stop_reason: Optional[str] = None

Keep it short and explicit. Each step says what kind of message it is, because that decides who sends it.

SEQUENCE = [
    {"after_hours": 2,   "kind": "agent_draft"},      # AI drafts, agent sends
    {"after_hours": 48,  "kind": "template_nudge"},   # pre-approved template
    {"after_hours": 120, "kind": "related_listing"},  # pre-approved template
]
php
def should_stop(lead, last_msg) -> Optional[str]:
    if last_msg and last_msg.from_lead:
        return "replied"            # a human takes over, timers end
    if lead.status in ("not_interested", "bought_elsewhere", "under_offer"):
        return "closed"
    if lead.opted_out:
        return "opt_out"
    if lead.step >= len(SEQUENCE):
        return "sequence_done"
    return None

A reply from the lead always stops automation and alerts the agent. That single rule prevents most of the embarrassing cases, like a nudge arriving an hour after the buyer booked a viewing.

def tick(now):
    for f in due_followups(now):
        lead = get_lead(f.lead_id)
        reason = should_stop(lead, last_message(f.lead_id))
        if reason:
            stop(f, reason)
            continue
        step = SEQUENCE[f.step]
        if step["kind"] == "agent_draft":
            queue_for_agent(f, draft_from_history(f.lead_id))
        else:
            send_template(f, step["kind"])
        advance(f)   # step += 1, compute next_at from the next step

Run tick from a scheduler every few minutes. Make advance and stop atomic with the send, or use an outbox table, so a crash cannot send the same nudge twice.

next_at to sensible local hours for the lead, not the server. Disclosure: I co-founded NxFlowAI (Mumbai). When we scope a follow-up workflow like this, the first audit takes 72 hours.

── more in #ai-agents 4 stories · sorted by recency
── more on @nxflowai 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/follow-up-timers-for…] indexed:0 read:2min 2026-10-19 · —