Watchlists and alerts

Watch homes by Zillow link, zpid or address. Each one is checked about once a day, and you get an event when its price, status, Zestimate, photos or rent Zestimate change: by signed webhook, a daily email, or the API.

Coming soon. Until watchlists launch, the endpoints below answer 404 watchlists_disabled.

Billing and limits

Each daily check of a watched home is a lookup: 1 credit, or free when the home comes from the 24-hour cache. Checks use your lookups like any other call (included, then prepaid credits, then usage past your plan) and pause when they run out.

PlanWatched homes
FreeWatchlists (coming soon): up to 5 homes
StarterWatchlists (coming soon): up to 50 homes
ProWatchlists (coming soon): up to 200 homes
BusinessWatchlists (coming soon): up to 1,000 homes
ScaleWatchlists (coming soon): up to 3,000 homes

The limit counts every home on all your watchlists, paused ones included. Adding a home past it returns 403 watch_limit_reached before any lookup, so it costs nothing.

How checks work

  • Watched homes are checked about once a day. There is no guaranteed time of day.
  • Each check is a lookup through the same gate as the API: 1 credit when it runs live, free when the home comes from the 24-hour cache. Checks use your plan's lookups, its spending limit and the service's daily limits.
  • When your lookups or your optional spending limit run out, checks pause and the dashboard says why. Nothing is billed while paused. We try again about every 6 hours, and you can resume at once with POST /watchlists/resume.
  • A check compares the home with its last snapshot: price, status, Zestimate, rent Zestimate and photo count. Only those fields are kept.
  • Paused homes and paused watchlists aren't checked. After a downgrade, homes past the new plan's limit aren't checked until you remove some.
  • Events are kept for the dashboard and GET /watchlists/events. With a webhook URL set, each event is also sent to it; with the email digest on, you get one email a day listing the day's events.

Events

TypeWhen
price_changeThe price moved by at least the watchlist's price_change_pct (default 0: any change). A change between a rent and a sale price isn't counted.
status_changeThe status moved between for_sale, pending, sold, off_market and for_rent. An unclear status never fires it.
zestimate_changeThe Zestimate moved by at least zestimate_change_pct (default 1).
new_photosThe photo count went up.
rent_changeThe rent Zestimate moved by at least rent_change_pct (default 0: any change).

Endpoints

Base https://api.propertiesapi.com/v1, with your key in the x-api-key header. The same watchlists are on your dashboard.

MethodPathWhat it does
GET/watchlistsYour watchlists, each with its home_count.
POST/watchlistsCreate a watchlist.
GET/watchlists/{id}One watchlist with its homes: each home's zpid, address, last snapshot, last check and result.
PATCH/watchlists/{id}Change its name, thresholds or events, or pause it with { "paused": true }.
DELETE/watchlists/{id}Delete the watchlist and stop watching its homes.
POST/watchlists/{id}/homesWatch a home by url, zpid or address. It is looked up now (a normal lookup: 1 credit, free from the cache) to find the home and record its first snapshot. Or send { "items": [...] } with up to 25 links, zpids or addresses. An apartment building (a zillow.com/apartments/ link) is watched by its link: its zpid is null. If an address turns out to be a home the list already watches, the answer is 200 with meta.already_watched and that watch.
PATCH/watchlists/{id}/homes/{homeId}Pause or resume one home with { "paused": true | false }.
DELETE/watchlists/{id}/homes/{homeId}Stop watching a home.
GET/watchlists/eventsRecent events (newest first), ?limit= up to 500.
GET/watchlists/settingsYour watched-home count and limit, whether checks are paused and why, the webhook URL and the email digest setting.
PATCH/watchlists/settingsSet the webhook URL (https only, or null to remove it) and turn the daily email digest on or off.
POST/watchlists/settings/secretCreate or rotate the webhook signing secret. It is shown in this response only.
GET/watchlists/deliveriesThe webhook delivery log: status, attempts, last HTTP status and error code for each event sent.
POST/watchlists/resumeResume checks that paused because your lookups or your spending limit ran out.
Create a watchlist
curl "https://api.propertiesapi.com/v1/watchlists" -H "x-api-key: $PROPERTIESAPI_KEY" \
  -H "content-type: application/json" \
  -d '{"name":"Austin flips","price_change_pct":2}'
Watch a home
curl "https://api.propertiesapi.com/v1/watchlists/wl_.../homes" -H "x-api-key: $PROPERTIESAPI_KEY" \
  -H "content-type: application/json" \
  -d '{"url":"https://www.zillow.com/homedetails/.../12345_zpid/"}'

Webhooks

  • Each event is a POST of JSON to your https webhook URL: { id, type, created_at, data: { watchlist_id, home_id, zpid, address, detail_url, old, new, change, change_pct } }. type is watch.<event type>, e.g. watch.price_change.
  • X-PropertiesAPI-Event-Id is the event id, the same on every retry: use it to ignore duplicates.
  • X-PropertiesAPI-Signature is t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>" with your signing secret>. Check it against the raw body and refuse timestamps older than 5 minutes.
  • Answer with any 2xx status. Anything else, or no answer within 10 seconds (DNS included), is retried after about 1 minute, 5 minutes, 30 minutes, 2 hours and 6 hours, then marked failed in the delivery log.
  • An endpoint that answers slowly (5 seconds or more) or fails is backed off: your other events wait, starting at 1 minute and doubling on each slow or failed answer, up to 6 hours. A fast 2xx resets it. Events go out in the order they happened, at most 2 at a time per account.
  • The URL must be https on port 443 (or 8443) and point to a public internet address. Private, loopback, link-local and cloud metadata addresses are refused when you save it, and again before every delivery and every redirect.
Set the webhook and get its secret
curl -X PATCH "https://api.propertiesapi.com/v1/watchlists/settings" -H "x-api-key: $PROPERTIESAPI_KEY" \
  -H "content-type: application/json" \
  -d '{"webhook_url":"https://example.com/hooks/propertiesapi"}'
curl -X POST "https://api.propertiesapi.com/v1/watchlists/settings/secret" -H "x-api-key: $PROPERTIESAPI_KEY"   # shown once
Webhook body (illustrative)
{
  "id": "evt_0000000000000000",
  "type": "watch.price_change",
  "created_at": "2026-10-21T14:05:00.000Z",
  "data": {
    "watchlist_id": "wl_0000000000000000",
    "home_id": "wh_0000000000000000",
    "zpid": "0000000",
    "address": "1600 Main St, Austin, TX 78701",
    "detail_url": "https://www.zillow.com/homedetails/1600-Main-St-Austin-TX-78701/0000000_zpid/",
    "old": 525000,
    "new": 510000,
    "change": -15000,
    "change_pct": -2.86
  }
}
Verify the signature (Node)
import { createHmac, timingSafeEqual } from "node:crypto";

// rawBody: the request body exactly as received (a string), secret: your whsec_ signing secret
export function verify(rawBody, header, secret) {
  const m = /^t=(\d+),v1=([0-9a-f]{64})$/.exec(header ?? "");
  if (!m) return false;
  if (Math.abs(Date.now() / 1000 - Number(m[1])) > 300) return false; // older than 5 minutes
  const want = createHmac("sha256", secret).update(`${m[1]}.${rawBody}`).digest("hex");
  return timingSafeEqual(Buffer.from(want), Buffer.from(m[2]));
}

Daily email

Turn on the email digest on your dashboard or with PATCH /watchlists/settings. You get at most one email a day, from login@propertiesapi.com, listing the changes found since the last one. No changes, no email.

Errors

StatusCodeWhen
400bad_paramA name outside 1-80 characters, a threshold outside 0-100, an unknown event type, or a url / zpid / address the lookup would refuse.
400bad_webhook_urlThe webhook URL isn't https, has a user name or password, uses another port, doesn't resolve, or points to a private address. details.reason says which.
402credits_exhaustedAdding a home needs a lookup and your lookups are used up (as for GET /v1/zillow/property). Not billed.
403account_requiredThe key isn't a dashboard key from an account.
403watch_limit_reachedYour plan's watched-home limit is reached (details.limit, details.plan, details.upgrade_url). Checked before any lookup: not billed.
403too_many_watchlistsAn account can have up to 20 watchlists.
404not_foundNo such watchlist or watched home on your account.
404watchlists_disabledWatchlists aren't available yet.
409already_watchedThat watchlist already watches this home (the same zpid, link or address). Checked before any lookup: not billed.

Other errors are the same as for every v1 call. See errors.

Data is provided as-is, as shown on public Zillow pages at the time of each check, without any guarantee of accuracy or completeness. Zillow is a trademark of Zillow, Inc. PropertiesAPI is an independent service and is not affiliated with, endorsed by or sponsored by Zillow.