Most geographic information system (GIS) workflows that need property attributes hit the same wall. You have a polygon. Maybe it is a neighbourhood boundary, a school catchment, a transit corridor, a floodplain, or a custom study area you drew by hand. You want every property inside that polygon with structural attributes, valuations, and assessments attached. Then you want to load it into QGIS or ArcGIS, style it, and analyze it.
This is the kind of thing that used to require pulling raw property data from dozens of public, government, and crowdsourced data sources, cleaning them, geocoding them, and stitching them together. With the Houski map endpoint you can do it in a single API call and load the result straight into your GIS.
The map endpoint supports polygon shapes
The /api-documentation/map endpoint accepts a polygon parameter. Pass a series of latitude and longitude pairs separated by underscores, with pairs separated by commas, and Houski returns every property whose coordinates fall inside the closed polygon, with all the same fields available from the properties endpoint.
The underlying API call pulls every property inside a polygon, in a single request. The block below is a live call against the real map endpoint with a small Calgary polygon, the request code and the JSON response are generated every time this page is rendered:
from dataclasses import dataclass
from dataclasses_json import dataclass_json
import requests
params = {}
params['api_key'] = 'YOUR_API_KEY'
params['polygon'] = '51.05_-114.10,51.05_-114.05,51.02_-114.05,51.02_-114.10,51.05_-114.10'
params['property_type_eq'] = 'House'
params['select'] = 'property_id,address,latitude,longitude,construction_year,interior_sq_m,land_area_sq_m,bedroom,bathroom_full,assessment_value,assessment_year,estimate_list_price,score_flood,score_fire'
response = requests.get('https://api.houski.ca/map', params=params)
if response.status_code == 200:
json_data = response.json()
print(json_data)
# You must copy the MapResponse type declarations from the
# Houski API documentation to strongly type the response
typed_response = MapResponse.from_dict(json_data)
# Log the response
print(typed_response)
else:
print(f'Failed to get data: {response}')
{
"aborted": false,
"cache_hit": false,
"cost_cents": 6.2400007247924805,
"data": {
"clusters": [],
"heatmap": [],
"properties": [
{
"address": "6 1744 7 Street SW",
"bathroom_full": 2,
"bedroom": 3,
"construction_year": 2006,
"estimate_list_price": 660525,
"interior_sq_m": 125.882568359375,
"land_area_sq_m": 512.0,
"latitude": 51.03611755371094,
"longitude": -114.0792007446289,
"property_id": "10004f7afe0c1946",
"score_fire": 10,
"score_flood": 9
},
{
"address": "1005 815 14 Avenue SW",
"bathroom_full": 2,
"bedroom": 3,
"construction_year": 2006,
"estimate_list_price": 526728,
"interior_sq_m": 125.882568359375,
"land_area_sq_m": 512.0,
"latitude": 51.039894104003906,
"longitude": -114.08025360107422,
"property_id": "1002e3ad9cd64ae2",
"score_fire": 10,
"score_flood": 8
},
{
"address": "2018 608 9 Street SW",
"bathroom_full": 2,
"bedroom": 3,
"construction_year": 2006,
"estimate_list_price": 710248,
"interior_sq_m": 125.882568359375,
"land_area_sq_m": 512.0,
"latitude": 51.04768371582031,
"longitude": -114.0837173461914,
"property_id": "100556b0922cfec",
"score_fire": 10,
"score_flood": 8
},
{
"address": "506 140 10 Avenue SW",
"bathroom_full": 2,
"bedroom": 3,
"construction_year": 2006,
"estimate_list_price": 738457,
"interior_sq_m": 125.882568359375,
"land_area_sq_m": 512.0,
"latitude": 51.043495178222656,
"longitude": -114.0652847290039,
"property_id": "100c84d47be20042",
"score_fire": 10,
"score_flood": 9
},
{
"address": "6 327 19 Avenue SW",
"bathroom_full": 2,
"bedroom": 3,
"construction_year": 2006,
"estimate_list_price": 439490,
"interior_sq_m": 125.882568359375,
"land_area_sq_m": 512.0,
"latitude": 51.03612518310547,
"longitude": -114.07012176513672,
"property_id": "100e00db61b3aab7",
"score_fire": 10,
"score_flood": 2
},
{
"address": "1208 524 10 Avenue SW",
"bathroom_full": 2,
"bedroom": 3,
"construction_year": 2006,
"estimate_list_price": 461467,
"interior_sq_m": 125.882568359375,
"land_area_sq_m": 512.0,
"latitude": 51.043704986572266,
"longitude": -114.0721206665039,
"property_id": "100ed179c285e0fc",
"score_fire": 10,
"score_flood": 9
}
]
},
"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": 4340
},
"price_quote": false,
"result_total": 26038,
"time_ms": 167
}
From the response, a short Python script converts each row to a GeoJSON Point feature and writes a study_area_properties.geojson file. In QGIS, drag that file onto the canvas. Properties show up as a point layer with every attribute attached. In ArcGIS Pro, use Add Data and point at the file. Same result.
Style by any field
Because the GeoJSON carries every field you selected, you can style or filter without leaving your GIS:
- Graduated symbols by estimate_list_price to visualize value gradients across the polygon.
- Categorized symbols by construction_year decade to surface heritage zones or post-war build waves.
- Filtered selections where score_flood is in the bottom quartile to focus on at-risk properties (remember, higher score is safer, so the bottom quartile is the at-risk group).
- Heatmaps weighted by assessment_value to compare assessed land use density inside versus outside a corridor.
Once the GeoJSON is in your GIS, the usual spatial analysis toolkit works as expected. Buffer, intersect, join to census tracts, run nearest-neighbour, build proximity raster surfaces.
A few practical patterns from working with planners
Catchment-bounded pricing context
Drop a school catchment boundary as a polygon. Pull every home inside it. The area_residential_list_price_per_sq_m field gives you surrounding-area list-price context for every home in the catchment, ready to style or summarize without any extra joins.
Floodplain exposure inventory
Pull the polygon for a 1-in-100-year floodplain from your provincial open data. Run the Houski map call to get every property inside it. Sum assessment_value for an exposed-value estimate. Filter by score_flood to identify properties that have additional exposure beyond the floodplain alone.
Transit corridor uplift studies
Draw a polygon 400 metres on either side of a planned light rail transit (LRT) alignment. Pull estimate_list_price and assessment_value for everything inside. Snapshot the result now and re-run the same pull on a schedule going forward to build the before-and-after series, and use the predict endpoint for date-conditioned values.
Heritage area characterization
Filter the polygon results by construction_year_lte=1945 to see how much of a study area is pre-war stock. Combine with roof_material and foundation_type for a quick build-stock characterization without a windshield survey.
Going larger than one polygon
If your study area is larger than a single API page, the map endpoint supports pagination through results_per_page and page. For very large jurisdictional pulls, the /api-documentation/properties endpoint with city_eq and community_eq filters is usually faster than polygon-bounded calls because it can match against indexed canonical fields.
If you want neighbourhood-level statistics rather than individual properties, the /api-documentation/aggregate endpoint returns medians, means, sums, and counts grouped by city or community in one call. That is the right tool for choropleth maps at the neighbourhood scale.
Why this matters for GIS shops
Most GIS teams either build their own scraping pipelines and maintain them forever, or pay enterprise prices for siloed data feeds. Houski covers more than 19 million Canadian properties through one consistent API, with structural details, valuations, assessments, and risk scores already attached. Pricing is pay-as-you-go with a $99 USD monthly minimum, which puts it within reach of a single analyst at a small firm as easily as a regional planning department or an engineering consultancy.
A planner who can answer "give me every detached home built before 1960 with a flood safety score in the bottom quartile inside this polygon" in under a minute is a planner whose internal customers love them.
Getting started
Spin up an API key from the quick-start guide, and try a small polygon first to verify the field selection. The /api-documentation/map endpoint documentation lists every supported parameter, including bounding-box filters as an alternative to polygon shapes.
From there, plug it into your QGIS or ArcGIS workflow and stop hand-stitching raw data feeds.
