RESO TECHNICAL FAQs
You only return enumeration values for single and multiple lookup fields in the payload JSON. I would prefer to get back the Display values (Annotation values in the Metadata for enumerated types).
The RESO API standard and certification tests require the response payload returns the enumerated values, not the Display values.
The response metadata returned via a call to the ../reso/odata/$metadata endpoint includes the Display values as <Annotation> for each <Member> of the enumerated type. XML parsers are available in common programming languages to extract this type of information.
Example of Linux command line extraction of enumerated type MLSAreaMajor annotation/display values:
$ curl –location –request GET ‘https://staging-resoapi.rmlsweb.com/reso/odata/$metadata’ –header ‘Authorization: <token>’| xpath -e \
‘/edmx:Edmx/edmx:DataServices/Schema/*[@Name=”MLSAreaMajor”]/Member/Annotation/@String’ 2>&1 | grep String | cut -d'”‘ -f2
400 Unknown property is not very informative. Can you tell me what is wrong with the following request?
https://resoapi.rmlsweb.com/reso/odata/property?$filter=CountyOrPerish eq ‘Curry’ and StateOrProvince eq ‘OR’ and StandardStatus eq ‘Active’
The fields you are querying against are lookup fields. The API requires that the comparison strings ‘Curry’ and ‘OR’ and ‘Active’ include their base type as part of the query.
In addition, CountyOrPerish is misspelled and should be CountyOrParish (Parish with an ‘a’).
Corrected query:
…/property?$filter=CountyOrParish eq Odata.Models.CountyOrParish’Curry’ and StateOrProvince eq Odata.Models.StateOrProvince’OR’ and StandardStatus eq Odata.Models.StandardStatus’Active’
*Note that there is no space between the Odata.Models.<type> and the quoted value ‘item’ – it is Odata.Models.type’item’
*An additional note, Microsoft Outlook and Word often perform auto-format to change single quotes to “smart” quotes. These are not the same characters and will fail if you cut and paste from the Microsoft apps into an API call.
Odata is generally case sensitive, so check the case of items used in your query URL.
This will fail with a 400 error: …/Property?$count=true&$filter=Availability eq Odata.Models.Availability’BuildOrderonly‘&$select=Availability
This will succeed: …/Property?$count=true&$filter=Availability eq Odata.Models.Availability’BuildOrderOnly‘&$select=Availability
Can you give me some language specific examples for calling the API?
You simply need the supplied authorization codes and a correctly formatted URL query.
You might find Postman (free download) a useful tool for exploring new APIs.
The $metadata XML response is where one finds the correct spelling and case for both attributes (data fields) and lookup enumerations.
https://resoapi-rmlsweb.com/reso/odata/$metadata
Below are language specific methods of calling the resoapi.
1) curl
curl –location –request GET ‘https://resoapi.rmlsweb.com/reso/odata/Property?$filter=ModificationTimestamp+ge+2022-04-01T00:00:00.000Z+and+StandardStatus+eq+Odata.Models.StandardStatus’\”Active’\”&$count=true&$orderby=ModificationTimestamp+desc’ \
–header ‘Authorization: Bearer <your token here>‘
2) Postman Javascript (The pm. prefix on some methods indicate they are Postman library calls ).
function fetchNextRecords(link) {
const getRequest = {
url: link,
method: ‘GET’,
header: {
‘Authorization’: `Bearer ${authToken}`,
‘User-Agent’: ‘PostmanRuntime/7.28.2’,
‘Accept’: ‘*/*’,
‘Cache-Control’: ‘no-cache’,
‘Postman-Token’: ‘ec717dfd-72a4-4c41-a46e-2b1238d82454’,
‘Host’: `resoapi.rmlsweb.com`,
‘Accept-Encoding’: ‘gzip, deflate, br’,
‘Connection’: ‘keep-alive’
}
};
pm.sendRequest(getRequest, (error, response) => {
const result = response.json();
// store the response data here
});
}
const query = ‘https://resoapi.rmlsweb.com/reso/odata/Property?$top=250&$filter=PhotosChangeTimestamp+ge+2022-05-01T00:00:00.000Z+and+PhotosChangeTimestamp+lt+2022-05-15T00:00:00.000Z’;
fetchNextRecords(query);
3) Javascript Fetch
var myHeaders = new Headers();
myHeaders.append(“Authorization”, “Bearer {{authToken}}”);
var requestOptions = {
method: ‘GET’,
headers: myHeaders,
redirect: ‘follow’
};
fetch(https://resoapi.rmlsweb.com/reso/odata/Property?$top=250&$filter=PhotosChangeTimestamp+ge+2022-05-01T00:00:00.000Z+and+PhotosChangeTimestamp+lt+2022-05-15T00:00:00.000Z&$count=true, requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log(‘error’, error));
4) PHP
<?php
require_once ‘HTTP/Request2.php’;
$request = new HTTP_Request2();
$request->setUrl(‘https://resoapi.rmlsweb.com/reso/odata/Property?$top=250&$filter=PhotosChangeTimestamp+ge+2022-05-01T00:00:00.000Z+and+PhotosChangeTimestamp+lt+2022-05-15T00:00:00.000Z’);
$request->setMethod(HTTP_Request2::METHOD_GET);
$request->setConfig(array(
‘follow_redirects’ => TRUE
));
$request->setHeader(array(
‘Authorization’ => ‘Bearer {{authToken}}’
));
try {
$response = $request->send();
if ($response->getStatus() == 200) {
echo $response->getBody();
}
else {
echo ‘Unexpected HTTP status: ‘ . $response->getStatus() . ‘ ‘ .
$response->getReasonPhrase();
}
}
catch(HTTP_Request2_Exception $e) {
echo ‘Error: ‘ . $e->getMessage();
}
Do you know where I can find more information on rate limits for the new API?
The only limit we place on standard feeds is a max 250 records sent back per request.
The size (# bytes) of a “record” may vary depending on the fields selected for the response. We typically do not limit based on the byte count in the response, just the record count.
Is there a limit to how many concurrent requests I can run?
There are no limits set. However, we suggest 3 concurrent sessions.
I was surprised to see how many integer fields are populated with zeros (instead of being empty/null), especially when comparing against the old feed.
This appears to be a function of using the Odata libraries. Edm.Int32 types are set to 0 when the DB returns null to the parser.
When filtering, you can specify “Item eq 0” and the response will not include any records where Item is actually a null. In the same way, “Item ne null” will return only records Item has an actual integer value, or the inverse, “Item eq null” will return only records where Item is null.
The API is problematic for downloading bulk amounts of data.
Using these filter range values, and the suggestion in RESO API Documentation
[Pseudocode, actual implementation varies by language]
Loop by _index from 0 to 23000000 by 10000
// Construct url using a filter with clauses based on _Index
URL = PATH + “/Property?$filter=ListingKeyNumeric+ge+(_index)+and+ListingKeyNumeric+lt+(_index+10000)&$orderby=ListingKeyNumeric+asc”
Response = GET URL+URL_FILTER
NextlinkUrl = Response.value[“@odata.nextlink”]
While NextlinkUrl is defined do
Response = GET NextlinkUrl
Save Response data
End
End
This maintains a better response time for the repeated query used to download pages (while loop) in each slice (outer loop by) of the overall data set (slice size of 10K listings).
Use try-catch code to trap on connection errors and retry the API call since connections do get dropped on occasion.
Why is BathsTotal a “Edm.String” instead of being an ”Edm.Decimal” like LotSizeAcres and LotSizeSquareFeet?
Baths looks like a number but does not really represent a number.
BathsTotal = 3.1 does not represent 3 and 1/10th baths, it is 3 full baths and 1 partial bath.
I want to know more about the Primary_Key that is returned when we query the Deleted Endpoint? How can I relate that Primary_Key to the listing?
This is what the Deleted Resource primary key equates to in the other resources.
- For Property and PropertyGreenVerification Resources the primary_key maps to the ListingKeyNumeric (also, ListingKey & ListingId).
- For OpenHouse Resource the primary_key maps to the OpenHouseKeyNumeric (also OpenHouseKey).
These are the only two Resource records appearing in the Deleted Resource currently.