For CRM enrichment

Zillow data for CRM and lead enrichment

Your leads and deals already carry a property address. Add the home's Zillow listing status, price, Zestimate and days on market to each record, send unclear addresses to a person, and refresh the fields on a schedule.

The job

Lenders, insurers' agencies, home service companies and brokerages all collect a property address with a lead. Whether that home is listed for sale, how long it has been on the market and roughly what it is worth changes how you prioritize the lead and what you say first.

The job is plain enrichment: read the address from each record, look up the home, write a few fields back, and never overwrite good data with a bad match. The example below does that with an export file; the same logic fits a CRM webhook or a nightly sync.

The workflow

  1. Export or receive records. Pull the records that have a full property address (street, city and state or ZIP) from your CRM's API, a webhook or an export file.
  2. Batch the addresses. Send up to 50 addresses per batch request. Store the returned detailUrl so future refreshes look the home up by link.
  3. Write back only confident matches. Write fields for ok results. Send address_ambiguous to a review queue with the closest match's link, and leave not_found records untouched.
  4. Refresh on a schedule. Re-run weekly or when a deal changes stage. Status changes such as FOR_SALE to PENDING are often the signal your team wants.

Enrich an export of leads

Node.js. Reads leads.json (id and address per lead), batches the lookups and writes enriched.json plus review.json for addresses a person should check.

JavaScript (Node.js)
import { readFileSync, writeFileSync } from "node:fs";

const BASE = "https://api.propertiesapi.com/v1";
const leads = JSON.parse(readFileSync("leads.json", "utf8")); // [{ id, address }, ...]
const enriched = [], review = [];

for (let i = 0; i < leads.length; i += 50) {
  const chunk = leads.slice(i, i + 50);
  const res = await fetch(`${BASE}/zillow/batch`, {
    method: "POST",
    headers: { "x-api-key": process.env.PROPERTIESAPI_KEY, "content-type": "application/json" },
    body: JSON.stringify({ items: chunk.map((l) => ({ address: l.address })) }),
    signal: AbortSignal.timeout(320_000),
  });
  const body = await res.json();
  if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);

  for (const r of body.data) {
    const lead = chunk[r.index];
    if (r.ok) {
      const h = r.data;
      enriched.push({
        id: lead.id,
        zillow_url: h.detailUrl,
        listing_status: h.statusText ?? h.homeStatus,
        list_price: h.price,
        zestimate: h.zestimate,
        days_on_market: h.calculated.days_on_market,
        listing_agent: h.agentName,
        listing_broker: h.brokerName,
      });
    } else if (r.error.code === "address_ambiguous") {
      review.push({ id: lead.id, address: lead.address, closest_match: r.error.details?.candidate?.detailUrl ?? null });
    }
  }
}
writeFileSync("enriched.json", JSON.stringify(enriched, null, 2));
writeFileSync("review.json", JSON.stringify(review, null, 2));

Fields that matter here

Response fields for crm and lead enrichment
FieldWhy it matters
homeStatus, statusTextWhether the home is for sale, pending, for rent, sold or off market.
price, zestimateThe listing price when listed, and Zillow's Zestimate when shown.
calculated.days_on_marketHow long the current listing has been up. Null when the home isn't listed.
agentName, brokerNameThe listing agent and brokerage on the listing, when it names them.
detailUrlThe Zillow page. Save it so the next refresh uses the link instead of the address.

What it won't do

  • No owner names, phone numbers or emails for the property's owner, and no skip tracing. Agent and broker fields come from the listing.
  • No search for new leads; it enriches records you already have.
  • Not for credit, insurance, employment or tenant decisions covered by the FCRA.
  • The data is what the public Zillow page shows, provided as-is.

CRM and lead enrichment: questions

Which CRMs does this work with?+

Any CRM you can read addresses from and write fields back to, through its API, a webhook, an automation tool or an export. The API itself doesn't connect to your CRM.

What happens with a partial or messy address?+

An address without a house number or without a city and state or ZIP is rejected before any lookup, for free. A full address whose closest Zillow match is a different home comes back as address_ambiguous with that home's link.

How often should I refresh?+

As often as status changes matter to you. Repeat lookups of the same home within 24 hours come from our cache and are free. Weekly refreshes of open deals are a common starting point.

What does enrichment cost?+

Zillow links and addresses cost the same: 1 credit per successful lookup. Failed and ambiguous lookups cost nothing. You start with 50 free lookups.

Try it on your own list

50 free lookups, no card, no approval.

Zillow is a trademark of Zillow, Inc. PropertiesAPI is an independent service and is not affiliated with, endorsed by or sponsored by Zillow.