# API Version 1.7

## Introduction

Welcome to the AnyProp RESO Listings API documentation. Our API provides access to real estate listing data following the [Real Estate Standards Organization (RESO)](https://www.reso.org/reso-web-api/) Web API standards. We utilize [OData (Open Data Protocol)](https://www.odata.org/) to offer a flexible and powerful querying capability for our data resources.

## Authentication

All API calls (except the token endpoint) require a Bearer token in the Authorization header:

```http
Authorization: Bearer your_access_token
```

### Getting an Access Token

{% openapi src="/files/XzdO5oYF1v8txYob44Dg" path="/v1/token" method="post" %}
[v1-listings-openapi.json](https://1641940837-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FrGzrwOnOaHE8efiS4dhB%2Fuploads%2Fgit-blob-c713ffa016af220bed86c06d208097df6a4a6058%2Fv1-listings-openapi.json?alt=media)
{% endopenapi %}

## Account Resources, Settings, and Permission

You can view account settings and permissions on the account/resources endpoint.

{% openapi src="/files/XzdO5oYF1v8txYob44Dg" path="/v1/account/resources" method="get" %}
[v1-listings-openapi.json](https://1641940837-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FrGzrwOnOaHE8efiS4dhB%2Fuploads%2Fgit-blob-c713ffa016af220bed86c06d208097df6a4a6058%2Fv1-listings-openapi.json?alt=media)
{% endopenapi %}

## MLS Profiles

You can get mls profiles (including logos, disclaimers, and basic compliance elements).

{% openapi src="/files/XzdO5oYF1v8txYob44Dg" path="/v1/listings/mls\_profiles" method="get" %}
[v1-listings-openapi.json](https://1641940837-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FrGzrwOnOaHE8efiS4dhB%2Fuploads%2Fgit-blob-c713ffa016af220bed86c06d208097df6a4a6058%2Fv1-listings-openapi.json?alt=media)
{% endopenapi %}

## API Resources

The base URL for all listings API requests is:

```
https://api.anyprop.com/v1/listings/data
```

### Property Resource

{% openapi src="/files/XzdO5oYF1v8txYob44Dg" path="/v1/listings/data/Property" method="get" %}
[v1-listings-openapi.json](https://1641940837-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FrGzrwOnOaHE8efiS4dhB%2Fuploads%2Fgit-blob-c713ffa016af220bed86c06d208097df6a4a6058%2Fv1-listings-openapi.json?alt=media)
{% endopenapi %}

**Available `$filter` fields:**

`OriginatingSystemName, ModificationTimestamp, PhotosChangeTimestamp, StandardStatus, PropertyType, ListingId, ListOfficeMlsId, ListingKey, OnMarketTimestamp, ListingContractDate, OnMarketDate, ListPrice, OriginalListPrice, CloseDate, StatusChangeTimestamp, MlsStatus, City, PostalCode, PostalCodePlus4, StateOrProvince, StreetDirPrefix, StreetDirSuffix, StreetName, StreetNumber, StreetSuffix, UnitNumber, UnparsedAddress, ListAgentFullName, CoListAgentFullName, BuyerAgentFullName, CoBuyerAgentFullName, ListOfficeName, CoListOfficeName, BuyerOfficeName, CoBuyerOfficeName, ListAgentEmail, CoListAgentEmail, BuyerAgentEmail, CoBuyerAgentEmail, BathroomsTotalInteger, PropertySubType, BathroomsPartial, BathroomsHalf, BathroomsFull, LotSizeArea, LotSizeSquareFeet, Latitude, Longitude, GarageYN, GarageSpaces, CarportYN, CarportSpaces, PoolPrivateYN, SeniorCommunityYN, AssociationYN, NewConstructionYN, BedroomsTotal, DaysOnMarket, YearBuiltEffective, YearBuilt, PhotosCount, LivingArea, SpecialListingConditions, CountyOrParish, OriginalEntryTimestamp, RawLocation, Location, RawAddressSearchText, ListAgentSearchText, BuyerAgentSearchText, ListOfficeSearchText, BuyerOfficeSearchText, KeywordSearchText, anyprop_ListAgentEmail, anyprop_BuyerAgentEmail, anyprop_ListAgentPhone, anyprop_BuyerAgentPhone, anyprop_OriginalEntryTimestamp, anyprop_DaysOnMarketReferenceTimestamp, anyprop_Address, anyprop_AddressAlias`

**`$expand` options:**

* `Media` - Property media (join from the Media resource)
* `OpenHouse` - Property open houses (join from the OpenHouse resource)
* `PropertyChange` - (Non-RESO) Historical change tracking for property fields with old/new values and modification timestamps
* `PreferredMedia` - (Non-RESO) Optimized expand that returns the first 2 photos by media order, with priority given to the preferred photo (much faster than expanding Media)

**Geospatial Filtering:**

Supported via `geo.distance` on **RawLocation** or **Location**. Only `le` comparison is accepted (distance in meters):

```http
$filter=geo.distance(RawLocation, geography'POINT(-82.98163737 35.11490043)') le 1000
```

Polygon filtering is supported via `geo.intersects` on **RawLocation** or **Location**:

```http
$filter=geo.intersects(RawLocation, geography'POLYGON((-80.30 25.70, -80.13 25.70, -80.13 25.85, -80.30 25.85, -80.30 25.70))')
```

**Text Search:**

The API supports fuzzy text matching using the `search.text` function. This feature allows you to search for properties using partial or incomplete text across multiple fields.

Syntax:

```
$filter=search.text(field, 'search terms', min_matches)
```

Parameters:

* **field** - The search field to query (e.g., `RawAddressSearchText`, `KeywordSearchText`)
* **search terms** - The text to search for (as a string)
* **min\_matches** (optional) - Required number of matching terms. For example, `2` means at least 2 of the tokenized search terms must match. To require all terms to match, use a large number like `1000` (values exceeding the token count are automatically capped).

Default behavior when `min_matches` is omitted:

* **RawAddressSearchText**: Matches if at least 40% of terms match
* **All other fields**: Strict matching (all terms must match)

**Address Search:**

Search for properties using partial or incomplete addresses with the **RawAddressSearchText** field.

*Note: This performs fuzzy text matching only; it is **not** a geocoding service.*

Example:

```
# Search for addresses containing "100 Gold" (defaults to 40% match)
$filter=search.text(RawAddressSearchText,'100 Gold')

# Search for properties on Main Street (require all terms)
$filter=search.text(RawAddressSearchText,'Main Street',1000)
```

**Agent and Office Search:**

Search for properties by agent, co-agent, office, or co-office names using `search.text` on the following fields:

* **ListAgentSearchText** - Listing agent names
* **BuyerAgentSearchText** - Buyer agent names
* **ListOfficeSearchText** - Listing office names
* **BuyerOfficeSearchText** - Buyer office names

Example:

```
# Search for properties with listing agent "John Smith" (strict match)
$filter=search.text(ListAgentSearchText,'John Smith')

# Search for properties with buyer agent "Jane Doe"
$filter=search.text(BuyerAgentSearchText,'Jane Doe')

# Search for properties with listing office "Acme Realty"
$filter=search.text(ListOfficeSearchText,'Acme Realty')
```

**Keyword Search:**

Search across listing remarks and descriptions using the **KeywordSearchText** field.

Fields included in search: `ListingId`, `Appliances`, `ArchitecturalStyle`, `Heating`, `Cooling`, `InteriorFeatures`, `ParkingFeatures`, `PropertySubType`, `WaterfrontFeatures`, `View`, `PublicRemarks`

Example:

```
# Search for properties mentioning "pool" and "renovated" (strict match)
$filter=search.text(KeywordSearchText,'pool renovated')

# Search for properties with at least one of these terms
$filter=search.text(KeywordSearchText,'waterfront dock boat',1)
```

**Sorting by Relevance:**

To sort results by the best match (using BM25), use:

```
$orderby=relevance desc
```

Complete Example:

```
# Search for "100 Gold" and sort by best match
$filter=search.text(RawAddressSearchText,'100 Gold')&$orderby=relevance desc
```

**Internal Non-RESO Fields:**

Useful fields derived internally that extend beyond the RESO standard:

*Geocoded Address:*

* **anyprop\_Address** - Normalized internal address (geocoded). Useful for identifying properties across listings.
* **anyprop\_AddressAlias** - Slug derived from `anyprop_Address`. Useful for identifying properties across listings.
* **anyprop\_RawAddress** - Raw full address built from MLS address fields, the unparsed address, and any other available information
* **anyprop\_HouseNumber** - House number from the geocoded address
* **anyprop\_StreetName** - Street name from the geocoded address
* **anyprop\_StreetAddress** - Street address (house number + street name) from the geocoded address
* **anyprop\_City** - City from the geocoded address
* **anyprop\_State** - State from the geocoded address
* **anyprop\_ZipCode** - Zip code from the geocoded address

*Geolocation:*

* **anyprop\_Latitude** - Geocoded latitude
* **anyprop\_Longitude** - Geocoded longitude
* **anyprop\_AddressFoundYN** - Whether the address was successfully geocoded
* **anyprop\_ExactGeocodeYN** - Whether the geocode is an exact match (address accuracy greater than or equal to line interpolation)

*Timestamps:*

* **anyprop\_OriginalEntryTimestamp** - Derived OriginalEntryTimestamp based on internal data. Example: `2025-08-19T16:19:13.000000Z`
* **anyprop\_DaysOnMarketReferenceTimestamp** - Derived date used to calculate DaysOnMarket. The DaysOnMarket value is computed as: `Current Time - anyprop_DaysOnMarketReferenceTimestamp`. Available as a $filter field. Example: `2026-02-17T22:15:04.300000Z`

*Financial:*

* **anyprop\_AssociationFeeTotalMonthly** - Derived monthly association fee total. Example: `250`

*Agent & Contact Search:*

* **anyprop\_ListAgentEmail** - Searches both list agent and co-list agent email addresses. Use standard comparison operators (`eq`, `contains`, etc.) — not a text search field.
* **anyprop\_BuyerAgentEmail** - Searches both buyer agent and co-buyer agent email addresses. Use standard comparison operators (`eq`, `contains`, etc.) — not a text search field.
* **anyprop\_ListAgentPhone** - Searches both list agents (main + co) across all phone number fields: `ListAgentDirectPhone`, `ListAgentHomePhone`, `ListAgentMobilePhone`, `ListAgentOfficePhone`, `ListAgentPreferredPhone`, `ListAgentTollFreePhone`, `CoListAgentDirectPhone`, `CoListAgentHomePhone`, `CoListAgentMobilePhone`, `CoListAgentOfficePhone`, `CoListAgentPreferredPhone`, `CoListAgentTollFreePhone`
* **anyprop\_BuyerAgentPhone** - Searches both buyer agents (main + co) across all phone number fields: `BuyerAgentDirectPhone`, `BuyerAgentHomePhone`, `BuyerAgentMobilePhone`, `BuyerAgentOfficePhone`, `BuyerAgentPreferredPhone`, `BuyerAgentTollFreePhone`, `CoBuyerAgentDirectPhone`, `CoBuyerAgentHomePhone`, `CoBuyerAgentMobilePhone`, `CoBuyerAgentOfficePhone`, `CoBuyerAgentPreferredPhone`, `CoBuyerAgentTollFreePhone`

> **Note:** Phone number fields can be queried in either the raw form from the MLS or a "normalized" form (all numeric).

### Media Resource

{% openapi src="/files/XzdO5oYF1v8txYob44Dg" path="/v1/listings/data/Media" method="get" %}
[v1-listings-openapi.json](https://1641940837-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FrGzrwOnOaHE8efiS4dhB%2Fuploads%2Fgit-blob-c713ffa016af220bed86c06d208097df6a4a6058%2Fv1-listings-openapi.json?alt=media)
{% endopenapi %}

**Available `$filter` fields:**

`OriginatingSystemName, ModificationTimestamp, MediaKey, MediaStatus, Order, MediaCategory, ResourceName, ResourceRecordKey, ResourceRecordID`

### Member Resource

{% openapi src="/files/XzdO5oYF1v8txYob44Dg" path="/v1/listings/data/Member" method="get" %}
[v1-listings-openapi.json](https://1641940837-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FrGzrwOnOaHE8efiS4dhB%2Fuploads%2Fgit-blob-c713ffa016af220bed86c06d208097df6a4a6058%2Fv1-listings-openapi.json?alt=media)
{% endopenapi %}

**Available `$filter` fields:**

`OriginatingSystemName, ModificationTimestamp, MemberMlsId, MemberFullName, MemberEmail, MemberStatus, MemberStateOrProvince, MemberStateLicense, OfficeKey, OfficeMlsId, OfficeName, anyprop_MemberPhone`

**Internal Non-RESO Fields:**

* **anyprop\_MemberPhone** - Searches across all member phone number fields: `MemberDirectPhone`, `MemberHomePhone`, `MemberMobilePhone`, `MemberOfficePhone`, `MemberPreferredPhone`, `MemberTollFreePhone`

> **Note:** Phone number fields can be queried in either the raw form from the MLS or a "normalized" form (all numeric).

### Office Resource

{% openapi src="/files/XzdO5oYF1v8txYob44Dg" path="/v1/listings/data/Office" method="get" %}
[v1-listings-openapi.json](https://1641940837-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FrGzrwOnOaHE8efiS4dhB%2Fuploads%2Fgit-blob-c713ffa016af220bed86c06d208097df6a4a6058%2Fv1-listings-openapi.json?alt=media)
{% endopenapi %}

**Available `$filter` fields:**

`OriginatingSystemName, ModificationTimestamp, OfficeMlsId, OfficeName, OfficePhone, OfficeEmail, OfficeStateOrProvince, OfficeStatus`

### OpenHouse Resource

{% openapi src="/files/XzdO5oYF1v8txYob44Dg" path="/v1/listings/data/OpenHouse" method="get" %}
[v1-listings-openapi.json](https://1641940837-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FrGzrwOnOaHE8efiS4dhB%2Fuploads%2Fgit-blob-c713ffa016af220bed86c06d208097df6a4a6058%2Fv1-listings-openapi.json?alt=media)
{% endopenapi %}

**Available `$filter` fields:**

`OriginatingSystemName, ModificationTimestamp, OpenHouseKey, ListingId, OpenHouseDate`

## Query Parameters

### OData Query Support

All resources support the following OData query parameters:

* `$filter`: Filter results using OData filter expressions
* `$select`: Select specific fields to return
* `$top`: Limit the number of results (default: 500, max: 5000)
* `$skip`: Skip a number of results for pagination

Additionally, the Property resource supports:

* `$expand`: Include related Media and OpenHouse data

Our API supports comprehensive OData filtering capabilities:

#### Comparison Operators

* `eq`: Equal to
* `ne`: Not equal to
* `gt`: Greater than
* `ge`: Greater than or equal to
* `lt`: Less than
* `le`: Less than or equal to

#### Logical Operators

* `and`: Both conditions must be true
* `or`: Either condition must be true
* `not`: Negates the condition

#### String Functions

* `contains(field, 'value')`: Checks if field contains the specified value
* `startswith(field, 'value')`: Checks if field starts with the specified value
* `endswith(field, 'value')`: Checks if field ends with the specified value

Example complex queries:

```
# Multiple conditions
$filter=PropertyType eq 'Residential' and StandardStatus eq 'Active'

# String function with logical operator
$filter=startswith(OfficeMlsId, 'P') or contains(OfficeName, 'Real')

# Date comparison
$filter=ModificationTimestamp gt '2023-01-01T00:00:00Z'
```

## API Grouping Results

The OData API supports data aggregation using `$apply=groupby()`. Note that ALL grouping is case insensitive for string fields.

### Syntax

```http
$apply=groupby((field1,field2,...))
```

### Response Schema

The grouping response contains the following:

* **group**
  * **groupby**: Field being grouped.
  * **count**: Total groups.
  * **buckets**: Array of group results.
    * **key**: Group value.
    * **count**: Items in the group.
    * **group**: Nested grouping (for multiple fields).

### Example Response

```json
{
  "group": {
    "groupby": "OriginatingSystemName",
    "count": 18,
    "buckets": [
      {
        "key": "global mls",
        "count": 89656,
        "group": {
          "groupby": "StateOrProvince",
          "count": 17,
          "buckets": [
            {
              "key": "fl",
              "count": 87267
            },
            {
              "key": "",
              "count": 2307
            }
          ]
        }
      }
    ]
  }
}
```

## Error Handling

All errors follow the standard OData format:

```json
{
  "error": {
    "code": "error_code",
    "message": "Human readable error message"
  }
}
```


# Release Notes

This document tracks changes and updates to the AnyProp RESO Listings API.

Minor version updates (e.g., 1.1, 1.2, 1.3) primarily add new functionality and performance improvements while maintaining backward compatibility.

## Version 1.7.0

**Release Date:** March 2026

### New Features

* **Polygon Geospatial Filtering**: Added `geo.intersects` support for polygon-based geospatial queries
  * Filter properties within a defined polygon area using `geo.intersects(RawLocation, geography'POLYGON(...)')` or `geo.intersects(Location, geography'POLYGON(...)')`
  * Complements existing `geo.distance` radius-based filtering

***

## Version 1.6.0

**Release Date:** February 2026

### New Features

* **Geocoded Address Fields**: New internal non-RESO fields providing normalized, geocoded address components
  * `anyprop_Address`, `anyprop_AddressAlias` - Normalized address and slug for identifying properties across listings
  * `anyprop_RawAddress` - Raw full address built from MLS address fields
  * `anyprop_HouseNumber`, `anyprop_StreetName`, `anyprop_StreetAddress`, `anyprop_City`, `anyprop_State`, `anyprop_ZipCode` - Parsed geocoded address components
* **Geolocation Fields**: New geocoded location fields
  * `anyprop_Latitude`, `anyprop_Longitude` - Geocoded coordinates
  * `anyprop_AddressFoundYN`, `anyprop_ExactGeocodeYN` - Geocode quality indicators
* **Agent & Contact Search Fields**: New derived fields for searching across agent and member contact information
  * `anyprop_ListAgentEmail`, `anyprop_BuyerAgentEmail` - Search both main and co-agent email addresses using standard comparison operators
  * `anyprop_ListAgentPhone`, `anyprop_BuyerAgentPhone` - Search both main and co-agent phone numbers across all phone fields
  * `anyprop_MemberPhone` - Search across all member phone number fields
  * Phone number fields can be queried in raw form or normalized (all numeric) form
* **Financial Fields**: New `anyprop_AssociationFeeTotalMonthly` derived field

### Enhanced Filtering

* **Property Resource**: Added filterable fields
  * `ListAgentEmail`, `CoListAgentEmail`, `BuyerAgentEmail`, `CoBuyerAgentEmail` - Filter by agent email addresses
  * `OriginalEntryTimestamp` - Filter by original entry timestamp
  * `anyprop_ListAgentEmail`, `anyprop_BuyerAgentEmail`, `anyprop_ListAgentPhone`, `anyprop_BuyerAgentPhone`, `anyprop_Address`, `anyprop_AddressAlias`
* **Member Resource**: Added filterable fields
  * `MemberEmail`, `OfficeKey`, `OfficeMlsId`, `OfficeName` - Enhanced member filtering
  * `anyprop_MemberPhone` - Search across all member phone fields
* **Office Resource**: Added filterable fields
  * `OfficePhone`, `OfficeEmail`

***

## Version 1.5.0

**Release Date:** December 2025

### New Features

* **Keyword Search**: New `KeywordSearchText` field for searching across listing remarks and descriptions
  * Use `search.text(KeywordSearchText, 'search terms')` to find properties by keywords
  * Supports strict matching by default (all terms must match)
* **Internal Non-RESO Fields**: New derived fields for enhanced filtering
  * `anyprop_OriginalEntryTimestamp` - Derived OriginalEntryTimestamp based on internal data
  * `anyprop_DaysOnMarketReferenceTimestamp` - Derived date used to calculate DaysOnMarket (available as a $filter field)

### Updates

* **search.text() Enhanced Syntax**: Added optional `min_matches` parameter
  * Syntax: `search.text(field, 'search terms', min_matches)`
  * Allows specifying minimum number of matching terms required
  * Default behavior: RawAddressSearchText matches at 40%, all other fields require strict matching

***

## Version 1.4.0

**Release Date:** November 2025

### New Features

* **PreferredMedia Expansion** (Non-RESO): New optimized `$expand=PreferredMedia` option for Property resources
  * Returns the first 2 photos by media order, with priority given to the preferred photo
  * Optimized alternative to expanding full Media resource

### Updates

* **PropertyChange Expansion**: Renamed `$expand=PropertyChanges` to `$expand=PropertyChange` for consistency (backwards compatible - both names supported)

***

## Version 1.3.0

**Release Date:** October 2025

### New Features

* **Fuzzy Search for Agents and Offices**: Added text search capability for finding properties by agent and office names
  * New `search.text()` function for `ListAgentSearchText`, `BuyerAgentSearchText`, `ListOfficeSearchText`, and `BuyerOfficeSearchText` fields
  * Enables searching across listing agents, buyer agents, co-agents, and their respective offices
  * Supports relevance-based sorting with `$orderby=relevance desc`

### Enhanced Filtering

* **Property Resource**: Added additional filterable fields
  * `CoListAgentFullName`, `BuyerAgentFullName`, `CoBuyerAgentFullName` - Filter by co-agent and buyer agent names
  * `CoListOfficeName`, `BuyerOfficeName`, `CoBuyerOfficeName` - Filter by co-office and buyer office names
  * `BathroomsHalf` - Filter by half bathrooms count
  * `SpecialListingConditions` - Filter by special listing conditions
* **Member Resource**: Added additional filterable fields
  * `MemberFullName`, `MemberStatus`, `MemberStateOrProvince`, `MemberStateLicense` - Enhanced member filtering capabilities
* **Office Resource**: Added additional filterable fields
  * `OfficeName`, `OfficeStateOrProvince`, `OfficeStatus` - Enhanced office filtering capabilities

***

## Version 1.2.0

**Release Date:** August 2025

### New Features

* **SearchText Functionality**: Added fuzzy address search capability
  * Introduced `search.text()` function for `RawAddressSearchText` field
  * Enables partial and incomplete address matching
  * Supports relevance-based sorting with `$orderby=relevance desc`

### Performance Improvements

* Enhanced query response times across all endpoints
* Optimized data retrieval and filtering operations

***

## Version 1.1.0

**Release Date:** July 2025

### Performance Improvements

* General performance updates and optimizations
* Improved API response times


