Market Statistics
Descriptionβ
Query to receive detailed market statistics based on a radius from a given location or within a neighborhood (Local Logic geography), over time and divided by asset class. In the United States, the data returned covers a number of market stats in the queried area based on sold homes:
- Median price
- Median square footage
- Median price per square foot
- Median year of construction
Local Logic is currently working on an update to our market statistics which will be available in December 2024. This update will expand our in-depth analysis on market activity in neighborhoods and cities across the United States by incorporating listing data and moving from weekly to daily updates of our statistics.
Additional statistics that will be available in this updated endpoint include:
- Listing data metrics
- Active listings count
- Pending listings count
- Listings under contract count
- New listings count
- Active listings' median age
- Home asking prices
- Minimum asking price
- Median asking price
- Maximum asking price
- Detailed percentile breakdowns on asking prices
- Median asking price per square foot
- Home sales prices
- Minimum sales price
- Maximum sales price
- Detailed percentile breakdowns on sales prices
- Median dollar difference between asking and sales prices
- Median percentage difference between asking and sales prices
- Percent of homes sold above & below asking price
- Absorption rate (a measure of supply & demand calculated by homes sold divided by total listings)
- Market conditions assessment (buyer's/seller's/netural market) with numeric qualifier
- Market speed
- Median days on market
- Median days to offer
- Detailed percentile breakdowns of days to sell
Structureβ
This endpoint returns data structured as a tree with muliple branches to allow consumers to view data at the appropriate level quickly. The data is organized with the following hierarchy, with total transactions and summary statistics at each level:
- Observation (price, square footage, price per square foot, and year built)
- Asset class (house, apartment, etc)
- Number of bedrooms
- Month
Because market data is only available in aggregate, any branch of the tree with less than 2 transactions is not displayed as a separate breakdown in the response. This can cause discrepancies when attempting to compare the total transactions across months, bedroom counts, and asset classes to the total transactions. For example,
- If only a single apartment was sold while mulitple homes were sold in the queried area, the transaction details of the apartment sale are not shown separately.
- If only a single 2 bedroom house was sold while multiple 3 bedroom houses were sold in the queried area, the 2 bedroom house's transaction details are not returned separately.
- If any single month has only a single transaction per asset class, this month is not broken down individually, but it is included in higher-level aggregates.
GET v3/marketstats
β
GET v3/marketstats
Headerβ
This API uses JWT token based authentication. This JWT Bearer token is what is used to populate the
Authorization
header below.
Instructions on how to retrieve this token can be found at Getting Started.
Header | Status | Description |
---|---|---|
Authorization | required | Your bearer token retrieved from our authorization API, ex. Bearer eyJhbGci... |
Accept | required | The datatype to request, this API will return application/json . |
QueryStringβ
Parameter | Status | Description |
---|---|---|
lat | optional | A decimal number between -90 and 90 , representing the latitude. Cannot be used with polygon . |
lng | optional | A decimal number between -180 and 180 , representing the longitude. Cannot be used with polygon . |
polygon | optional | A WKT Polygon of the area to query over. Cannot be used with lat /lng /radius . |
radius_unit | optional | When radius is provided, radius_unit can be set to meter or mile to determine the measurement unit of the radius. Default: meter . |
radius | optional | Can be used with lat /lng to determine the radius to query around the said lat /lng . Default: 1609 meters / 1 mile. |
data | optional | The type of the queried data. Can either be rent or sale . Default: rent . |
limit | optional | Maximum number of rows to be returned from the Database. Default: 10000. |
investment_type | required | Level 1 property type to be queried. Options: residential , commercial , industrial , lots , agriculture . |
residential_l2 | optional | Residential Level 2 property type to be queried. Options: apartments , plexes , townhouses , houses , manufactured . |
commercial_l2 | optional | Commercial Level 2 property type to be queried. Options: multifamily , mixed . |
time_period_start | optional | Start date for posted listings in the form YYYY-MM-DD. Default: 12 months before the current date. |
time_period_end | optional | End date for posted listings in the form YYYY-MM-DD. Default: Current date. |
property_size_min | optional | Minimum property size in square feet to be queried. |
property_size_max | optional | Maximum property size in square feet to be queried. |
year_built_min | optional | Minimum year property was built to be queried. |
year_built_max | optional | Maximum year property was built to be queried. |
bedroom_limit | optional | A parameter that allows to aggregate number of bedrooms above bedroom_limit to bedroom_limit+. |
float_precision | optional | A parameter that controls the float precision in calculated numbers. Default: 4. |
use_geog_id | optional | Boolean to query by smallest geog_id based on the lat lng. Default: false . |
Usage examplesβ
- NodeJS
- Python
require('node-fetch')('https://api.locallogic.co/v3/marketstats?' + new URLSearchParams({
lat: 45.508888,
lng: -73.561668,
radius: 5500,
limit: 50000,
time_period_start: "2024-01-01",
time_period_end": "2024-03-01",
property_size_min: 0
property_size_max: 5000,
year_built_min: 1900,
year_built_max: 2020,
bedroom_limit: 4,
float_precision: 4,
investment_type: "residential,commercial,industrial,lots,agriculture",
residential_l2: "apartments,plexes,townhouses,houses,manufactured",
commercial_l2: "multifamily,mixed",
data: "rent"
}), {
method: 'GET',
headers: {
Accept: 'application/json',
Authorization: 'Bearer eyJhbGciOiJ...'
}
})
.then(response => response.json())
.then(body => {
console.log(body)
})
.catch(error => {
console.log(error)
})
import requests
response = requests.get(
"https://api.locallogic.co/v3/typologies",
headers={
"Accept": "application/json",
"Authorization": "Bearer eyJhbGciOiJ..."},
params={
"lat": "45.508888",
"lng": "-73.561668",
"radius": "55000",
"limit": "50000",
"time_period_start": end_of_last_month.replace(day=1).isoformat()[:10],
"time_period_end": end_of_last_month.isoformat()[:10],
"property_size_min": "0",
"property_size_max": "5000",
"year_built_min": "1900",
"year_built_max": "2020",
"bedroom_limit": "4",
"float_precision": "4",
"investment_type": "residential,commercial,industrial,lots,agriculture",
"residential_l2": "apartments,plexes,townhouses,houses,manufactured",
"commercial_l2": "multifamily,mixed",
"data": "rent",
}
)
print(response.json())
Response exampleβ
{
"data": {
"key": "CA-rent",
"pricing": {
"asking_price": {
"apartments": {
"beds_1": {
"2024-03": {
"change_indicator": 0.0,
"key": "2024-03",
"median": 191.5,
"raw_count": 40,
"stats_q25": 175.0,
"stats_q75": 206.5
},
"key": "beds_1",
"total": {
"change_indicator": 0.0,
"key": "total",
"median": 191.5,
"raw_count": 40,
"stats_q25": 175.0,
"stats_q75": 206.5
}
},
}
// truncated
}
},
"source": "usagedata",
"total": 109
},
"meta": {
"message": "Successfully called marketstats API.",
"statusCode": 200,
"type": "LocalLogic.API.Success"
}
}
GET v3/marketstats/{geog_id}
β
Accepted values for geog_id
are those matching g10_*
, g20_*
, g30_*
, g32_*
and g35_*
. Other values will result with a 404 (not found) status code.
GET v3/marketstats/{geog_id}
Headerβ
This API uses JWT token based authentication. This JWT Bearer token is what is used to populate the
Authorization
header below.
Instructions on how to retrieve this token can be found at Getting Started.
Header | Status | Description |
---|---|---|
Authorization | required | Your bearer token retrieved from our authorization API, ex. Bearer eyJhbGci... |
Accept | required | The datatype to request, this API will return application/json . |
Usage examplesβ
- NodeJS
- Python
require('node-fetch')('https://api.locallogic.co/v3/marketstats/g30_c28wnknk"?' + new URLSearchParams({
}), {
method: 'GET',
headers: {
Accept: 'application/json',
Authorization: 'Bearer eyJhbGciOiJ...'
}
})
.then(response => response.json())
.then(body => {
console.log(body)
})
.catch(error => {
console.log(error)
})
import requests
response = requests.get(
"https://api.locallogic.co/v3/marketstats/g30_c28wnknk",
headers={
"Accept": "application/json",
"Authorization": "Bearer eyJhbGciOiJ..."
},
)
print(response.json())
Response exampleβ
{
"data": {
"price": {
"houses": {
"beds_3": {
"key": "beds_3",
"2022-07": {
"median": 700000.0,
"stats_q25": 645000.0,
"stats_q75": 737500.0,
"raw_count": 3,
"key": "2022-07"
},
// truncated
"total": {
"median": 760000.0,
"stats_q25": 697992.0,
"stats_q75": 862000.0,
"raw_count": 25,
"key": "total"
}
"beds_unknown": {
"key": "beds_unknown",
"2023-07": {
"median": 614500.0,
"stats_q25": 591750.0,
"stats_q75": 637250.0,
"raw_count": 2,
"key": "2023-07"
},
// truncated
"total": {
"median": 670000.0,
"stats_q25": 637250.0,
"stats_q75": 815187.5,
"raw_count": 12,
"key": "total"
}
},
"total": {
"key": "total",
"2022-07": {
"median": 775000.0,
"stats_q25": 700000.0,
"stats_q75": 835000.0,
"raw_count": 5,
"key": "2022-07"
},
// truncated
},
"2024-05": {
"median": 1463700.0,
"stats_q25": 1308050.0,
"stats_q75": 1619350.0,
"raw_count": 2,
"key": "2024-05"
},
"total": {
"median": 835000.0,
"stats_q25": 698494.0,
"stats_q75": 996250.0,
"raw_count": 54,
"key": "total",
"raw_count_yearly_change": -0.5,
"price_yearly_change": 0.07471109162647957
},
"subtotal_12_months": {
"median": 830000.0,
"stats_q25": 675000.0,
"stats_q75": 1100000.0,
"raw_count": 25
}
},
"key": "houses"
},
"key": "price"
},
"key": "pricing",
"owner_occupied": {
// truncated
},
"geog_id": "g30_djq1y33x",
"total": 54,
"source": "fa",
"name": "US-sale"
},
"meta": {
"message": "Successfully called marketstats API.",
"type": "LocalLogic.API.Success",
"statusCode": 200
}
}
Error codesβ
When calling Local Logicβs API, you may receive an HTTP error code. These errors are explained below. In general, error codes starting with β4β are due to an invalid API call and can be fixed on your end, whereas error codes starting with β5β are due to server errors (that is, problems on our end). If you receive something not described here, please contact us at support@locallogic.co.
400 - BadRequest
This error code happens when the request inputs are incorrect. Use the detail field of the response for clarification. Example:
{
"code": "LocalLogic.API.BadRequest",
"detail": "ValidationErrors: AroundEndpoint is invalid:\n\tinclude is invalid: \"bad_input\" is not an acceptable value: \"groceries\", \"restaurants\", \"nightlife\", \"cafes\", \"shopping\", \"daycares\", \"primary_schools\", \"high_schools\""
}
401 - Unauthorized
This error code happens when your API key cannot access specific resources or locations. For example, some API keys can only access certain countries / states / provinces. Feel free to contact us for more information. Example:
{
"code": "LocalLogic.API.Unauthorized",
"detail": "Your API KEY doesn't support this region"
}
403 - Forbidden
This error code happens when you forgot to include security credentials with your request or you are requesting a parameter that you do not have access to. Example:
{
"message": "Forbidden"
}
404 - NotFound
This error code happens when we donβt have data for the requested location. For example, if you send a lat/lng pair for a location in Antarctica, we will return this error as we donβt have data for Antarctica (yet!). Example:
{
"code": "LocalLogic.API.NotFound",
"detail": "No Location Scores found for this location."
}
422 - Unprocessable Entity
This error code is returned when the correct parameters have been sent however, the data they contain is not valid. For example, if you send a lat/lng pair and the latitude is invalid (ie. not in the range [-90, 90]) and/or the longitude is invalid (ie. not in the range [-180, 180]).
{
"message": "Latitude must be within [-90, 90], Longitude must be within [-180, 180], Requires at least lat/lng pair, or geography_ids. None supplied.",
"code": "LocalLogic.API.BadRequest",
"statusCode": 422
}
500 - ServerError
This error code means that an error occurred on our end. Feel free to retry the same request to see if the problem persists. If you received a lot of these errors, please contact us at support@locallogic.co Example:
{
"code": "LocalLogic.API.ServerError",
"detail": "No Location Scores found for this location."
}
502 - BadGateway
This error code means that an error came from our cloud provider. Feel free to retry the same request to see if the problem persists. Example:
{
"message": "Internal server error"
}