I maintain Foreclosure Finder, a paid API on RapidAPI with a free evaluation plan. This walkthrough shows how to turn a location search into a small CSV watchlist. The same pattern works for other APIs that return a meta object and a listings array.
Disclosure: this article was prepared with AI assistance. The example search was checked against the live RapidAPI service.
We'll search within 25 miles of ZIP 30067, keep single-family homes with at least three bedrooms, and filter for advertised prices or opening bids from $50,000 to $250,000. We'll export the first 100 matching listings, cheapest first, with links back to the sources.
Foreclosure Finder combines Auction.com, HUD HomeStore, Fannie Mae HomePath, Freddie Mac HomeSteps, and Redfin. Their inventory and fields differ, so the useful output is a shortlist to inspect, not a claim that every row is an available bargain. Auction.com can include private-seller listings; inspect assetType and status if your workflow requires strictly foreclosure or bank-owned inventory.
Subscribe to Foreclosure Finder on RapidAPI. BASIC includes 300 requests per month. The search below uses free-tier fields. PRO is $10/month for 10,000 requests and the full data fields.
Save your key as an environment variable, rather than writing it into a script you might share:
export RAPIDAPI_KEY='YOUR_KEY'
On Windows PowerShell:
$env:RAPIDAPI_KEY = 'YOUR_KEY'
This uses Python's standard library; no packages to install. Save it as watchlist.py and run python watchlist.py.
import csv
import json
import os
import urllib.error
import urllib.parse
import urllib.request
host = "foreclosure-finder1.p.rapidapi.com"
params = {
"zipcode": "30067",
"radius": 25,
"minPrice": 50000,
"maxPrice": 250000,
"minBeds": 3,
"propertyType": "SINGLE_FAMILY_HOME",
"sort": "price_asc",
"limit": 100,
}
url = f"https://{host}/zipcode/all?{urllib.parse.urlencode(params)}"
request = urllib.request.Request(url, headers={
"X-RapidAPI-Key": os.environ["RAPIDAPI_KEY"],
"X-RapidAPI-Host": host,
})
try:
with urllib.request.urlopen(request, timeout=65) as response:
result = json.load(response)
except urllib.error.HTTPError as error:
raise SystemExit(f"API request failed with HTTP {error.code}")
except urllib.error.URLError as error:
raise SystemExit(f"Could not reach the API: {error.reason}")
meta = result.get("meta", {})
if meta.get("failedSources"):
raise SystemExit(
"Partial source failure; keep the previous watchlist and retry: "
+ ", ".join(meta["failedSources"])
)
rows = result.get("listings", [])
columns = [
"source", "listingId", "address", "openingBid", "bedrooms",
"bathrooms", "assetType", "status", "propertyLink",
]
def safe_cell(value):
if isinstance(value, str) and value.lstrip().startswith(("=", "+", "-", "@")):
return "'" + value
return value
with open("watchlist.csv", "w", newline="", encoding="utf-8") as output:
writer = csv.DictWriter(output, fieldnames=columns)
writer.writeheader()
writer.writerows({key: safe_cell(row.get(key)) for key in columns} for row in rows)
print(f"Saved {len(rows)} of {meta.get('totalCount', len(rows))} matches to watchlist.csv")
An empty successful search writes a header-only CSV. A partial source failure stops before replacing your previous file, so a source outage doesn't silently look like disappearing inventory.
limit=100 exports one page. If meta.totalCount exceeds 100, fetch additional pages with offset=100, offset=200, and so on; each page uses another request. Rerunning this example replaces the file with the latest snapshot, so save dated copies if you want history.
zipcode and radius with your target area.sources=hud,fanniemae,freddiemac if you only want those sources./city/all?state=MI&city=detroit for a city search./listing/{source}/{listingId} for a full listing record, including photos, description, facts, and available contact information. Each detail lookup uses another request.
The API also supports format=csv if you want it to produce the spreadsheet directly. I used JSON here to show how to inspect source failures and select your output columns.
openingBid is the common price field. For an auction it can be an opening bid, not the current high bid or final purchase price. On other sources it generally represents the advertised asking price. Check source, assetType, status, and the linked listing before treating a row as actionable.
Search results are fetched on demand and cached for one hour. Running the same query every minute doesn't provide minute-by-minute market updates. Listing counts change, and source sites can be unavailable.
Paid plans include Auction.com bid data, valuation and rental estimates where supplied, plus calculated discount and yield fields. Those are screening inputs, not guaranteed investment returns.
Try one ZIP you already know, compare a few rows with their source pages, and then decide whether it fits your workflow.
Open the live demo and setup guides.
What would make a watchlist useful in your application: scheduled snapshots, listing details, or notifications about changes?