# 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="<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>" 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="<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>" 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="<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>" 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="<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>" 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="<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>" 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="<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>" 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="<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>" 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="<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>" 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"
  }
}
```
