API Documentation

The Listings API is compliant to the RESO Web API standard for transfer of real estate data. The data follows the RESO Data Dictionary standard for field naming, grouping and data type definition.

Data retrieval largely follows OData protocol with the addition of custom querying options to enhance aggregation queries.

Authentication

Access to the API utilizes OAuth2.

Client Credentials (ID and secret) are provided for each user of the API, allowing for retrieval of bearer access token with preset expiry (default 3600 seconds).

We must encode the combination of Client ID and Client Secret Key separated by “:” in Base 64 format like this:

Base64Encode(5pq9999coididi613e222o1nnpp: fhkoq33a69d8191j1tercv35037clb9e5a7d215e64e4e) = 85e1b0e7539a4a96b00ee02b335aa6418c580917a6b4667f6f7a6fe2149536041569924dfbe4a7df33f==

Can use online service Base64Encode for the encoding.

The end point for the token must include two parameters:

  1. "grant_type" = "client_credentials"
  2. "client_id" = "5pq9999coididi613e222o1nnpp"

Example request to retrieve access token:

curl -X POST -H "Content-Type: application/x-www-form-urlencoded" \
-H "Authorization: Basic 85e1b0e7539a4a96b00ee02b335aa6418c580917a6b4667f6f7a6fe2149536041569924dfbe4a7df33f==" \
-H "Host: authenticate.constellation1apis.com" \
"https://authenticate.constellation1apis.com/oauth2/token?grant_type=client_credentials&client_id=5pq9999coididi613e222o1nnpp"

Authentication response:

{
"access_token": "**********************************",
"expires_in": 3600,
"token_type": "Bearer"
}

Usage

Once the access token is retrieved, it is needed in each call to the Constellation1 API under the Authorization HTTP header:

curl -X GET -i -H "Host: listings.constellation1apis.com" \
-H "Authorization: Bearer **********************************" \
"https://listings.constellation1apis.com/odata/Property?$top=5&$select=ListingKey,StreetNumberNumeric"

Recommendation: It is recommended to include 'Accept-Encoding' header with value 'gzip, deflate, br'. This will compress the response into a zip/brotli format. This should improve the latency in transit by compressing the size. Client will have to decompress the response before processing it:

Header Value
Accept-Encoding gzip, deflate, br

Metadata

The Listings API has an endpoint to retrieve metadata:

https://listings.constellation1apis.com/odata/$metadata

This endpoint allows caller to know available fields and data types for each entity.

<?xml version="1.0" encoding="utf-8" ?>
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
    <edmx:DataServices>
        <Schema Namespace="Cirrus.OData.Domain.Models" xmlns="http://docs.oasis-open.org/odata/ns/edm">
            <EntityType Name="Property">
                <Property Name="AccessibilityFeatures" Type="Collection(Edm.String)" />
                <Property Name="Appliances" Type="Collection(Edm.String)" />
                <Property Name="ArchitecturalStyle" Type="Collection(Edm.String)" />
                ...
            </EntityType>
            <EntityType Name="OpenHouse" />
            <EntityType Name="Member" />
            <EntityType Name="Office" />
            <EntityType Name="Media" />
            <EntityType Name="Dom" />
        </Schema>
        <Schema Namespace="org.reso.metadata.enums" xmlns="http://docs.oasis-open.org/odata/ns/edm">
            <EnumType Name="ArchitecturalStyle" UnderlyingType="Edm.Int64" />
            <EnumType Name="Appliances" />
            ...
        </Schema>
    </edmx:DataServices>
</edmx:Edmx>

Entities

The Listings API supports several entity types, primarily Property which represents a real estate listing. Other entity types such as Media represents supplementary data to a listing such as photos.

Entity Description URL
Property Real Estate Listing https://listings.constellation1apis.com/odata/Property
Member MLS Agent https://listings.constellation1apis.com/odata/Member
Office MLS Office https://listings.constellation1apis.com/odata/Office
Media Photos, Virtual Tours, etc. https://listings.constellation1apis.com/odata/Media
OpenHouse Open House Events https://listings.constellation1apis.com/odata/OpenHouse
Dom Days on Market https://listings.constellation1apis.com/odata/Dom
PropertyUnitTypes Property Units https://listings.constellation1apis.com/odata/PropertyUnitTypes
PropertyRooms Property Rooms https://listings.constellation1apis.com/odata/PropertyRooms
RawMlsProperty Raw Mls Data Fields https://listings.constellation1apis.com/odata/RawMlsProperty

Basic Requests

Following OData protocol, the following examples show how combining options and filters can retrieve a desired subset of real estate data results.

GET /odata/property?$select=...&$filter=...&$top=...&$orderby=...&$ignorenulls=...

API response structure

{
    "@@odata.context": "...",
    "@@odata.count": 0,
    "@@odata.totalCount": 0,
    "value": [],
    "group": [],
    "@@odata.nextLink": "...",
    "debug": { ... },
}
Field Description
@@odata.context annotation of the request
@@odata.count number of records returned in response, default is 10
@@odata.totalCount total number of records found in result set
value result set from query
group used for aggregation results
@@odata.nextLink used for server side, allows user to cycle through entire result set
debug hidden by default, used for troubleshooting and insight into underlying search criteria

Time Range Queries

Select

By default, the entire set of fields are returned, however, we can whitelist specific fields in the response using $select. Whitelist fields are specified in a comma separated list.

Example request:

GET /odata/property?$select=ListingId,StandardStatus

Example response:

{
    "@@odata.context": "https://listings.constellation1apis.com/$metadata#Property",
    "@@odata.count": 10,
    "@@odata.totalCount": 100,
    "value": [
        {
        "ListingId": "1",
        "StandardStatus": "Active"
        },
        {
        "ListingId": "2",
        "StandardStatus": "Active"
        }
        ...
    ]
}

Top

By default, the first 10 results are returned in any API request, however we can alter the number of results by using the $top option followed by a non-negative integer value.

Example request:

GET /odata/Property?$top=1

Recommendation: It is recommended to not exceed $top=1000 with $ignorenulls=true flag. Exceeding this limit will cause slowness of response payloads

Skip

Note: It is ideal and more performant to use the SkipToken approach to paging through result sets

Often in combination with $top, the $skip option allows for client side paging, also using a non-negative integer we can cycling through the entire result set.

Example request:

GET /odata/Property?$top=5&skip=2

Ignore Nulls (preferred)

By default, the response payload will include all fields defined in the metadata where null is returned when there is no value. The $ignorenulls boolean flag will omit fields which have no values thus reducing payload size

Example request:

GET /odata/Property?$ignorenulls=true

Ignore Case

By default, searches are case sensitive. The $ignorecase boolean flag will do case-insensitve searches for supported text fields.

Example request:

GET /odata/Property?$filter=BuildingName eq 'The Great House'&$ignorecase=true

All supported fields are mentioned below:

Property
BuildingName BuyerAgentEmail BuyerAgentFirstName BuyerAgentFullName BuyerAgentLastName
BuyerAgentMiddleName BuyerAgentMlsId BuyerOfficeEmail BuyerOfficeMlsId BuyerOfficeName
CityRegion CoBuyerAgentEmail CoBuyerAgentFirstName CoBuyerAgentFullName CoBuyerAgentLastName
CoBuyerAgentMiddleName CoBuyerAgentMlsId CoBuyerOfficeEmail CoBuyerOfficeMlsId CoBuyerOfficeName
CoListAgentEmail CoListAgentFirstName CoListAgentFullName CoListAgentLastName CoListAgentMiddleName
CoListAgentMlsId CoListOfficeEmail CoListOfficeMlsId CoListOfficeName CountyOrParish
ElementarySchool ElementarySchoolDistrict HighSchool HighSchoolDistrict ListAgentEmail
ListAgentFirstName ListAgentFullName ListAgentLastName ListAgentMlsId ListingId
ListOfficeEmail ListOfficeMlsId ListOfficeName MiddleOrJuniorSchoolDistrict SchoolDistrict
StateOrProvince StreetDirPrefix StreetName StreetNumber StreetNumberNumeric
StreetSuffix SubdivisionName UnitNumber UnparsedAddress
Office
MainOfficeMlsId OfficeCity OfficeEmail OfficeMlsId OfficeName
Member
MemberEmail MemberFirstName MemberFullName MemberLastName MemberMiddleName
MemberMlsId

Filter

Most common option is $filter, typically at least one filter is used when retrieving data, often used are comparison operators to filter results by an MLS (Data Source) via the OriginatingSystemName field.

The following is a list of supported operators and expressions. In future additional OData expressions could be added to the API.

Comparison Operators

Note: single quotation is required for string values

Operator Description Example
eq Equal GET /odata/Property?$filter=OriginatingSystemName eq 'CRMLS'
ne Not Equal GET /odata/Property?$filter=StandardStatus ne 'Active'
gt Greater Than GET /odata/Property?$filter=ListPrice gt 100000
ge Greater Than or Equal GET /odata/Property?$filter=ListPrice ge 100000
lt Less Than GET /odata/Property?$filter=ListPrice lt 200000
le Less Than or Equal GET /odata/Property?$filter=ListPrice le 200000
has Has enumerable GET /odata/Property?$filter=Appliances has 'Freezer'
in Is a member of GET /odata/Property?$filter=StandardStatus in ('Active','Sold')

The any expression is required for fields which are collections as defined in the metadata endpoint where the field is defined as Type="Collection(Edm.String)" (e.g. Appliances).

Boolean Operators

Note: boolean operator is expressed in lower cased

Often used to chain multiple comparison expressions, the boolean operators and and or can precise subset of real estate listings

Operator Description Example
and Logical AND GET /odata/Property?$filter=OriginatingSystemName eq 'CRMLS' and StandardStatus eq 'Active'
or Logical OR GET /odata/Property?$filter=OriginatingSystemName eq 'VirginIslands' or OriginatingSystemName eq 'WesternKY'

Using Standard Lookup Values

Lookups (as defined in Lookups-RESO Data Dictionary 1.7-RESO ) are enumerations where normally their values do not contain special characters or spaces. In situations where they do, they can be filtered using the standard lookup value defined in the RESO data dictionary along with the prefix 'org.reso.metadata.enums'.

Example requests:


GET /odata/Property?$filter=org.reso.metadata.enums.PropertyType eq 'Commercial Sale'
GET /odata/Property?$filter=org.reso.metadata.enums.StandardStatus eq 'Active Under Contract'
GET /odata/Property?$filter=org.reso.metadata.enums.PropertySubType eq 'Single Family Residence'
        

Functions

startswith()

In support of partial and autocomplete queries, the startswith() provides the ability to return results of partial values, such as beginning of a street name or postal/zip code.

Example requests:


GET /odata/Property?$filter=startswith(PostalCode, '902')
GET /odata/Property?$filter=startswith(PostalCode, '9021')
GET /odata/Property?$filter=startswith(PostalCode, '90210')
             

contains()

The contains() function complements the startswith() function as it allows for wildcard searches with the use of the asterisk symbol *, this can be expressed before, after, or within a search term

Example requests:


GET /odata/Property?$filter=contains(SubdivisionName, 'Park*')
GET /odata/Property?$filter=contains(SubdivisionName, '*Arlington')
GET /odata/Property?$filter=contains(SubdivisionName, 'P*rk')
GET /odata/Property?$filter=contains(SubdivisionName, '*Arlington Park*')
            

Geospatial Search

Radius

A radius search returns listings which are located within distance from a fixed point on a map. The function used for radius search “geo.distance” accepts two parameters representing the field (“Location”) and a fixed point (latitude/longitude), followed by a less than operator with a distance value represented by meters.

Example request:


GET /odata/Property?$filter= geo.distance(Location, geography'POINT(-82.5154 40.7584)') lt 1000.0
                

Polygon

A Polygon is a series of coordinates (longitude/latitude pairs) which can represent basic shapes, typically a Polygon’s first and last coordinates match to form a closed shape. Our API supports the “geo.intersects” canonical function which accepts two parameters, firstly the field (“Location”) representing the latitude/longitude of each listing and second the Polygon shape where listings are located within.

Example requests:


GET /odata/Property?$filter=geo.intersects(Location, geography'POLYGON((-82.5294685 40.7700118, -82.5081825 40.7698818, -82.5064659 40.7493377, -82.5272369 40.7489476, -82.5294685 40.7700118))')
            

Expand

In OData, the $expand allows for retrieval of supplementary entity data where there is an association to the primary entity. Typically $expand would be used where Property is the primary EntityType. Expand can retrieve multiple sub-entities using a comma separated list.

Example requests:

GET /odata/Property?$expand=Media
GET /odata/Property?$expand=Media,OpenHouse

Recommendation: It is recommended to not exceed $top=500 with $expand as $expand increases the payload size and query time, potentially resulting in a degradation of service.

Select in Expand

The $select option within $expand allows for the retrieval of specific fields from the expanded resources. This can help in reducing the payload size by selecting only the necessary fields.

Example request:

GET /odata/Property?$expand=Office($select=OfficeType)

Paging (SkipToken)

When making a request to the API that yields a larger amount of results than what is presentable in the response payload, the response payload will include the node "@@odata.nextLink" with a hyperlink to the next set of results. This "@@odata.nextLink" node will reappear until all results has been retrieved.

Example response:

{
    "@@odata.context": "https://listings.constellation1apis.com/$metadata#Property",
    "@@odata.count": 10,
    "@@odata.totalCount": 2295,
    "value": [ ... ],
    "group": [],
    "@@odata.nextLink": "https://listings.constellation1apis.com/property/skiptoken/FGluY2x1ZGVfY29udGV4dF91dWlkDnF1ZXJ5VGhlbkZldGNoBRYxd3h4RWFXRlQwYWtDbGZjdkd0aTNBAA",
}

Ordering

To sort results, the $orderby option can be used, providing the desired sort field and direction, if direction is not provided by default it is assumed the sort order is ascending. Multiple order by expressions can be provided by a comma separated list.

Example requests:

GET /odata/Property?$orderby=ModificationTimestamp
GET /odata/Property?$orderby=ModificationTimestamp desc
GET /odata/Property?$orderby=ModificationTimestamp desc, ListPrice asc

Aggregation

There are two approaches to generating an aggregation result, using:

  1. using $apply=groupby()
  2. using $nested

OData standard protocol prefers usage of the former, however this does not appear to support nested aggregation results, thus there is the latter option.

Aggregation results are returned in the group:[] node, it is often useful to use the $top=0 flag to clear the value:[] results as this may not be needed during aggregation requests.

With $apply=groupby() multiple aggregate results can be returned provided a comma separated list.

Example requests:

GET /odata/Property?$apply=groupby((StateOrProvince))&$top=0
GET /odata/Property?$apply=groupby((StateOrProvince,City))&$top=0

Example results:

{
    "@@odata.context":"https://listings.constellation1apis.com/$metadata#Property",
    "@@odata.count":0,
    "@@odata.totalCount":2590,
    "value":[ ... ],
    "group":[
      {
         "groupby":"StateOrProvince",
         "count":3,
         "buckets":[
            {
               "key":"IL",
               "count":3,
               "sub_aggregate":[
                  ...
               ]
            },
            {
               "key":"KY",
               "count":2584,
               "sub_aggregate":[
                  ...
               ]
            },
            {
               "key":"TN",
               "count":3,
               "sub_aggregate":[
                  ...
               ]
            }
         ]
      }
    ]
}

Nested

In addition to the $apply=groupby() approach, the $nested approach can support nested results, it can also handle fields which are collection of strings.

Example requests:

GET /odata/Property?$nested=PropertyType,PropertySubType,ArchitecturalStyle

Example response:

{
    "@@odata.context":"https://listings.constellation1apis.com/$metadata#Property",
    "@@odata.count":0,
    "@@odata.totalCount":10000,
    "value":[

    ],
    "group":[
      {
         "groupby":"PropertyType",
         "count":21,
         "buckets":[
            {
               "key":"CLE",
               "count":95,
               "sub_aggregate":[
                  {
                     "groupby":"PropertySubType",
                     "count":2,
                     "buckets":[
                        {
                           "key":"Business",
                           "count":1,
                           "sub_aggregate":[
                              {
                                 "groupby":"ArchitecturalStyle",
                                 "count":1,
                                 "buckets":[
                                    {
                                       "key":"Other (see remarks)",
                                       "count":1,
                                       "sub_aggregate":[

                                       ]
                                    }
                                 ]
                              }
                           ]
                        },
                        {
                           "key":"Unimproved Land",
                           "count":3,
                           "sub_aggregate":[
                              {
                                 "groupby":"ArchitecturalStyle",
                                 "count":2,
                                 "buckets":[
                                    {
                                       "key":"Other (see remarks)",
                                       "count":2,
                                       "sub_aggregate":[

                                       ]
                                    },
                                    {
                                       "key":"Traditional",
                                       "count":1,
                                       "sub_aggregate":[

                                       ]
                                    }
                                 ]
                              }
                           ]
                        }
                     ]
                  }
               ]
            },
            {
               "key":"TWN",
               "count":6,
               "sub_aggregate":[
                  {
                     "groupby":"PropertySubType",
                     "count":1,
                     "buckets":[
                        {
                           "key":"Townhouse",
                           "count":6,
                           "sub_aggregate":[
                              {
                                 "groupby":"ArchitecturalStyle",
                                 "count":0,
                                 "buckets":[

                                 ]
                              }
                           ]
                        }
                     ]
                  }
               ]
            }
         ]
      }
    ]
}

Time Range Queries

Queries can contain filter on date ranges for DateTime field types

Example Requests:


GET /odata/Property?$ignorenulls=true&$filter=ModificationTimestamp ge 2022-01-01T00:00:00Z
GET /odata/Property?$ignorenulls=true&$filter=ModificationTimestamp gt 2022-01-01T00:00:00Z and ModificationTimestamp lt 2022-02-01T00:00:00Z

How to do a full job?

A full job requires the first request to a sort by $orderby=ListingKey asc this acts as an initial marker to retrieve subsequent records via the @@odata.nextLink url

Example

First request:


GET /odata/Property?$ignorenulls=true&$filter=OriginatingSystemName eq 'CRMLS'&$top=300&$orderby=ListingKey asc
                

Use the @@odata.nextLink url returned from the first request for the rest of the requests:


GET /odata/Property/skiptoken/FGluY2x1ZGVfY29udGV4dF91dWlkDnF1ZXJ5VGhlbkZldGNoBRZGYmFTT0FSRVExeTRfckMxZ1loOEhnAAAAAAm0TVYWajZEYmttQ1JSWEdIUTlfRDRHNnB0dxY0NUZaQzBJcFI2NmU5N1h5NHFpWXZ3AAAAAAnwnR4WTVQ3WEhKLU9Ua215d2xxWW94SFcydxZGYmFTT0FSRVExeTRfckMxZ1loOEhnAAAAAAm0TVcWajZEYmttQ1JSWEdIUTlfRDRHNnB0dxY0NUZaQzBJcFI2NmU5N1h5NHFpWXZ3AAAAAAnwnR8WTVQ3WEhKLU9Ua215d2xxWW94SFcydxY0NUZaQzBJcFI2NmU5N1h5NHFpWXZ3AAAAAAnwnSAWTVQ3WEhKLU9Ua215d2xxWW94SFcydw==/?$filter=OriginatingSystemName%20eq%20%27CRMLS%27&$ignorenulls=true&$top=300
                

Keep cycling through the entire result set until the @@odata.count is 0

MLS Sync

We recommend a sync process be run once or twice per day in which you request all available ListingIds from a given data source. The delta between that list and the one you currently have in your database will signal which listings should be removed from your database, as well as flag any records available to you which may have been missed in regular incremental operations. This is the same method by which we keep the Constellation1 API current.

Example Requests:


GET /odata/Property?$ignorenulls=true&$select=ListingId
GET /odata/Property?$ignorenulls=true&$select=ListingKey,ListingId

Images

Retrieve images

There are two ways to retrive images:

  1. The recommended way to retrive image Urls is to use $expand on Property entity. In this way, you can get all the image records for one listing, and can use this data to compare with the records in your system to do the add/update/delete operations.

PhotosChangeTimestamp is the field in Property entity to reflect the last photo modification timestamp and can be used to get the list of listings with latest photo updates.

Example requests:

GET /odata/property?$ignorenulls=true&$expand=Media&$select=ListingId,PhotosCount&$filter=OriginatingSystemName eq 'CRMLS' and PhotosChangeTimestamp ge 2022-06-06T16:53:07+00:00

Example response:

{
    "@@odata.context": "http://listings.constellation1apis.com/$metadata#Property",
    "@@odata.count": 50,
    "@@odata.totalCount": 70,
    "value": [
        {
            "ListingId": "PW22122540",
            "OriginatingSystemName": "CRMLS",
            "PhotosCount": 4,
            "StandardStatus": "Active",
            "Media": [
                {
                    "Id": "13071194064517",
                    "Order": 0,
                    "MediaType": "jpeg",
                    "MediaURL": "https://photos.prod.cirrussystem.net/1307/731c82121af9e429dfa966711c59b46d/2505719132.jpeg",
                    "MediaModificationTimestamp": "2022-06-08T01:51:13.103441Z",
                    "ModificationTimestamp": "2022-06-08T01:51:13+00:00",
                    "OriginatingSystemName": "CRMLS",
                    "ResourceRecordID": "PW22122540",
                    "MediaCategory": "Photo",
                    "ResourceRecordKey": "13074115592807",
                    "MediaKey": "13071194064517"
                },
                {
                    "Id": "13072357035296",
                    "Order": 1,
                    "MediaType": "jpeg",
                    "MediaURL": "https://photos.prod.cirrussystem.net/1307/731c82121af9e429dfa966711c59b46d/604979049.jpeg",
                    "MediaModificationTimestamp": "2022-06-08T01:51:13.1653589Z",
                    "ModificationTimestamp": "2022-06-08T01:51:13+00:00",
                    "OriginatingSystemName": "CRMLS",
                    "ResourceRecordID": "PW22122540",
                    "MediaCategory": "Photo",
                    "ResourceRecordKey": "13074115592807",
                    "MediaKey": "13072357035296"
                },
                {
                    "Id": "13073563813694",
                    "Order": 2,
                    "MediaType": "jpeg",
                    "MediaURL": "https://photos.prod.cirrussystem.net/1307/731c82121af9e429dfa966711c59b46d/510761608.jpeg",
                    "MediaModificationTimestamp": "2022-06-08T01:51:13.2318988Z",
                    "ModificationTimestamp": "2022-06-08T01:51:13+00:00",
                    "OriginatingSystemName": "CRMLS",
                    "ResourceRecordID": "PW22122540",
                    "MediaCategory": "Photo",
                    "ResourceRecordKey": "13074115592807",
                    "MediaKey": "13073563813694"
                },
                {
                    "Id": "1307524091547",
                    "Order": 3,
                    "MediaType": "jpeg",
                    "MediaURL": "https://photos.prod.cirrussystem.net/1307/731c82121af9e429dfa966711c59b46d/4053895032.jpeg",
                    "MediaModificationTimestamp": "2022-06-08T01:51:13.3700629Z",
                    "ModificationTimestamp": "2022-06-08T01:51:13+00:00",
                    "OriginatingSystemName": "CRMLS",
                    "ResourceRecordID": "PW22122540",
                    "MediaCategory": "Photo",
                    "ResourceRecordKey": "13074115592807",
                    "MediaKey": "1307524091547"
                }
            ],
        }            
    ],
    "group": [],
    "@@odata.nextLink": "https://listings.constellation1apis.com/odata/property/skiptoken/FGluY2x1ZGVfY29udGV4dF91dWlkDnF1ZXJ5VGhlbkZldGNoBRZ6ZlBObmtkcVQwaVN1VUNMNC1nWHN3AAAAAAE873EWQi1OZTg5a0hRMXVwTXhmMUR6NWw2URZEUU9BblpIbVR1Nm5lOXBXT2FhaXh3AAAAAAFNXXEWcWkxY3hhUTRUcnFIMkZsZENwWktadxZjSWtRMl85ZlRaaTdFWVJsM0o1VjFRAAAAAAFTZWsWeHdfTmJXcDlSTW1fZVkxTVhjXzNWURZ6ZlBObmtkcVQwaVN1VUNMNC1nWHN3AAAAAAE873IWQi1OZTg5a0hRMXVwTXhmMUR6NWw2URZ6ZlBObmtkcVQwaVN1VUNMNC1nWHN3AAAAAAE873MWQi1OZTg5a0hRMXVwTXhmMUR6NWw2UQ==/?$expand=Media&$filter=OriginatingSystemName%20eq%20%27CRMLS%27%20and%20PhotosChangeTimestamp%20ge%202022-06-06T16%3A53%3A07.0000000Z%20and%20PhotosCount%20eq%204&$ignorenulls=true&$select=ListingId,PhotosCount,PhotosChangeTimestamp"
}
  1. Retrieve images from Media entity. Currently we only have the active photos in the Media entity. If a image is removed from the Media, you will not be able to find out unless you reference the PhotosCount in Property entity.

Example requests:

GET Example requests:

GET /odata/media?$filter=OriginatingSystemName eq 'CRMLS' and ModificationTimestamp gt 2022-06-08T18:08:18.5086332-07:00&$top=100&$ignorenulls=true

Example response:

{
    "@@odata.context": "http://listings.constellation1apis.com/$metadata#Media",
    "@@odata.count": 100,
    "@@odata.totalCount": 40720,
    "value": [
        {
            "Id": "1307474260391",
            "Order": 0,
            "MediaType": "jpeg",
            "MediaURL": "https://photos.prod.cirrussystem.net/1307/aea51671d925e754134c87346ecb824b/141986726.jpeg",
            "MediaModificationTimestamp": "2022-06-09T12:31:11.544528Z",
            "ModificationTimestamp": "2022-06-09T12:31:16+00:00",
            "OriginatingSystemName": "CRMLS",
            "ResourceRecordID": "IV22118726",
            "MediaCategory": "Photo",
            "ResourceRecordKey": "13075796572",
            "MediaKey": "1307474260391"
        },
        {
            "Id": "13073608336386",
            "Order": 1,
            "MediaType": "jpeg",
            "MediaURL": "https://photos.prod.cirrussystem.net/1307/aea51671d925e754134c87346ecb824b/19583124.jpeg",
            "MediaModificationTimestamp": "2022-06-09T12:31:11.7175839Z",
            "ModificationTimestamp": "2022-06-09T12:31:16+00:00",
            "OriginatingSystemName": "CRMLS",
            "ResourceRecordID": "IV22118726",
            "MediaCategory": "Photo",
            "ResourceRecordKey": "13075796572",
            "MediaKey": "13073608336386"
        },
        {
            "Id": "13072399412764",
            "Order": 2,
            "MediaType": "jpeg",
            "MediaURL": "https://photos.prod.cirrussystem.net/1307/aea51671d925e754134c87346ecb824b/264290378.jpeg",
            "MediaModificationTimestamp": "2022-06-09T12:31:11.8101757Z",
            "ModificationTimestamp": "2022-06-09T12:31:16+00:00",
            "OriginatingSystemName": "CRMLS",
            "ResourceRecordID": "IV22118726",
            "MediaCategory": "Photo",
            "ResourceRecordKey": "13075796572",
            "MediaKey": "13072399412764"
        }
    ],
    "group": [],
    "@@odata.nextLink": "https://listings.constellation1apis.com/odata/media/skiptoken/FGluY2x1ZGVfY29udGV4dF91dWlkDnF1ZXJ5VGhlbkZldGNoBRZEUU9BblpIbVR1Nm5lOXBXT2FhaXh3AAAAAAFnDsoWcWkxY3hhUTRUcnFIMkZsZENwWktadxZ6ZlBObmtkcVQwaVN1VUNMNC1nWHN3AAAAAAFVQ_wWQi1OZTg5a0hRMXVwTXhmMUR6NWw2URZEUU9BblpIbVR1Nm5lOXBXT2FhaXh3AAAAAAFnDssWcWkxY3hhUTRUcnFIMkZsZENwWktadxZEUU9BblpIbVR1Nm5lOXBXT2FhaXh3AAAAAAFnDswWcWkxY3hhUTRUcnFIMkZsZENwWktadxZ6ZlBObmtkcVQwaVN1VUNMNC1nWHN3AAAAAAFVQ_0WQi1OZTg5a0hRMXVwTXhmMUR6NWw2UQ==/?$filter=OriginatingSystemName%20eq%20%27CRMLS%27%20and%20ModificationTimestamp%20gt%202022-06-09T01%3A08%3A18.5086332Z&$ignorenulls=true&$top=100"
}

Download Image By Url

Note: The iamge url represents one unique image based on the content of the image file, so you don't need download the image again if the url is the same.

Dowload original image by the url from the response:

https://photos.prod.cirrussystem.net/1307/731c82121af9e429dfa966711c59b46d/2505719132.jpeg

Download image by predefined sizes:
Add the parameter d={size} to the image url.
Size values: l(Large, Width=1024), s(Small, Width=480), t(Thumbnail, Width=150)
Download thumbnail image example:

https://photos.prod.cirrussystem.net/1307/731c82121af9e429dfa966711c59b46d/2505719132.jpeg?d=t

Dynamic size image download:
  1. By width only with d={Width}. Example:
    https://photos.prod.cirrussystem.net/1307/731c82121af9e429dfa966711c59b46d/2505719132.jpeg?d=600
  2. By width and height with d={Width}x{Height}. Exmaple:
    https://photos.prod.cirrussystem.net/1307/731c82121af9e429dfa966711c59b46d/2505719132.jpeg?d=500x320