Canadian insured catastrophe losses smashed every record in 2024, with CatIQ tallying roughly $8.5 billion in total insured losses, driven largely by the August Calgary hailstorm, the Jasper wildfire complex, the Toronto and southern Quebec flooding events, and a late-season Atlantic system. Reinsurance renewals at the start of 2026 hardened again. Treaty capacity for Canadian property is more expensive, more conditional, and more data-hungry than at any point in recent memory.
If you are a property and casualty underwriter, an actuary, a reinsurance analyst, or a climate risk officer reading this, you already know the punchline. The old approach of pricing fire and water perils off three-character postal code rate tables and a vague nod to "the wildland urban interface" is not going to survive the next treaty cycle. You need defensible, geocoded, programmatic risk data at the address level. Not at the forward sortation area (FSA) level. Not at the dissemination area level. The address.
That is what this post is about. I am going to walk you through how Houski exposes per-property climate safety scores across all 19 million plus Canadian properties in the database, how to combine those scores with construction characteristics for sharper loss modelling, and how to operationalize the whole thing inside an underwriting workflow. By the end you should have a clear path from a single endpoint call to a portfolio-level concentration report.
Why postal-code-averaged underwriting is breaking
Let me be blunt about why this matters. A T2N postal code in northwest Calgary contains both a 1962 bungalow with cedar shake siding sitting in a treed coulee and a 2019 Built Green concrete-tile townhouse on a graded interior lot. Same FSA. Same legacy rate. Wildly different probable maximum loss for both wildfire and hail.
The actuarial cost of pretending these two properties belong in the same risk bucket has always been non-zero. In a 1990s climate it was tolerable, because the tail was thin and the reinsurance was cheap. In a 2026 climate it is not tolerable, because:
- Wildfire seasons in BC and Alberta have stayed brutal four years running. Lytton, Fort McMurray, West Kelowna, Jasper, and the 2025 Okanagan complex are not outliers anymore, they are the trend line.
- Atlantic Canada hurricanes in the Fiona-and-after era are reshaping coastal underwriting from the Annapolis Valley to Cape Breton to Newfoundland's Avalon Peninsula.
- Convective storm losses (hail and severe wind) on the Prairies are the single largest contributor to Canadian insured cat losses most years.
- The federal flood insurance program is finally rolling out, which means private carriers need to know exactly which properties are inside, adjacent to, or far from designated high-risk flood zones, because those properties will reprice fastest.
- Reinsurance treaties now expect address-resolved exposure files, not aggregated rollups. Try negotiating a Canadian property cat treaty without a per-risk dataset and watch what happens to your rate on line.
Postal-code averaging is essentially a cross-subsidy from low-risk insureds to high-risk insureds inside the same FSA. In a soft market that is fine. In a hard market your low-risk insureds get poached by a competitor who can price them more accurately, and you are left with the adverse selection.
The fix is per-property data. That is what we built Houski to deliver.
How Houski's climate safety scores work
Before any code, the orientation rule, because this trips up everyone the first time.
Every score field in Houski that starts with score_ is normalized to a 0 to 10 scale where higher means safer. This applies to:
- score_flood
- score_fire
- score_earthquake
- score_hurricane
- score_tornado
- score_air_quality
- score_water_quality
A property with score_flood of 9 has very high flood safety, meaning very low flood risk. A property with score_flood of 1 has very low flood safety, meaning very high flood risk. The convention is consistent across every score field in the system. When you build presets, name them positively ("flood safety score"), and when you filter for low-risk exposure use the _gte suffix.
The scores themselves are assembled from public, government, and crowdsourced data sources. Flood is computed per location using the property's exact lat and lon, not snapped to a centroid of any administrative polygon. Fire is deliberately a neighbourhood-scale score, evaluated over roughly 1.5 kilometres around the property, because what burns houses is the fuel around them, not the lot itself.
That last point matters for underwriting because two properties on the same street can sit on opposite sides of a flood zone boundary, and the data has to reflect that.
Example one: pulling a single property's climate risk profile
Let us say you are quoting a homeowner policy on 123 Main Street in some Canadian community. You have geocoded the address (or you are using Houski's /geocoding endpoint to do it, your call). Now you want the full climate safety profile plus the address echo and coordinates for your file.
Address lookups on /properties take the bare address parameter together with city and province_abbreviation, so the endpoint can resolve the parcel from the four-part location key. The block below is a live call against the real API, so the request code and the JSON response always reflect the current schema and current data:
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('select', 'address,city,province_abbreviation,latitude,longitude,score_flood,score_fire,score_earthquake,score_hurricane,score_tornado');
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.3600001335144043,
"data": [
{
"address": "31 Hawkside Park NW",
"city": "Calgary",
"latitude": 51.12946319580078,
"longitude": -114.17919921875,
"property_id": "10000f97f5cb7b9f",
"province_abbreviation": "AB",
"score_earthquake": 9,
"score_fire": 8,
"score_flood": 10,
"score_hurricane": 10,
"score_tornado": 8
},
{
"address": "6 1744 7 Street SW",
"city": "Calgary",
"latitude": 51.03611755371094,
"longitude": -114.0792007446289,
"property_id": "10004f7afe0c1946",
"province_abbreviation": "AB",
"score_earthquake": 9,
"score_fire": 10,
"score_flood": 9,
"score_hurricane": 10,
"score_tornado": 8
},
{
"address": "384 Copperpond Landng SE",
"city": "Calgary",
"latitude": 50.925743103027344,
"longitude": -113.92975616455078,
"property_id": "10007f9761f49940",
"province_abbreviation": "AB",
"score_earthquake": 9,
"score_fire": 5,
"score_flood": 8,
"score_hurricane": 10,
"score_tornado": 8
},
{
"address": "239 Dalhurst Way NW",
"city": "Calgary",
"latitude": 51.110740661621094,
"longitude": -114.1513900756836,
"property_id": "100086f6bc064d3f",
"province_abbreviation": "AB",
"score_earthquake": 9,
"score_fire": 5,
"score_flood": 10,
"score_hurricane": 10,
"score_tornado": 8
},
{
"address": "52 Cedargrove Way SW",
"city": "Calgary",
"latitude": 50.95145034790039,
"longitude": -114.12571716308594,
"property_id": "1000c277cd905d3b",
"province_abbreviation": "AB",
"score_earthquake": 9,
"score_fire": 5,
"score_flood": 10,
"score_hurricane": 10,
"score_tornado": 8
},
{
"address": "28 Sundown Gr SE",
"city": "Calgary",
"latitude": 50.899044036865234,
"longitude": -114.04895782470705,
"property_id": "1001109ab2aebbc0",
"province_abbreviation": "AB",
"score_earthquake": 9,
"score_fire": 8,
"score_flood": 10,
"score_hurricane": 10,
"score_tornado": 8
}
],
"error": "",
"pagination": {
"current_page": 1,
"has_next_page": true,
"has_previous_page": false,
"page_total": 113490
},
"price_quote": false,
"result_total": 680936,
"time_ms": 1626,
"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"
}
}
How to read scores like these for underwriting. Suppose a Calgary property comes back with score_flood of 8, score_fire of 6, score_earthquake of 9, score_hurricane of 10, and score_tornado of 5:
- score_flood of 8 is solidly above-average flood safety. This property is not in a designated floodplain, but is not on the highest ground in the city either.
- score_fire of 6 is mid-pack. Worth checking the surrounding fuel load and the roof material before quoting. Prairie cities have variable wildland urban interface exposure depending on the river valley and ravine system.
- score_earthquake of 9 reflects low seismicity in southern Alberta.
- score_hurricane of 10 is essentially the floor of hurricane risk in inland Canada.
- score_tornado of 5 is meaningfully exposed. Southern Alberta, southern Manitoba, southern Saskatchewan, and southwestern Ontario all sit on the active end of the Canadian tornado climatology.
Notice the framing throughout: high score equals safety. Never invert in your code or your dashboards. Carriers that wire it backwards end up renewing the worst part of their book at concession pricing because their internal "risk score" is actually a safety score. Get the convention right at ingest.
Example two: bulk-screening a 50,000-property portfolio
This is the workflow that pays for itself the fastest. You have a renewal book, or an acquired book, or a quote-shopping list, and you want to flag concentration in low-safety zones for any specific peril.
We would loop through your policy admin export in batches, posting property IDs to /properties, pulling back just the score columns plus the join key, then aggregating in pandas. The primary underlying call looks like this:
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('property_id_in', 'bd9c6fb24c31c772');
url.searchParams.set('results_per_page', '500');
url.searchParams.set('select', 'property_id,address,city,province_abbreviation,latitude,longitude,score_flood,score_fire,score_earthquake,score_hurricane,score_tornado,construction_year,roof_material,exterior_finish,foundation_type');
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": 0.9600000977516174,
"data": [
{
"address": "302 610 17 Avenue SW",
"city": "Calgary",
"construction_year": 1979,
"exterior_finish": "Brick",
"foundation_type": "Wood",
"latitude": 51.03819274902344,
"longitude": -114.07510375976562,
"property_id": "bd9c6fb24c31c772",
"province_abbreviation": "AB",
"roof_material": "Asphalt",
"score_earthquake": 9,
"score_fire": 9,
"score_flood": 9,
"score_hurricane": 10,
"score_tornado": 8
}
],
"error": "",
"pagination": {
"current_page": 1,
"has_next_page": false,
"has_previous_page": false,
"page_total": 1
},
"price_quote": false,
"result_total": 1,
"time_ms": 54,
"ui_info": {}
}
What this approach gives you, in roughly the time it takes to drink a coffee, is a defensible picture of where in your book the climate risk is actually concentrated. Not by FSA. By address.
Aggregated by province, the response from the call above becomes the kind of table you put in front of your chief underwriting officer when you propose a non-renewal program for a specific geography, or when you propose tightening eligibility on cedar shake roofs in interface zones. It is also the kind of table your reinsurance broker will ask for when they market your treaty.
Combining climate scores with construction characteristics
Climate scores tell you what the hazard is. Construction characteristics tell you what the property does when the hazard arrives. Loss modelling is the product of the two.
Houski exposes the construction fields you need on the same /properties endpoint, so you can pull risk and construction in one call:
- construction_year (integer, the year built)
- roof_material (asphalt shingle, metal, clay tile, cedar shake, membrane, etc.)
- exterior_finish (vinyl siding, brick, stucco, fibre cement, wood siding, etc.)
- foundation_type (poured concrete, concrete block, crawl space, slab, basement)
- property_type, interior_sq_m, floor_above_ground for additional context
Some of the underwriting heuristics that pop out the moment you have these two datasets joined together:
- Cedar shake roof plus score_fire under 6 is a different risk class than asphalt shingle plus score_fire under 6. Same hazard, very different vulnerability.
- A finished basement on a property with score_flood under 5 is a higher claim severity per event than a slab-on-grade in the same zone.
- Brick veneer plus construction_year after 2010 in a score_tornado zone behaves better than vinyl siding plus pre-1990 construction in the same zone.
- Older construction_year plus low score_earthquake in southwestern BC raises seismic retrofit questions before binding.
The block below is a live call against the real API showing both bands of data pulled in a single request:
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('select', 'address,latitude,longitude,construction_year,roof_material,exterior_finish,foundation_type,interior_sq_m,score_flood,score_fire,score_earthquake,score_hurricane,score_tornado');
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": 6.2400007247924805,
"data": [
{
"address": "31 Hawkside Park NW",
"construction_year": 1988,
"exterior_finish": "Vinyl",
"foundation_type": "Wood",
"interior_sq_m": 126.34708404541016,
"latitude": 51.12946319580078,
"longitude": -114.17919921875,
"property_id": "10000f97f5cb7b9f",
"roof_material": "Asphalt",
"score_earthquake": 9,
"score_fire": 8,
"score_flood": 10,
"score_hurricane": 10,
"score_tornado": 8
},
{
"address": "6 1744 7 Street SW",
"construction_year": 2006,
"exterior_finish": "Vinyl",
"foundation_type": "Wood",
"interior_sq_m": 125.882568359375,
"latitude": 51.03611755371094,
"longitude": -114.0792007446289,
"property_id": "10004f7afe0c1946",
"roof_material": "Asphalt",
"score_earthquake": 9,
"score_fire": 10,
"score_flood": 9,
"score_hurricane": 10,
"score_tornado": 8
},
{
"address": "384 Copperpond Landng SE",
"construction_year": 2006,
"exterior_finish": "Vinyl",
"foundation_type": "Wood",
"interior_sq_m": 125.882568359375,
"latitude": 50.925743103027344,
"longitude": -113.92975616455078,
"property_id": "10007f9761f49940",
"roof_material": "Asphalt",
"score_earthquake": 9,
"score_fire": 5,
"score_flood": 8,
"score_hurricane": 10,
"score_tornado": 8
},
{
"address": "239 Dalhurst Way NW",
"construction_year": 1971,
"exterior_finish": "Vinyl",
"foundation_type": "Wood",
"interior_sq_m": 108.46339416503906,
"latitude": 51.110740661621094,
"longitude": -114.1513900756836,
"property_id": "100086f6bc064d3f",
"roof_material": "Asphalt",
"score_earthquake": 9,
"score_fire": 5,
"score_flood": 10,
"score_hurricane": 10,
"score_tornado": 8
},
{
"address": "52 Cedargrove Way SW",
"construction_year": 1984,
"exterior_finish": "Vinyl",
"foundation_type": "Wood",
"interior_sq_m": 136.4734344482422,
"latitude": 50.95145034790039,
"longitude": -114.12571716308594,
"property_id": "1000c277cd905d3b",
"roof_material": "Asphalt",
"score_earthquake": 9,
"score_fire": 5,
"score_flood": 10,
"score_hurricane": 10,
"score_tornado": 8
},
{
"address": "28 Sundown Gr SE",
"construction_year": 1988,
"exterior_finish": "Stucco",
"foundation_type": "Wood",
"interior_sq_m": 172.61241149902344,
"latitude": 50.899044036865234,
"longitude": -114.04895782470705,
"property_id": "1001109ab2aebbc0",
"roof_material": "Asphalt",
"score_earthquake": 9,
"score_fire": 8,
"score_flood": 10,
"score_hurricane": 10,
"score_tornado": 8
}
],
"error": "",
"pagination": {
"current_page": 1,
"has_next_page": true,
"has_previous_page": false,
"page_total": 113490
},
"price_quote": false,
"result_total": 680936,
"time_ms": 82,
"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"
}
}
The returned object is exactly the shape you can feed into a rating engine, a triage queue for a senior underwriter, or a referral rule for a structural inspection.
Using /aggregate for portfolio rebalancing
Underwriting is not just per-risk. It is also about the shape of the book. The /aggregate endpoint lets you compute statistics across slices of the database without pulling individual rows. This is the right tool when you are deciding which communities to grow in and which to manage out.
Suppose you want median fire safety scores across BC communities, weighted toward communities with enough housing stock to be worth marketing in. The /aggregate endpoint returns one aggregation per call, scoped to a country, province, city, or community, so the pattern is to loop over your target cities and ask /aggregate for each metric. The primary underlying call looks like this:
const houski_data = async (): Promise<AggregateResponse> => {
// You must copy the AggregateResponse type declarations from the
// Houski API documentation to strongly type the response
const url = new URL('https://api.houski.ca/aggregate');
url.searchParams.set('aggregation', 'median');
url.searchParams.set('api_key', 'YOUR_API_KEY');
url.searchParams.set('city', 'vancouver');
url.searchParams.set('country_abbreviation', 'ca');
url.searchParams.set('field', 'score_fire');
url.searchParams.set('province_abbreviation', 'bc');
const response = await fetch(url);
const data = await response.json();
return data;
}
(async () => {
let data: AggregateResponse = await houski_data();
// Log the response
console.log(data);
})();
{
"cache_hit": false,
"cost_cents": 1.0,
"data": [
{
"aggregation": "median",
"field": "score_fire",
"value": "10"
}
],
"error": "",
"price_quote": false,
"time_ms": 58
}
Each call returns the requested aggregation for that one city. Stitch the per-city responses together client-side, drop communities below your minimum property count, and sort by whichever metric you care about. The end result is the same table you can drop straight into your portfolio strategy deck. Each score cell is the 0 to 10 median with a plain read in brackets so the direction is obvious: (safe) is low hazard, (ok) is moderate, (risky) is the end to underwrite carefully. Higher is always safer.
| city | median score_fire | median score_flood | median score_earthquake | property count |
|---|---|---|---|---|
| Sidney | 8.5 (safe) | 7.0 (ok) | 4.0 (risky) | 4,912 |
| Squamish | 4.5 (risky) | 6.5 (ok) | 4.0 (risky) | 6,204 |
A community with high median fire safety and meaningful property count is a candidate for growth in your wildfire-exposed lines. A community with low median fire safety, regardless of how many properties it has, is a candidate for tighter eligibility, higher deductibles, or programmatic non-renewal. The point is that the decision is data-backed and per-community, not gut-felt.
You can issue the same /aggregate call against any province and any score field. Median tornado safety across southern Manitoba and Saskatchewan communities is a useful one. Median hurricane safety across Nova Scotia and Newfoundland communities is another. Median flood safety across Quebec municipalities along the St. Lawrence and Richelieu corridors is the one I would prioritize for any carrier writing in that region.
Pricing implications: per-property differential pricing
Once you have address-resolved scores in the rating engine, the pricing question changes. Instead of one rate per FSA per occupancy class, you can implement multiplicative load factors per peril per property.
A simple version of the rate algebra:
final_premium = base_rate
* fire_load(score_fire, roof_material)
* flood_load(score_flood, foundation_type)
* wind_load(score_hurricane, score_tornado, exterior_finish)
* quake_load(score_earthquake, construction_year)
* occupancy_factor
* deductible_factor
The fire load function might look like a piecewise schedule where a score_fire above 8 with asphalt shingle gets a 0.92 multiplier, a score_fire between 5 and 8 with asphalt shingle is neutral at 1.00, and a score_fire below 4 with cedar shake gets a 1.45 multiplier and a referral flag.
What this does competitively is it lets you price the safe properties more aggressively (and win them) while pricing the high-risk properties at a level that actually covers their expected loss plus your cost of capital. The result is better selection on the front end and lower loss ratio volatility on the back end, which is exactly what your reinsurer wants to see at renewal.
The other implication is on deductibles. Per-peril deductibles indexed to per-property safety scores let you give insureds a real choice. A homeowner in a score_flood 3 zone can opt for a higher water deductible in exchange for a meaningful premium reduction, and you have a defensible, transparent basis for the trade.
Reinsurance treaty disclosure
This is where the most operational pain at carriers shows up right now. Reinsurers and their cat modellers want detailed exposure files. They want every risk with a clean lat and lon, a construction vintage, a primary occupancy, and ideally an indication of secondary modifiers like roof type, foundation, and proximity to relevant hazards.
If you are still submitting exposures with Forward Sortation Area centroids and "frame" as your construction code, you are leaving rate on line on the table. Modern catastrophe models (Moody's RMS, Verisk AIR, Karen Clark and Company, CoreLogic) all reward higher-resolution inputs with tighter loss distributions, which translates into better treaty pricing and more capacity at the layers you actually need.
Houski's role in this workflow is to get every property in your book up to a consistent, defensible standard before you ship the file to your broker. Step by step:
- Take your policy admin export. It will be messy. Some addresses will be unit-suite-street, some will be PO boxes, some will be rural route descriptions.
- Run every address through /geocoding to get a canonical address, lat, lon, and Houski property ID.
- Hit /properties with the property IDs to pull construction characteristics and climate safety scores.
- Join back to your policy data and produce the exposure file in your reinsurer's preferred schema.
- Document your enrichment pipeline as a methodology appendix in the submission. Brokers love this. It signals that you actually know your book.
The audit trail matters. When the cat model output looks different than last year, your reinsurer will ask why. "We adopted Houski per-property scores from the prior FSA-averaged approach" is a clean, defensible answer. The losses they avoided modelling at the postal code level become the losses they correctly attribute at the address level, and the basis risk in the treaty drops.
Operationalizing inside an underwriting workflow
A few practical notes for the people who actually have to wire this into a production underwriting platform.
Cache the scores. Climate safety scores do not change minute-to-minute. They update on a cadence as the underlying hazard layers and Houski's models evolve. Pull them at quote time, store them on the policy record, and re-pull them at renewal and after any material event (wildfire season, hurricane landfall, regulatory hazard map update).
Use field selection religiously. Every Houski request is metered. Pulling all 200 plus fields when you need eight is wasteful. Use select to pull only what your rating engine and your audit log require.
Filter at the API, not in your application. If you only want properties with score_flood_gte=7, push that filter into the request. Do not pull the world and filter in pandas.
Watch for nulls. A small number of properties will have null on one or more score fields, typically because they sit outside the coverage of a specific hazard layer or because geocode confidence is low. Treat null as "refer to a senior underwriter," not as "safe by default." This is the single most common mistake carriers make when integrating.
Geocoding quality is the foundation of everything. If your address parser sends a Calgary address to a coordinate in Edmonton, every score is wrong. Use the /geocoding endpoint, store the returned property ID, and re-use it on every subsequent call. The property ID is the join key for the entire system.
Test your inversion logic. Before you ship to production, write a unit test that asserts: a property with score_flood = 9 is safer than a property with score_flood = 2. This is not a hypothetical concern. Carriers have shipped the inversion bug, found it months later, and had to refund. Get a continuous integration (CI) test in place.
A note on the tornado and hail problem
Tornado safety scores in the database capture climatological exposure, not real-time outbreak risk. They are the right input for portfolio rebalancing and for differentiating southern Saskatchewan from northern Saskatchewan. They are not a substitute for nowcasting during severe weather season.
Hail is not currently a dedicated score_* field, in part because the convective storm climatology for hail in Canada is non-stationary in a way that makes a single static score misleading. For hail underwriting on the Prairies you want a combination of score_tornado (as a proxy for severe convective exposure), roof_material, and construction_year (impact-rated shingles and modern building codes matter a lot). A future field expansion may surface hail safety directly. In the interim, treat the convective triplet as your hail proxy.
Building a defensible methodology document
Every carrier eventually gets asked the same question by a regulator, an internal audit team, or a reinsurer's actuarial review: "How exactly did you derive these risk loadings, and what data inputs are behind them?"
A clean methodology document for an address-resolved climate underwriting program has roughly the following sections:
- Data sourcing. Where did the per-property scores come from, on what update cadence, and what is the underlying hazard layer for each peril?
- Geocoding pipeline. How is each policy address resolved to a coordinate, and what is the fallback when geocoding confidence is low?
- Score-to-load mapping. The actual numerical schedule that takes a score_flood of 4 and a foundation type of "basement" and outputs a flood load multiplier.
- Referral thresholds. What combination of scores and construction characteristics triggers a senior underwriter review, and what triggers an automatic decline?
- Renewal re-rating cadence. How often are scores re-pulled, what counts as a material change, and how is that change communicated to the insured?
- Audit trail. What is stored on each policy record, and how is it surfaced to a reviewer six months or three years later?
The methodology document is not a one-time deliverable. It is a living artefact that gets updated when score versions move, when you adjust thresholds, or when you add a new peril (hail, sea level rise, sub-soil settlement). Treat it like code. Version it. Date the entries. Store the rationale for each change, not just the change itself.
Example three: a flood-focused subset query
A common workflow during a renewal cycle is to ask "which of my policies are sitting in the lowest decile of flood safety in their respective province?" That is two queries to Houski. First, get the provincial flood safety distribution from /aggregate:
const houski_data = async (): Promise<AggregateResponse> => {
// You must copy the AggregateResponse type declarations from the
// Houski API documentation to strongly type the response
const url = new URL('https://api.houski.ca/aggregate');
url.searchParams.set('aggregation', 'median');
url.searchParams.set('api_key', 'YOUR_API_KEY');
url.searchParams.set('country_abbreviation', 'ca');
url.searchParams.set('field', 'score_flood');
url.searchParams.set('province_abbreviation', 'nb');
const response = await fetch(url);
const data = await response.json();
return data;
}
(async () => {
let data: AggregateResponse = await houski_data();
// Log the response
console.log(data);
})();
{
"cache_hit": false,
"cost_cents": 1.0,
"data": [
{
"aggregation": "median",
"field": "score_flood",
"value": "8"
}
],
"error": "",
"price_quote": false,
"time_ms": 37
}
Then apply the returned benchmark to your book, filtering your local policy frame for any row below the provincial threshold. This is the exact framing you want for the conversation with your chief actuary about whether the New Brunswick book is concentrating flood exposure faster than the rest of the country. You can run the same pattern for fire safety in BC, tornado safety in southern Ontario, or hurricane safety in Atlantic Canada.
What this looks like at the desk
To make the abstract concrete, here is what an underwriter's quote workflow looks like with this data wired in:
- Address comes in from the broker.
- Quote engine calls /geocoding to canonicalize and grab the property ID.
- Quote engine calls /properties with select for construction and the five climate safety scores.
- Rating engine applies per-peril load factors as described above.
- If any score is below the carrier's referral threshold (commonly 3 or 4 depending on appetite), the quote routes to a senior underwriter with the full risk profile pre-populated.
- If the quote binds, the property ID and the snapshot of scores are written to the policy record for the audit trail.
- At renewal, the workflow repeats. If scores have moved materially, the system flags it.
Total wall-clock time from address to bindable quote: under one second on the API side, and however long your rating engine takes on its side. No clipboard, no PDF flood maps, no manual lookups.
Common integration anti-patterns
A few patterns go wrong often, in roughly their frequency:
- Pulling all 200 plus fields at quote time because nobody set up a select parameter. This is expensive and slow. Pull what you rate on.
- Storing the score on the policy record but not the score version or the timestamp. When the model updates and the score moves three points, you have no way to explain the rate change to the insured.
- Treating null scores as zero or as 10. Both are wrong. Null is "we do not have confidence in this answer." Route to a human.
- Using FSA centroids to geocode and then pulling per-property scores against those centroids. The whole point of address resolution is that you do not snap to a centroid. Geocode the actual address.
- Inverting the score in the rating engine because someone on the team thought "high score means high risk." This is the single most expensive bug you can ship. Get a CI test in place that asserts orientation, and put a note in the rating engine source comments.
- Forgetting that climate risk has correlation structure. A wildfire event does not produce one claim, it produces hundreds across a contiguous region. Per-property scores help you see that concentration before it bites you. Use them for that.
The competitive position
I will close on the strategic point. The carriers that resolve their exposure to the address level over the next 18 to 24 months will be the ones that grow profitably through the back half of the decade. The carriers that do not will continue to lose their best risks to competitors who can price them properly, while retaining the worst risks because nobody else will take them. This adverse selection spiral is already underway in some segments, particularly on coastal Atlantic property and on interface wildfire exposure in BC and Alberta.
Climate risk is not going to get less expensive. Reinsurance is not going to get less data-hungry. The tools to operate at this resolution are now commodity-priced. There is no longer a defensible reason to underwrite Canadian property at the FSA level.
If you want to put your hands on this data, the fastest path is to grab an API key and run the queries in this post against a handful of addresses you already know well. You will see the orientation immediately, you will see the construction fields, and you will see how cleanly the data joins back to your existing policy admin export.
Get started at /api-documentation/quick-start. The full field catalogue, endpoint reference, and code samples in additional languages are linked from there. If you want to talk through a specific portfolio integration, contact us.
Underwrite the property, not the postal code.
Alex Wilkinson CEO, Houski
