REALTOR APIrealtor.ca ↗
Search and retrieve Canadian real estate listings from REALTOR.ca. Get MLS data, property details, photos, pricing, agent info, and pagination via 2 endpoints.
What is the REALTOR API?
The REALTOR.ca API provides access to Canadian MLS property listings through 2 endpoints: search_listings for geographic bounding-box searches with price, bedroom, and sort filters, and get_listing_details for full property data on a specific MLS number. Responses include structured fields for price, address, bedrooms, bathrooms, parking, agent contacts, brokerage details, and multi-resolution photo URLs.
curl -X GET 'https://api.parse.bot/scraper/74c62a3e-07d2-4eb2-a736-d1542f09450d/search_listings?price_max=3000000&price_min=1000000&bedrooms_min=3¤t_page=1&latitude_max=43.85&latitude_min=43.45&longitude_max=-79.00&longitude_min=-79.76&records_per_page=10&property_type_group_id=1&property_search_type_id=1&sort=6-D&transaction_type_id=2' \ -H 'X-API-Key: $PARSE_API_KEY'
Typed, relational, agent-ready
A generated client with real types, enums, and the links between objects — the structure a flat JSON response can't carry. Autocompletes in your editor and reads cleanly to coding agents.
- Fully typed · autocompletes
- Objects link to objects
- Typed errors & pagination
Typed Python client. Set up the SDK in your uv project, then pull this API’s typed client:
uv add parse-sdk uv run parse init uv run parse add --marketplace realtor-ca-api
uv run parse add --marketplace pulls a pinned snapshot of this canonical API — it won’t change underneath you. To customize it, subscribe and swap to your own copy.
"""Walkthrough: REALTOR.ca SDK — search listings, drill into details, handle errors."""
from parse_apis.realtor_ca_property_listings_api import RealtorCa, Sort, TransactionType, ListingNotFound
client = RealtorCa()
# Search for residential listings in Toronto area, sorted by price ascending.
for listing in client.listings.search(
latitude_max="43.85",
longitude_max="-79.00",
latitude_min="43.45",
longitude_min="-79.76",
price_min="1000000",
price_max="3000000",
sort=Sort.PRICE_ASC,
transaction_type_id=TransactionType.FOR_SALE,
limit=3,
):
print(listing.address, listing.price, listing.bedrooms, listing.building_type)
# Drill into one listing for full details.
first = client.listings.search(
latitude_max="43.70",
longitude_max="-79.30",
latitude_min="43.60",
longitude_min="-79.50",
sort=Sort.NEWEST,
limit=1,
).first()
if first:
detail = client.listings.get(mls_number=first.mls_number)
print(detail.price, detail.address, detail.parking_spaces)
for agent in detail.agents:
print(agent.name, agent.position, agent.brokerage.name)
# Typed error handling for an expired MLS number.
try:
client.listings.get(mls_number="X00000000")
except ListingNotFound as exc:
print(f"Listing gone: {exc}")
print("exercised: listings.search / listings.get / ListingNotFound")Search for property listings within a geographic bounding box with price and property filters. Returns paginated results ordered by the sort parameter. The bounding box coordinates define the search area; omitting them searches across all of Canada. Each listing in the response carries an mls_number usable with get_listing_details for full property information.
| Param | Type | Description |
|---|---|---|
| sort | string | Sort order for results |
| price_max | string | Maximum price filter. Omitting returns all prices above price_min. |
| price_min | string | Minimum price filter |
| bedrooms_min | string | Minimum number of bedrooms. Omitting returns all bedroom counts. |
| current_page | integer | Page number for pagination (1-based) |
| latitude_max | string | Maximum latitude of search bounding box |
| latitude_min | string | Minimum latitude of search bounding box |
| longitude_max | string | Maximum longitude of search bounding box |
| longitude_min | string | Minimum longitude of search bounding box |
| building_type_id | string | Building type filter ID. Omitting returns all building types. |
| records_per_page | string | Number of results per page (max 50) |
| transaction_type_id | string | Transaction type filter |
| property_type_group_id | string | Property type group: 1 (residential) |
| property_search_type_id | string | Property search type: 1 (residential), 0 (all) |
{
"type": "object",
"fields": {
"listings": "array of listing objects with id, mls_number, url, address, price, bedrooms, bathrooms, photos, agents, and more",
"pagination": "object containing current_page, total_pages, total_records, records_per_page, records_showing"
}
}About the REALTOR API
Search Listings by Geography and Filters
The search_listings endpoint accepts a geographic bounding box defined by latitude_min, latitude_max, and longitude_max (along with implied longitude minimum) to return MLS listings within that area. You can narrow results with price_min, price_max, and bedrooms_min, and control ordering with the sort parameter — 6-D for price descending, 6-A for price ascending, or 1-A for newest first. Pagination is handled via current_page, and every response includes a pagination object with current_page, total_pages, total_records, and records_per_page so you can walk through large result sets.
Listing Detail Fields
The get_listing_details endpoint takes a single required input — property_id, which is an MLS number such as W13040146 — and returns a full property record. That record includes price (formatted with currency symbol), address, bedrooms, stories, parking (as an array of type strings), photos with high_res, med_res, and low_res URL variants, and media as an array of typed media objects. Agent data comes back as an array under agents, with each entry containing name, position, phones, and brokerage details.
MLS Number Lifecycle
MLS numbers are tied to active listings and expire when a property is removed from the market. Passing an expired or invalid property_id to get_listing_details returns a stale_input response with kind input_not_found rather than an error. For any production use, MLS numbers should be sourced from fresh search_listings results via results[*].mls_number to minimize stale lookups.
Coverage Scope
The API covers publicly listed properties across Canada on REALTOR.ca, including residential listings with bedroom, bathroom, parking, and multi-resolution photo data. Listing URLs are returned in both endpoints, pointing directly to the canonical REALTOR.ca page for each property.
The REALTOR API is a managed, monitored endpoint for realtor.ca — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when realtor.ca changes and a check fails, the API is automatically queued for repair and re-verified. It is built to keep working as the site underneath it changes.
This isn't an official realtor.ca API — it's an independent, maintained REST wrapper over public data. Where the source has no official API (or only a limited one), Parse gives you a stable contract over a source that never promised one, and keeps it current. Need a new endpoint or field? You can revise it yourself in plain English and the agent rebuilds it against the live site in minutes — contributing the change back to the shared API is free.
Will this API break when the source site changes?+
Is this an official API from the source site?+
Can I fix or extend this API myself if I need a new endpoint or field?+
What happens if I call an endpoint that has an issue?+
- Build a Canadian property search map using bounding-box coordinates and price filters from
search_listings - Display MLS listing cards with multi-resolution photos and formatted price from
get_listing_details - Track agent and brokerage contact details for lead generation or CRM enrichment
- Monitor new listings in a target area by polling
search_listingssorted by1-A(newest first) - Filter properties by minimum bedroom count and maximum price for a buyer-facing search tool
- Paginate through large metropolitan result sets using the
pagination.total_pagesfield - Build a listing detail page with parking type arrays, stories, and full agent phone data
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 100 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
One credit = one API call regardless of which marketplace API you call. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.
Does REALTOR.ca have an official developer API?+
What does `search_listings` return beyond basic price and address?+
total_records and total_pages so you can iterate through result sets page by page.What happens when I request details for a listing that has been sold or removed?+
get_listing_details endpoint returns a stale_input response with kind input_not_found for any MLS number that is expired or invalid. To reduce stale lookups, always source property_id values from recent search_listings results rather than storing MLS numbers long-term.