Quickstart
Authenticate, discover the RESO service, query Property, and follow continuation pages
This quickstart uses the RESO Web API from discovery through synchronization.
It covers the public contract that is ready for integration: the service
document, $metadata, the Property collection, direct key retrieval, and
opaque continuation paging.
Use placeholders in development
The hostname and API key below are examples. Every production request is scoped by the signed entitlement associated with the supplied key.
Configure authentication
export REALTY_API_KEY="<issued-api-key>"
export REALTY_API_BASE="https://api.example.invalid"const baseUrl = "https://api.example.invalid";
const headers = { "x-api-key": process.env.REALTY_API_KEY! };import os
import requests
base_url = "https://api.example.invalid"
headers = {"x-api-key": os.environ["REALTY_API_KEY"]}Discover active resources
curl --request GET \
--url "$REALTY_API_BASE/reso/odata" \
--header "x-api-key: $REALTY_API_KEY" \
--header "Accept: application/json"The service document is the activation authority. Only request entity sets
listed in its value array.
{
"@odata.context": "https://api.example.invalid/reso/odata/$metadata",
"value": [
{ "name": "Property", "kind": "EntitySet", "url": "Property" }
]
}Inspect the schema
Fetch $metadata before generating queries or typed clients. It is the
authoritative field, type, nullability, key, and entity-set contract.
curl --request GET \
--url "$REALTY_API_BASE/reso/odata/\$metadata" \
--header "x-api-key: $REALTY_API_KEY" \
--header "Accept: application/xml"The searchable Property field catalog provides the same implemented field inventory in a human-friendly form.
Query a compact Property page
Start with $select, a bounded $top, and a deterministic order. Use
$filter for RESO field criteria.
curl --get \
--url "$REALTY_API_BASE/reso/odata/Property" \
--header "x-api-key: $REALTY_API_KEY" \
--header "Accept: application/json" \
--data-urlencode '$select=ListingKey,ListingId,OriginatingSystemName,StandardStatus,ListPrice,ModificationTimestamp' \
--data-urlencode '$filter=StandardStatus eq '\''Active'\''' \
--data-urlencode '$orderby=ModificationTimestamp asc,ListingKey asc' \
--data-urlencode '$top=100' \
--data-urlencode '$ignorenulls=true'{
"@odata.context": "https://api.example.invalid/reso/odata/$metadata#Property",
"value": [
{
"ListingKey": "listing-key-01",
"ListingId": "A1234567",
"OriginatingSystemName": "ExampleMLS",
"StandardStatus": "Active",
"ListPrice": 725000,
"ModificationTimestamp": "2026-07-22T14:30:00Z"
}
],
"@odata.nextLink": "https://api.example.invalid/reso/odata/Property?...&$skiptoken=OPAQUE"
}Follow continuation pages
When @odata.nextLink is present, request that URL exactly as returned.
Do not decode, edit, or combine its $skiptoken with $skip. The absence
of @odata.nextLink means the result set is complete.
let next: string | undefined = `${baseUrl}/reso/odata/Property?$top=100`;
while (next) {
const page = await fetch(next, { headers }).then((response) => response.json());
await consume(page.value);
next = page["@odata.nextLink"];
}Choose the correct identity query
A Placekey identifies a physical property and may group many listing records. A ListingKey identifies one RESO Property record.
GET /reso/odata/Property?placekey=223-227@5vg-82n-pgk
GET /reso/odata/Property('listing-key-01')?$select=ListingKey,StandardStatus,ListPrice
GET /reso/odata/Property?$filter=OriginatingSystemName eq 'ExampleMLS' and ListingId eq 'A1234567'