!

/map

GET
https://api.houski.ca/map
Our interactive map page is powered by this endpoint.

The map endpoint provides access to property map pins (which are essentially just properties), and clusters. This data is suitable for use with interactive maps.

Additionally, this endpoint can generate heatmap data, presented as a grid of cells where each cell's intensity reflects the concentration of properties relative to other cells. The endpoint supports extensive filtering options for properties, including fields such as list price, sale price, for sale status, and number of bedrooms, among others.

This endpoint conforms to Houski API's standard filtering and sorting functionality.

Example use cases

  1. Systems that track and monitor property data changes in a region. For example, to monitor for properties or land going on sale within a specific boundary.
  2. Online property marketplaces can enhance their services with map-based functionality.
  3. Governments can leverage both pin and cluster data for housing and urban planning.
  4. Investors can visualize high-potential areas and trends for property investment.
  5. Insurance companies can use the data to better assess property risks.
  6. Property management companies can optimize rental pricing strategies.
  7. Journalists can use the data to create visualizations for stories related to housing trends and affordability, for example 'Where are the cheapest houses in Canada?'.
  8. Data analysts can derive fast, unique insights from clustered property data.

Request parameters

NameRequiredTypeDescription
api_keyYesUUID v4Your API key for authorization
clusterNoBoolean (default: false)Manual control of whether the data returned should be in pins or clusters.
cluster_overNoIntegerAutomatically return clusters instead of pins when there are more results than this.
heatmapNoBoolean (default: false)Return heatmap data instead of pins.
heatmap_cell_limitNoIntegerThe max number of heatmap cells returned (default: 1000, max: 10000)
heatmap_aggregation_fieldNoStringField to use for heatmap intensity calculation. When not provided, density of properties is used.
heatmap_aggregation_typeNoString (default: 'mean')aggregation method for heatmap values. Possible values: 'mean', 'median', 'sum'
heatmap_aggregation_invert_intensityNoBoolean (default: false)When true, inverts the intensity values (1.0 - intensity) to make lower values appear as higher intensity
abort_overNoIntegerAbort request if number of results exceeds this value (cost control).
polygonIf not using bboxPolygon filter stringGet results inside a polygon.
bbox_ne_latIf not using polygonNumberNortheast latitude for bounding box.
bbox_ne_lngIf not using polygonNumberNortheast longitude for bounding box.
bbox_sw_latIf not using polygonNumberSouthwest latitude for bounding box.
bbox_sw_lngIf not using polygonNumberSouthwest longitude for bounding box.

Working with heatmaps

The map endpoint provides powerful heatmap capabilities that can visualize both property density and numeric property attributes.

Basic heatmap (property density)

When the heatmap parameter is set to true without specifying a heatmap_aggregation_field, the API returns a heatmap where the intensity of each cell represents the density of properties in that area relative to other areas. This is useful for visualizing where properties that match specific filters are concentrated.

Aggregated field heatmap

By specifying a heatmap_aggregation_field along with heatmap=true, you can create heatmaps based on numeric property values such as price, square footage, or number of bedrooms.

When using field-based heatmaps, you can control how values are aggregated within each cell:

  • mean (default): The average value of all properties in the cell
  • median: The middle value of all properties in the cell
  • sum: The total of all values in the cell

By default, higher field values result in higher intensity areas on the heatmap. Setting heatmap_aggregation_invert_intensity=true reverses this, making lower values appear as higher intensity. This is useful when visualizing fields where the lowest values are the visual target (for something like affordability).

Response object

Type declarations are available at the bottom of this page.

NameTypeDescription
abortedBooleanIndicates if the request was aborted due to exceeding the abort_over limit
cache_hitBooleanIndicates if the data was retrieved from the cache
cost_centsNumberCost of the API call in cents
dataObjectContains the map data in 'clusters', 'properties', or 'heatmap' arrays depending on the request type
errorStringDetails about the error. Empty if no error
is_propertiesBooleanIndicates if the returned data contains individual properties
is_clustersBooleanIndicates if the returned data contains clustered properties
is_heatmapBooleanIndicates if the returned data contains heatmap cells
is_heatmap_aggregationBoolean (nullable)When present, indicates if the heatmap uses a field for aggregation (true) or just property density (false)
is_heatmap_aggregation_invert_intensityBoolean (nullable)When present, indicates if heatmap intensity values are inverted (1.0 - value)
heatmap_aggregation_typeString (nullable)When present, indicates the type of aggregation used: 'mean', 'median', or 'sum'
heatmap_aggregation_max_valueNumber (nullable)When present, the maximum value found in the aggregated field (before normalization)
heatmap_aggregation_min_valueNumber (nullable)When present, the minimum value found in the aggregated field (before normalization)
heatmap_aggregation_fieldString (nullable)When present, the field name used for heatmap aggregation
paginationObjectPagination information
price_quoteBooleanIndicates if this is a price quote request
result_totalNumberTotal number of results
time_msNumberTime taken for the request to complete in milliseconds

Example requests and responses

Programming language

Select the programming language you want to display the code examples in.

Get map data by bounding box
Request
Shell session
curl -X GET "https://api.houski.ca/map?abort_over=500000&api_key=YOUR_API_KEY&bbox_ne_lat=51.17345&bbox_ne_lng=-113.96269&bbox_sw_lat=50.87234&bbox_sw_lng=-114.22313&bedroom_gte=4&cluster_over=1000"
TypeScript code
const houski_map_data_bounding_box = async (): Promise<MapResponse> => {

    // You must copy the MapResponse type declarations from the 
    // Houski API documentation to strongly type the response

    const url = new URL('https://api.houski.ca/map');
    url.searchParams.set('abort_over', '500000');
    url.searchParams.set('api_key', 'YOUR_API_KEY');
    url.searchParams.set('bbox_ne_lat', '51.17345');
    url.searchParams.set('bbox_ne_lng', '-113.96269');
    url.searchParams.set('bbox_sw_lat', '50.87234');
    url.searchParams.set('bbox_sw_lng', '-114.22313');
    url.searchParams.set('bedroom_gte', '4');
    url.searchParams.set('cluster_over', '1000');

    const response = await fetch(url);
    const data = await response.json();

    return data;
}

(async () => {
let data: MapResponse = await houski_map_data_bounding_box();

// Log the response
console.log(data);
})();
Response
JSON
{
  "aborted": false,
  "cache_hit": true,
  "cost_cents": 0.13518500328063965,
  "data": {
    "clusters": [
      {
        "latitude": 51.13455581665039,
        "longitude": -114.14463806152344,
        "number_of_properties": 4570
      },
      {
        "latitude": 50.948692321777344,
        "longitude": -114.11646270751952,
        "number_of_properties": 3753
      },
      {
        "latitude": 50.91866683959961,
        "longitude": -113.98948669433594,
        "number_of_properties": 1875
      },
      {
        "latitude": 51.042999267578125,
        "longitude": -114.19219207763672,
        "number_of_properties": 4392
      },
      {
        "latitude": 51.04344940185547,
        "longitude": -114.10740661621094,
        "number_of_properties": 2025
      },
      {
        "latitude": 50.947654724121094,
        "longitude": -114.04849243164062,
        "number_of_properties": 1396
      },
      {
        "latitude": 51.1214599609375,
        "longitude": -114.18830871582033,
        "number_of_properties": 2721
      },
      {
        "latitude": 51.14665985107422,
        "longitude": -114.08708190917967,
        "number_of_properties": 2347
      },
      {
        "latitude": 51.11043930053711,
        "longitude": -113.96965789794922,
        "number_of_properties": 1234
      },
      {
        "latitude": 50.89536666870117,
        "longitude": -114.04856872558594,
        "number_of_properties": 2724
      }
    ],
    "heatmap": [],
    "properties": []
  },
  "error": "",
  "heatmap_aggregation_field": null,
  "heatmap_aggregation_max_value": null,
  "heatmap_aggregation_min_value": null,
  "heatmap_aggregation_type": null,
  "is_clusters": true,
  "is_heatmap": false,
  "is_heatmap_aggregation": null,
  "is_heatmap_aggregation_invert_intensity": null,
  "is_properties": false,
  "pagination": {
    "current_page": 1,
    "has_next_page": false,
    "has_previous_page": false,
    "page_total": 1
  },
  "price_quote": false,
  "result_total": 10,
  "time_ms": 88
}
Basic heatmap (property density)
Returns a heatmap based on property density within the bounding box.
Request
Shell session
curl -X GET "https://api.houski.ca/map?api_key=YOUR_API_KEY&bbox_ne_lat=51.17345&bbox_ne_lng=-113.96269&bbox_sw_lat=50.87234&bbox_sw_lng=-114.22313&heatmap=true&heatmap_cell_limit=10"
TypeScript code
const houski_map_data_basic_heatmap = async (): Promise<MapResponse> => {

    // You must copy the MapResponse type declarations from the 
    // Houski API documentation to strongly type the response

    const url = new URL('https://api.houski.ca/map');
    url.searchParams.set('api_key', 'YOUR_API_KEY');
    url.searchParams.set('bbox_ne_lat', '51.17345');
    url.searchParams.set('bbox_ne_lng', '-113.96269');
    url.searchParams.set('bbox_sw_lat', '50.87234');
    url.searchParams.set('bbox_sw_lng', '-114.22313');
    url.searchParams.set('heatmap', 'true');
    url.searchParams.set('heatmap_cell_limit', '10');

    const response = await fetch(url);
    const data = await response.json();

    return data;
}

(async () => {
let data: MapResponse = await houski_map_data_basic_heatmap();

// Log the response
console.log(data);
})();
Response
JSON
{
  "aborted": false,
  "cache_hit": true,
  "cost_cents": 2.475059986114502,
  "data": {
    "clusters": [],
    "heatmap": [
      {
        "aggregation_value": null,
        "intensity": 0.017429091036319733,
        "latitude": 51.20560836791992,
        "longitude": -113.9850845336914,
        "number_of_properties": 2206
      },
      {
        "aggregation_value": null,
        "intensity": 0.046385399997234344,
        "latitude": 50.919952392578125,
        "longitude": -114.17552185058594,
        "number_of_properties": 5871
      },
      {
        "aggregation_value": null,
        "intensity": 0.048084065318107605,
        "latitude": 51.20560836791992,
        "longitude": -114.17552185058594,
        "number_of_properties": 6086
      },
      {
        "aggregation_value": null,
        "intensity": 0.13312791287899017,
        "latitude": 51.20560836791992,
        "longitude": -114.0802993774414,
        "number_of_properties": 16850
      },
      {
        "aggregation_value": null,
        "intensity": 0.14140792191028595,
        "latitude": 51.110389709472656,
        "longitude": -113.9850845336914,
        "number_of_properties": 17898
      },
      {
        "aggregation_value": null,
        "intensity": 0.2591056227684021,
        "latitude": 51.01517105102539,
        "longitude": -113.9850845336914,
        "number_of_properties": 32795
      },
      {
        "aggregation_value": null,
        "intensity": 0.30532512068748474,
        "latitude": 50.919952392578125,
        "longitude": -113.9850845336914,
        "number_of_properties": 38645
      },
      {
        "aggregation_value": null,
        "intensity": 0.4178952276706696,
        "latitude": 51.01517105102539,
        "longitude": -114.17552185058594,
        "number_of_properties": 52893
      },
      {
        "aggregation_value": null,
        "intensity": 0.4955123662948608,
        "latitude": 51.110389709472656,
        "longitude": -114.0802993774414,
        "number_of_properties": 62717
      },
      {
        "aggregation_value": null,
        "intensity": 0.5194121599197388,
        "latitude": 51.110389709472656,
        "longitude": -114.17552185058594,
        "number_of_properties": 65742
      },
      {
        "aggregation_value": null,
        "intensity": 0.5272892713546753,
        "latitude": 50.919952392578125,
        "longitude": -114.0802993774414,
        "number_of_properties": 66739
      },
      {
        "aggregation_value": null,
        "intensity": 1.0,
        "latitude": 51.01517105102539,
        "longitude": -114.0802993774414,
        "number_of_properties": 126570
      }
    ],
    "properties": []
  },
  "error": "",
  "heatmap_aggregation_field": null,
  "heatmap_aggregation_max_value": null,
  "heatmap_aggregation_min_value": null,
  "heatmap_aggregation_type": "mean",
  "is_clusters": false,
  "is_heatmap": true,
  "is_heatmap_aggregation": false,
  "is_heatmap_aggregation_invert_intensity": false,
  "is_properties": false,
  "pagination": {
    "current_page": 1,
    "has_next_page": false,
    "has_previous_page": false,
    "page_total": 1
  },
  "price_quote": false,
  "result_total": 12,
  "time_ms": 185
}
Price heatmap with median aggregation
Returns a heatmap based on the median listing price of properties in each cell.
Request
Shell session
curl -X GET "https://api.houski.ca/map?api_key=YOUR_API_KEY&bbox_ne_lat=51.17345&bbox_ne_lng=-113.96269&bbox_sw_lat=50.87234&bbox_sw_lng=-114.22313&heatmap=true&heatmap_aggregation_field=estimate_list_price&heatmap_aggregation_type=median&heatmap_cell_limit=10"
TypeScript code
const houski_map_data_price_heatmap = async (): Promise<MapResponse> => {

    // You must copy the MapResponse type declarations from the 
    // Houski API documentation to strongly type the response

    const url = new URL('https://api.houski.ca/map');
    url.searchParams.set('api_key', 'YOUR_API_KEY');
    url.searchParams.set('bbox_ne_lat', '51.17345');
    url.searchParams.set('bbox_ne_lng', '-113.96269');
    url.searchParams.set('bbox_sw_lat', '50.87234');
    url.searchParams.set('bbox_sw_lng', '-114.22313');
    url.searchParams.set('heatmap', 'true');
    url.searchParams.set('heatmap_aggregation_field', 'estimate_list_price');
    url.searchParams.set('heatmap_aggregation_type', 'median');
    url.searchParams.set('heatmap_cell_limit', '10');

    const response = await fetch(url);
    const data = await response.json();

    return data;
}

(async () => {
let data: MapResponse = await houski_map_data_price_heatmap();

// Log the response
console.log(data);
})();
Response
JSON
{
  "aborted": false,
  "cache_hit": true,
  "cost_cents": 2.475059986114502,
  "data": {
    "clusters": [],
    "heatmap": [
      {
        "aggregation_value": 719932.0,
        "intensity": 0.653650164604187,
        "latitude": 50.919952392578125,
        "longitude": -114.17552185058594,
        "number_of_properties": 5871
      },
      {
        "aggregation_value": 756247.0,
        "intensity": 0.8194887042045593,
        "latitude": 51.110389709472656,
        "longitude": -114.17552185058594,
        "number_of_properties": 65742
      },
      {
        "aggregation_value": 576797.0,
        "intensity": 0.0,
        "latitude": 51.01517105102539,
        "longitude": -113.9850845336914,
        "number_of_properties": 32795
      },
      {
        "aggregation_value": 618384.0,
        "intensity": 0.1899140626192093,
        "latitude": 51.110389709472656,
        "longitude": -113.9850845336914,
        "number_of_properties": 17898
      },
      {
        "aggregation_value": 653475.0,
        "intensity": 0.3501630425453186,
        "latitude": 51.20560836791992,
        "longitude": -114.17552185058594,
        "number_of_properties": 6086
      },
      {
        "aggregation_value": 592261.0,
        "intensity": 0.07061896473169327,
        "latitude": 51.20560836791992,
        "longitude": -113.9850845336914,
        "number_of_properties": 2206
      },
      {
        "aggregation_value": 795775.0,
        "intensity": 1.0,
        "latitude": 51.01517105102539,
        "longitude": -114.17552185058594,
        "number_of_properties": 52893
      },
      {
        "aggregation_value": 683967.0,
        "intensity": 0.4894098937511444,
        "latitude": 50.919952392578125,
        "longitude": -113.9850845336914,
        "number_of_properties": 38645
      },
      {
        "aggregation_value": 683779.0,
        "intensity": 0.4885513484477997,
        "latitude": 51.110389709472656,
        "longitude": -114.0802993774414,
        "number_of_properties": 62717
      },
      {
        "aggregation_value": 613614.0,
        "intensity": 0.1681310385465622,
        "latitude": 51.01517105102539,
        "longitude": -114.0802993774414,
        "number_of_properties": 126570
      },
      {
        "aggregation_value": 666989.0,
        "intensity": 0.41187700629234314,
        "latitude": 50.919952392578125,
        "longitude": -114.0802993774414,
        "number_of_properties": 66739
      },
      {
        "aggregation_value": 641701.5,
        "intensity": 0.2963973581790924,
        "latitude": 51.20560836791992,
        "longitude": -114.0802993774414,
        "number_of_properties": 16850
      }
    ],
    "properties": []
  },
  "error": "",
  "heatmap_aggregation_field": "estimate_list_price",
  "heatmap_aggregation_max_value": 795775.0,
  "heatmap_aggregation_min_value": 576797.0,
  "heatmap_aggregation_type": "median",
  "is_clusters": false,
  "is_heatmap": true,
  "is_heatmap_aggregation": true,
  "is_heatmap_aggregation_invert_intensity": false,
  "is_properties": false,
  "pagination": {
    "current_page": 1,
    "has_next_page": false,
    "has_previous_page": false,
    "page_total": 1
  },
  "price_quote": false,
  "result_total": 12,
  "time_ms": 206
}
Get map data by polygon
Polygon requests are made from a string in the format of 'lat_lng,lat_lng,lat_lng...', for all of the polygon's points.
Request
Shell session
curl -X GET "https://api.houski.ca/map?abort_over=500000&address_regex=^1(1|2|3)(1|2|3|4|5).*$&api_key=YOUR_API_KEY&cluster_over=1000&polygon=51.0447_-114.0719,51.0544_-114.0719,51.0544_-114.0856,51.0452_-114.0856&results_per_page=3&select=address"
TypeScript code
const houski_map_data_polygon = async (): Promise<MapResponse> => {

    // You must copy the MapResponse type declarations from the 
    // Houski API documentation to strongly type the response

    const url = new URL('https://api.houski.ca/map');
    url.searchParams.set('abort_over', '500000');
    url.searchParams.set('address_regex', '^1(1|2|3)(1|2|3|4|5).*$');
    url.searchParams.set('api_key', 'YOUR_API_KEY');
    url.searchParams.set('cluster_over', '1000');
    url.searchParams.set('polygon', '51.0447_-114.0719,51.0544_-114.0719,51.0544_-114.0856,51.0452_-114.0856');
    url.searchParams.set('results_per_page', '3');
    url.searchParams.set('select', 'address');

    const response = await fetch(url);
    const data = await response.json();

    return data;
}

(async () => {
let data: MapResponse = await houski_map_data_polygon();

// Log the response
console.log(data);
})();
Response
JSON
{
  "aborted": false,
  "cache_hit": true,
  "cost_cents": 1.2000000476837158,
  "data": {
    "clusters": [],
    "heatmap": [],
    "properties": [
      {
        "address": "115 717 7 Avenue SW",
        "latitude": 51.04677963256836,
        "longitude": -114.07721710205078,
        "property_id": "1e387eddd1593196"
      },
      {
        "address": "1110 727 6 Avenue SW",
        "latitude": 51.04758834838867,
        "longitude": -114.07758331298828,
        "property_id": "263d02b678c59d1"
      },
      {
        "address": "1210 730 2 Avenue SW",
        "latitude": 51.05198669433594,
        "longitude": -114.07747650146484,
        "property_id": "2c257928d24a642e"
      }
    ]
  },
  "error": "",
  "heatmap_aggregation_field": null,
  "heatmap_aggregation_max_value": null,
  "heatmap_aggregation_min_value": null,
  "heatmap_aggregation_type": null,
  "is_clusters": false,
  "is_heatmap": false,
  "is_heatmap_aggregation": null,
  "is_heatmap_aggregation_invert_intensity": null,
  "is_properties": true,
  "pagination": {
    "current_page": 1,
    "has_next_page": true,
    "has_previous_page": false,
    "page_total": 23
  },
  "price_quote": false,
  "result_total": 68,
  "time_ms": 3292
}

Response type declarations

TypeScript code
interface MapResponse {
    aborted: boolean;
    cache_hit: boolean;
    cost_cents: number;
    data: MapData;
    error: string;
    is_clusters: boolean;
    is_properties: boolean;
    is_heatmap: boolean;
    is_heatmap_aggregation?: boolean | null;
    is_heatmap_aggregation_invert_intensity?: boolean | null;
    heatmap_aggregation_type?: string | null;
    heatmap_aggregation_max_value?: number | null;
    heatmap_aggregation_min_value?: number | null;
    heatmap_aggregation_field?: string | null;
    pagination: Pagination;
    price_quote: boolean;
    result_total: number;
    time_ms: number;
}

interface MapData {
    properties: Property[];
    clusters: Cluster[];
    heatmap: HeatPoint[];
}

interface Cluster {
    latitude: number;
    longitude: number;
    number_of_properties: number;
}

interface HeatPoint {
    latitude: number;
    longitude: number;
    intensity: number;
    number_of_properties: number;
    aggregation_value?: number | null;
}

// You can find the Property type on the /properties endpoint API docs
// https://www.houski.ca/api-documentation/properties