Here is a query that does the opposite of what most people expect the first time they write it:
const houski_data = async (): Promise<PropertiesResponse> => {
// You must copy the PropertiesResponse type declarations from the
// Houski API documentation to strongly type the response
const url = new URL('https://api.houski.ca/properties');
url.searchParams.set('api_key', 'YOUR_API_KEY');
url.searchParams.set('city', 'calgary');
url.searchParams.set('country_abbreviation', 'ca');
url.searchParams.set('province_abbreviation', 'ab');
url.searchParams.set('results_per_page', '10');
url.searchParams.set('score_flood_lte', '2');
url.searchParams.set('select', 'address,postal_code,community,score_flood,basement_type,foundation_type,construction_year');
const response = await fetch(url);
const data = await response.json();
return data;
}
(async () => {
let data: PropertiesResponse = await houski_data();
// Log the response
console.log(data);
})();
{
"cache_hit": false,
"cost_cents": 4.399999618530273,
"data": [
{
"address": "205 317 19 Avenue SW",
"basement_type": "None",
"community": "Mission",
"construction_year": 1981,
"foundation_type": "Wood",
"postal_code": "T2S0E1",
"property_id": "100a9d1cecc37def",
"score_flood": 2
},
{
"address": "133 Cranbrook Garden SE",
"basement_type": "Full",
"community": "Cranston",
"construction_year": 2021,
"foundation_type": "Wood",
"postal_code": "T3M2L7",
"property_id": "100b8c86bda22410",
"score_flood": 0
},
{
"address": "6 327 19 Avenue SW",
"basement_type": "Full",
"community": "Beltline",
"construction_year": 2006,
"foundation_type": "Wood",
"postal_code": "T2S0E1",
"property_id": "100e00db61b3aab7",
"score_flood": 2
},
{
"address": "172 Wolf Hollow Villas SE",
"basement_type": "Full",
"community": "Wolf Willow",
"construction_year": 2025,
"foundation_type": "Wood",
"postal_code": "T2X5X2",
"property_id": "10119160d4272f45",
"score_flood": 2
},
{
"address": "120 1212 1 Street SE",
"basement_type": "Full",
"community": "Beltline",
"construction_year": 2006,
"foundation_type": "Wood",
"postal_code": "T2G2H8",
"property_id": "1011f1f9b58bf05c",
"score_flood": 2
},
{
"address": "14 616 24 Avenue SW",
"basement_type": "Full",
"community": "Cliff Bungalow",
"construction_year": 1978,
"foundation_type": "Wood",
"postal_code": "T2S0K6",
"property_id": "1014bab4a85812e5",
"score_flood": 1
},
{
"address": "1172 Cranbrook Gardens SE",
"basement_type": "Full",
"community": "Unknown",
"construction_year": 2023,
"foundation_type": "Wood",
"postal_code": "T3M3B9",
"property_id": "101fcf6159f84782",
"score_flood": 0
},
{
"address": "18 Cranbrook Cove SE",
"basement_type": "Full",
"community": "Cranston",
"construction_year": 2019,
"foundation_type": "Wood",
"postal_code": "T3M2S9",
"property_id": "10233bd64a3e4418",
"score_flood": 1
},
{
"address": "308 2416 Erlton Street SW",
"basement_type": "None",
"community": "Erlton",
"construction_year": 2003,
"foundation_type": "Wood",
"postal_code": "T2S3B7",
"property_id": "102bec2fb04f61e8",
"score_flood": 1
},
{
"address": "907 85 Quarry Park Road SE",
"basement_type": "Full",
"community": "Douglasdale-Glen",
"construction_year": 2006,
"foundation_type": "Wood",
"postal_code": "T2C5V5",
"property_id": "103f4fac4760468e",
"score_flood": 0
}
],
"error": "",
"pagination": {
"current_page": 1,
"has_next_page": true,
"has_previous_page": false,
"page_total": 872
},
"price_quote": false,
"result_total": 8720,
"time_ms": 59,
"ui_info": {
"city": "Calgary",
"city_id": "6ec95b53075d062c",
"city_link": "ca/ab/calgary",
"city_slug": "calgary",
"country": "Canada",
"country_abbreviation": "CA",
"country_abbreviation_id": "9ace2b6431b7f1be",
"country_abbreviation_link": "ca",
"country_slug": "canada",
"province": "Alberta",
"province_abbreviation": "AB",
"province_abbreviation_id": "aae1f05a0f89d2c7",
"province_abbreviation_link": "ca/ab",
"province_slug": "alberta"
}
}
If you read score_flood as a flood risk score, you just asked for the safest properties in Calgary. You actually got the most exposed ones.
Every score Houski publishes runs from 0 to 10, and on every single one of them, higher is better. There are no exceptions. Not for flood, not for fire, not for earthquake, hurricane, or tornado. A 9 is always good news and a 0 is always bad news, whatever the score is measuring.
This is the single most common misread of our data, so it is worth spending a page on.
Why it works this way
The alternative is worse. If some scores were oriented one way and others the reverse, every person using them would have to keep a mental table of which is which, and every model trained on them would need a sign flip applied per field by hand. One person forgets, and the model learns that flood danger predicts higher value.
So the rule is absolute. Higher is better. Always. If a number goes up, the property got better in that respect.
The consequence is that the risk scores are not risk scores. They are safety scores. score_flood is flood safety. score_fire is fire safety. score_earthquake is earthquake safety. A 10 on score_earthquake means the ground under the area is unlikely to shake, not that it is guaranteed to.
Once that clicks, the filters read naturally. Low score means exposed. High score means safe.
const houski_data = async (): Promise<PropertiesResponse> => {
// You must copy the PropertiesResponse type declarations from the
// Houski API documentation to strongly type the response
const url = new URL('https://api.houski.ca/properties');
url.searchParams.set('api_key', 'YOUR_API_KEY');
url.searchParams.set('city', 'calgary');
url.searchParams.set('country_abbreviation', 'ca');
url.searchParams.set('province_abbreviation', 'ab');
url.searchParams.set('results_per_page', '10');
url.searchParams.set('score_fire_gte', '7');
url.searchParams.set('score_flood_gte', '8');
url.searchParams.set('select', 'address,postal_code,community,score_flood,score_fire,estimate_sale_price');
const response = await fetch(url);
const data = await response.json();
return data;
}
(async () => {
let data: PropertiesResponse = await houski_data();
// Log the response
console.log(data);
})();
{
"cache_hit": false,
"cost_cents": 3.3999996185302734,
"data": [
{
"address": "31 Hawkside Park NW",
"community": "Hawkwood",
"estimate_sale_price": 652319,
"postal_code": "T3G2W3",
"property_id": "10000f97f5cb7b9f",
"score_fire": 8,
"score_flood": 10
},
{
"address": "6 1744 7 Street SW",
"community": "Beltline",
"estimate_sale_price": 826706,
"postal_code": "T2T2W6",
"property_id": "10004f7afe0c1946",
"score_fire": 10,
"score_flood": 9
},
{
"address": "28 Sundown Gr SE",
"community": "Sundance",
"estimate_sale_price": 781636,
"postal_code": "T2X3G3",
"property_id": "1001109ab2aebbc0",
"score_fire": 8,
"score_flood": 10
},
{
"address": "C304 4501 37 Street NW",
"community": "Beltline",
"estimate_sale_price": 963101,
"postal_code": "T2L2J5",
"property_id": "10013b5e28e0c630",
"score_fire": 8,
"score_flood": 9
},
{
"address": "1011 Olympia Crescent SE",
"community": "Ogden",
"estimate_sale_price": 494909,
"postal_code": "T2C1G6",
"property_id": "1001ffcbf6c0248c",
"score_fire": 8,
"score_flood": 8
},
{
"address": "432 27 Avenue NW",
"community": "Mount Pleasant",
"estimate_sale_price": 1166097,
"postal_code": "T2M2H6",
"property_id": "10021e44aa219b00",
"score_fire": 10,
"score_flood": 10
},
{
"address": "2206 10 Avenue SW",
"community": "Sunalta",
"estimate_sale_price": 3380693,
"postal_code": "T3C0K6",
"property_id": "10023888bdd1ce5d",
"score_fire": 8,
"score_flood": 8
},
{
"address": "1516 49 Street SE",
"community": "Forest Lawn",
"estimate_sale_price": 465441,
"postal_code": "T2A1S1",
"property_id": "10024c6023d6ca9",
"score_fire": 8,
"score_flood": 10
},
{
"address": "17 125 23 Avenue SW",
"community": "Mission",
"estimate_sale_price": 266879,
"postal_code": "T2S0H9",
"property_id": "10025933fa932bff",
"score_fire": 10,
"score_flood": 8
},
{
"address": "2 2022 11 Avenue SW",
"community": "Sunalta",
"estimate_sale_price": 190114,
"postal_code": "T3C0P1",
"property_id": "10027a59d3becf43",
"score_fire": 8,
"score_flood": 9
}
],
"error": "",
"pagination": {
"current_page": 1,
"has_next_page": true,
"has_previous_page": false,
"page_total": 37172
},
"price_quote": false,
"result_total": 371720,
"time_ms": 75,
"ui_info": {
"city": "Calgary",
"city_id": "6ec95b53075d062c",
"city_link": "ca/ab/calgary",
"city_slug": "calgary",
"country": "Canada",
"country_abbreviation": "CA",
"country_abbreviation_id": "9ace2b6431b7f1be",
"country_abbreviation_link": "ca",
"country_slug": "canada",
"province": "Alberta",
"province_abbreviation": "AB",
"province_abbreviation_id": "aae1f05a0f89d2c7",
"province_abbreviation_link": "ca/ab",
"province_slug": "alberta"
}
}
That is the low-exposure query. Both scores high, both hazards unlikely.
The bands
Each score carries its own description in the fields reference, but they share a shape. Using flood as the example:
- 0 to 2 - Very high flood exposure. The surrounding area floods readily.
- 3 to 4 - High flood exposure. The area sees significant flooding.
- 5 to 6 - Moderate flood safety. Some flood-prone conditions nearby.
- 7 to 8 - High flood safety. The area floods only rarely.
- 9 to 10 - Very high flood safety. The surrounding area is very unlikely to flood.
The same 0 to 10 shape applies to the amenity and livability scores, where the reading is more intuitive because nobody expects score_education to be backwards. High education score, good schools nearby. High score_parking, plenty of parking supply. High score_nature, good access to green space.
They describe the area, not the property
This is the second thing to internalise, and it is related to the first.
A score is about the surroundings. score_flood does not claim your specific house will flood. The house might sit on a rise and stay dry through everything. But if the area around it floods, the roads flood, the utilities go down, the services stop, and the value and the insurance premium move regardless of whether water ever touches the foundation. That is what the score is telling you, and it is genuinely the more useful thing to know at the area level.
So treat a low score as a prompt to look harder at the individual property, not as a verdict on it. The score narrows where you look. It does not replace looking.
Fire is a neighbourhood score on purpose
score_fire deserves its own paragraph, because people ask why it is not sharper.
Fire safety is computed across a neighbourhood-scale window, roughly one and a half kilometres. That is deliberate, and it is not a limitation we are working around. Houses sit on cleared, non-fuel land. If you scored fire per pixel, every house in the country would come back safe, because the pixel under a house has no fuel in it. The number would be true and completely useless.
What actually burns houses is the fuel around them and the fire behaviour of the landscape they sit in. That is a neighbourhood property, so it gets measured at neighbourhood scale. Flood is different - water finds elevation, so per-pixel is meaningful there, and score_flood is computed accordingly.
Two scores, two scales, because the underlying physics is different. Anyone who tells you they have per-house wildfire risk from raster data is selling you a number that does not mean what they say it means.
The full set
Hazard safety - score_flood, score_fire, score_earthquake, score_hurricane, score_tornado
Environment - score_air_quality, score_water_quality, score_quiet, score_smell
Connectivity - score_internet, score_cell_coverage
Getting around - score_walkability, score_transit, score_bicycle, score_parking, score_traffic
Amenities and life - score_education, score_family, score_entertainment, score_food_and_drink, score_nature, score_shopping, score_safety, score_retirement, score_curb_appeal
The composite - score_total is the Houski score, a proprietary 1 to 10 rating of overall property quality and desirability, with score_total_percent alongside it.
The complete list, each with its own banding and description, lives in the fields reference.
Using them well
Do not invert them. If you are naming a filter, a preset, or a column in your own product, name it positively. "Flood safety" reads correctly. "Flood risk" pointed at score_flood is a bug waiting to happen, because the next person to touch the code will assume high means dangerous.
Do not sum them blindly. A property with a 10 on entertainment and a 2 on quiet is not a 6 on average, it is a downtown condo. Weight them for what you are actually deciding.
Do combine them with property fields. The scores tell you about the area. The property fields tell you about the building. Underwriting an old house in a flood-exposed area is a different question from underwriting a new one on the same street.
const houski_data = async (): Promise<PropertiesResponse> => {
// You must copy the PropertiesResponse type declarations from the
// Houski API documentation to strongly type the response
const url = new URL('https://api.houski.ca/properties');
url.searchParams.set('api_key', 'YOUR_API_KEY');
url.searchParams.set('city', 'calgary');
url.searchParams.set('construction_year_lte', '1980');
url.searchParams.set('country_abbreviation', 'ca');
url.searchParams.set('province_abbreviation', 'ab');
url.searchParams.set('results_per_page', '10');
url.searchParams.set('score_flood_lte', '3');
url.searchParams.set('select', 'address,postal_code,score_flood,construction_year,basement_type,foundation_type,floor_below_ground');
const response = await fetch(url);
const data = await response.json();
return data;
}
(async () => {
let data: PropertiesResponse = await houski_data();
// Log the response
console.log(data);
})();
{
"cache_hit": false,
"cost_cents": 5.299999713897705,
"data": [
{
"address": "5852 Bow Crescent NW",
"basement_type": "Full",
"construction_year": 1980,
"floor_below_ground": 1,
"foundation_type": "Wood",
"postal_code": "T3B2B7",
"property_id": "100af602324e3847",
"score_flood": 3
},
{
"address": "14 616 24 Avenue SW",
"basement_type": "Full",
"construction_year": 1978,
"floor_below_ground": 1,
"foundation_type": "Wood",
"postal_code": "T2S0K6",
"property_id": "1014bab4a85812e5",
"score_flood": 1
},
{
"address": "201 934 2 Avenue NW",
"basement_type": "Full",
"construction_year": 1969,
"floor_below_ground": 1,
"foundation_type": "Wood",
"postal_code": "T2N0E6",
"property_id": "102368d69b982464",
"score_flood": 3
},
{
"address": "5203 13 Avenue NW",
"basement_type": "Full",
"construction_year": 1952,
"floor_below_ground": 1,
"foundation_type": "Wood",
"postal_code": "T3B4S3",
"property_id": "1032b9768684b5c5",
"score_flood": 3
},
{
"address": "6A 133 25 Avenue SW",
"basement_type": "None",
"construction_year": 1976,
"floor_below_ground": 1,
"foundation_type": "Wood",
"postal_code": "T2S0K8",
"property_id": "1072aaede1d7b960",
"score_flood": 2
},
{
"address": "2 3927 Edmonton Trail NE",
"basement_type": "Full",
"construction_year": 1976,
"floor_below_ground": 1,
"foundation_type": "Wood",
"postal_code": "T2E6T1",
"property_id": "1076ba3e5747f800",
"score_flood": 1
},
{
"address": "212 38 Avenue SW",
"basement_type": "Full",
"construction_year": 1912,
"floor_below_ground": 1,
"foundation_type": "Wood",
"postal_code": "T2T2J3",
"property_id": "107e54c1cecf701b",
"score_flood": 1
},
{
"address": "7 928 3 Avenue NW",
"basement_type": "Full",
"construction_year": 1977,
"floor_below_ground": 1,
"foundation_type": "Wood",
"postal_code": "T2N0J6",
"property_id": "10aa49472a1b5c0a",
"score_flood": 3
},
{
"address": "B6 624 Beaver Dam Road NE",
"basement_type": "Full",
"construction_year": 1978,
"floor_below_ground": 1,
"foundation_type": "Wood",
"postal_code": "T2K4W6",
"property_id": "10d7b1324d109454",
"score_flood": 3
},
{
"address": "6232 Bow Crescent NW",
"basement_type": "Full",
"construction_year": 1969,
"floor_below_ground": 1,
"foundation_type": "Wood",
"postal_code": "T3B2B9",
"property_id": "111af2bc9dbfd167",
"score_flood": 3
}
],
"error": "",
"pagination": {
"current_page": 1,
"has_next_page": true,
"has_previous_page": false,
"page_total": 125
},
"price_quote": false,
"result_total": 1248,
"time_ms": 62,
"ui_info": {
"city": "Calgary",
"city_id": "6ec95b53075d062c",
"city_link": "ca/ab/calgary",
"city_slug": "calgary",
"country": "Canada",
"country_abbreviation": "CA",
"country_abbreviation_id": "9ace2b6431b7f1be",
"country_abbreviation_link": "ca",
"country_slug": "canada",
"province": "Alberta",
"province_abbreviation": "AB",
"province_abbreviation_id": "aae1f05a0f89d2c7",
"province_abbreviation_link": "ca/ab",
"province_slug": "alberta"
}
}
Exposed area, old building, basement below grade. That is a real exposure question rather than a map colour.
The pre-built version
If you would rather have the list than write the query, the datasets page has the hazard cuts already assembled - flood risk properties, fire risk properties, wildland-urban interface homes, multi-hazard exposure, earthquake risk properties. Each one is built on these scores with the orientation already handled correctly, and each updates daily.
The rule is one sentence and it never bends: higher is better, on every score, always. If you remember nothing else from this post, remember that the flood filter you are about to write probably points the wrong way. Browse the fields reference or explore the datasets.
