Data workflows

Triage a Real Estate Lead List with Claude and the Zillow MCP Server

Sort inbound real estate leads by current Zillow listing status in one Claude session: strip the CRM export, set the rules, run one MCP batch and review unclear rows.

8 min read

Why triage a lead list with Claude

A busy agent or inside-sales team gets more inquiries than it can call back the same day: valuation requests from a website form, buyers who paste a Zillow link, old contacts pulled back out of the CRM. Before anyone picks up the phone, the useful question is plain: what is happening with this property right now? Is it already listed with another brokerage, did it sell recently, is it a rental, or is it sitting off market?

Claude, connected to the PropertiesAPI MCP server, can answer that for a whole list in one conversation. It reads each home's current Zillow listing status and a few supporting fields, then sorts the leads into buckets you define. This article covers that sorting job: the rules, the prompt, the batch call, the review, and how to write the result back without letting a chat transcript become your system of record. Connection steps live on the MCP server overview, and a session that compares a shortlist of homes is covered in a separate walkthrough.

Strip the lead list down to property identifiers

A CRM export carries names, phone numbers, emails and free-text notes. None of that is needed to look up a property, and none of it belongs in a chat. Export two columns only: the lead ID and the property identifier. Use the Zillow link when the lead sent one; otherwise use the full street address with city and state or ZIP. The lead ID is what lets you join the answer back to the CRM later, so keep it on every row.

Links beat addresses. A Zillow link names exactly one home, while an address has to be matched first, and a match can land on a neighboring house or a different unit. If your form asks for a unit or apartment number, keep it in the address column rather than in a separate field the lookup never sees.

leads-for-claude.csv (illustrative placeholders, no personal data)
lead_id,property
L-1041,https://www.zillow.com/homedetails/<home-a>_zpid/
L-1042,"2640 Steiner St, San Francisco, CA 94115"
L-1043,https://www.zillow.com/homedetails/<home-b>_zpid/
L-1044,"742 Evergreen Ter, Springfield, IL 62704"
L-1045,"<street> APT <unit>, <city>, <state> <zip>"

Write the triage rules before you ask

The model should apply your rules, not invent them. Decide the buckets up front and tie each one to a field the tools return. homeStatus is the main signal and uses Zillow's own values, such as FOR_SALE, PENDING, COMING_SOON, FORECLOSURE, RECENTLY_SOLD, SOLD, FOR_RENT, OTHER and OFF_MARKET. A home that isn't listed usually comes back as OTHER, not OFF_MARKET, so the off-market bucket must accept both. Supporting fields explain the bucket: brokerName for a listed home, dateSold and lastSoldPrice for a recent sale, daysOnZillow for how long a listing has been up.

Keep one bucket for answers that need a person. An address that matched a different home, an address with no match at all, and a home whose status is missing all go there, and the table should say which of the three it was.

BucketRule, read from the responseSuggested next step
Listed elsewherehomeStatus is FOR_SALE, PENDING, COMING_SOON or FORECLOSURENote brokerName and follow your brokerage's rules for homes listed with another agent
Recently soldhomeStatus is RECENTLY_SOLD or SOLDCompare dateSold with the inquiry date before calling
RentalhomeStatus is FOR_RENTRoute to the rentals or property-management team
Off markethomeStatus is OTHER or OFF_MARKETA possible listing conversation; call first
Needs reviewan error such as address_ambiguous or not_found, homeStatus is null, or any value not listed aboveA person confirms the property before anyone calls

The prompt that runs the triage

Paste the rules and the stripped list into one message. Ask Claude to check credits first, look the whole list up in one batch, and return one row per lead ID, including the leads it could not classify. Asking for the field values next to each bucket keeps every decision checkable, and asking for missing values to be written as missing stops a null from turning into a guess.

Prompt (illustrative)
You are triaging inbound real estate leads. Use only the PropertiesAPI tools.

1. Call get_usage and tell me how many credits are left before any lookup.
2. Look up every property below with one get_zillow_properties call.
3. Put each lead in exactly one bucket:
     Listed elsewhere  homeStatus FOR_SALE, PENDING, COMING_SOON or FORECLOSURE
     Recently sold     homeStatus RECENTLY_SOLD or SOLD
     Rental            homeStatus FOR_RENT
     Off market        homeStatus OTHER or OFF_MARKET
     Needs review      any error, homeStatus null, or any other value
4. Return a table: lead_id, bucket, homeStatus, price, daysOnZillow, brokerName,
   dateSold, detailUrl, meta.fetched_at, and the error code if there is one.
5. Never guess a status. Write "missing" for any null value.

L-1041  https://www.zillow.com/homedetails/<home-a>_zpid/
L-1042  2640 Steiner St, San Francisco, CA 94115
L-1043  https://www.zillow.com/homedetails/<home-b>_zpid/
L-1044  742 Evergreen Ter, Springfield, IL 62704
L-1045  <street> APT <unit>, <city>, <state> <zip>

What Claude calls, and what comes back

A well-behaved run makes two tool calls. get_usage is free and runs no lookup, so it is the right first step before a batch. get_zillow_properties then takes the whole list, up to 50 items per call, and returns one result per item in the same order, each marked ok or not. One item failing doesn't fail the others.

The batch's own meta says how the run went: count, succeeded, failed, cache_hits and credits. If the account runs out of credits part-way, the remaining items come back as credits_exhausted and are listed in meta.credits_exhausted. If the per-minute limit runs out, meta.rate_limited lists the affected items with a retry_after. Ask Claude to report both lists rather than quietly dropping rows, because a lead that silently disappears from the table is worse than one marked for review.

Tool calls in the run (illustrative)
get_usage {}
  -> plan, credits used and credits left (no lookup, no credit)

get_zillow_properties {
  "items": [
    "https://www.zillow.com/homedetails/<home-a>_zpid/",
    "2640 Steiner St, San Francisco, CA 94115",
    "https://www.zillow.com/homedetails/<home-b>_zpid/",
    "742 Evergreen Ter, Springfield, IL 62704",
    "<street> APT <unit>, <city>, <state> <zip>"
  ]
}
  -> { data: [
       { index: 0, ok: true,  data: { homeStatus, price, daysOnZillow, brokerName, ... },
                              meta: { cached, credits, fetched_at } },
       { index: 1, ok: false, error: { code: "address_ambiguous", message,
                              details: { candidate: { detailUrl } } } },
       ...
     ],
     meta: { count, succeeded, failed, cache_hits, credits } }

Review the buckets before anyone picks up the phone

Read the Needs review rows first. For address_ambiguous, the error carries Zillow's closest match as a link. Open it and decide whether it is the home the lead meant. If it is, ask Claude to look that link up with get_zillow_property and move the lead to the right bucket. If it isn't, go back to the lead for a unit number or ZIP code. A not_found answer usually means a typo or an incomplete address. None of these failures is billed.

Then spot-check the confident rows. Open a few detailUrl links and confirm that the status Claude reported matches the Zillow page. Check meta.fetched_at as well: a cached answer is an earlier observation, and a listing can change status between collection and your call.

Be clear about what the buckets cannot tell you. The tools don't return owner names or contact details, they don't search a neighborhood for other homes, and a Zestimate is Zillow's estimate, not an appraisal. Treat the triage as a routing aid for your own team's follow-up, never as a judgement about the person who sent the inquiry.

Write the result back to the CRM, not the chat

A chat transcript is a poor system of record. Ask Claude for the final table as CSV with the lead ID first, then import it into a separate set of CRM fields: a property status, a triage bucket and a checked-at timestamp taken from meta.fetched_at. Keep those apart from the fields your team types by hand, so a later lookup never overwrites a note an agent wrote.

When the same triage runs every morning, move it out of the chat. The rules above translate directly into a short script against the batch endpoint, and the CRM enrichment guide shows a merge policy that keeps API observations and team-entered facts in separate columns.

triage.csv returned by Claude (illustrative)
lead_id,bucket,homeStatus,price,daysOnZillow,brokerName,dateSold,detailUrl,fetched_at,error
L-1041,Listed elsewhere,FOR_SALE,<price>,<days>,<broker>,missing,https://www.zillow.com/homedetails/<home-a>_zpid/,<fetched_at>,
L-1042,Needs review,missing,missing,missing,missing,missing,missing,missing,address_ambiguous
L-1043,Off market,OTHER,missing,missing,missing,<date>,https://www.zillow.com/homedetails/<home-b>_zpid/,<fetched_at>,

What a triage run costs

The MCP tools bill exactly like the REST API. Zillow links and addresses cost the same: 1 credit per successful lookup. Repeat lookups of the same home within 24 hours come from our cache and are free. A lead that comes back the next morning inside that window costs nothing to re-check. Failed items, including address_ambiguous and not_found, cost nothing, and get_usage is free.

A live lookup takes typically 8 seconds, up to about 20, and a full batch can take minutes, so a long list moves more slowly in chat than in a script. Split a list longer than the batch limit into several calls, and ask Claude to say which call each lead was in so a partial run is easy to resume.

Validation scope: the tool names, arguments, result shapes, error codes and billing rules in this article were checked against the MCP server's published tool definitions and the batch endpoint documentation. The lead list, prompt output and tables are illustrative and use placeholders rather than real homes or people.

Sources and documentation

Product details checked against the linked documentation on October 22, 2026. Code and sample inputs are illustrative unless stated otherwise.

Written by PropertiesAPI, an independent property data service. We are not affiliated with Zillow. Source data may be incomplete or change over time.