!

Lenders: you valued the collateral once, years ago, and the book has been drifting ever since

Photo of Alex Wilkinson
Alex Wilkinson
CEO of Houski
2026-07-15

A mortgage book gets valued at origination and then, for most lenders, it goes dark. The appraisal that justified the loan ages in a file while the property under it appreciates, stagnates, or quietly slides with its neighbourhood. Five years later the loan comes up for renewal, or the borrower misses two payments, and someone finally asks what the collateral is worth now. That is the most expensive possible moment to be finding out.

The reason books go dark is cost. Reappraising thousands of properties on a schedule was never economical, so nobody did it, and "we check at renewal" became the industry's monitoring strategy.

At a tenth of a cent per field per property, that constraint is gone. Revaluing a 10,000-loan book, pulling three fields per property, costs about thirty dollars. You could run it monthly and the line item would still disappear into rounding. What follows is the mechanics.

Step one: resolve your book to property identifiers, once

Your loan system has addresses. The API works on property identifiers, which are stable across quarters, so you do the address resolution one time and keep the mapping:

API request
TypeScript code
const houski_data = async (): Promise<SearchResponse> => {

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

    const url = new URL('https://api.houski.ca/search');
    url.searchParams.set('api_key', 'YOUR_API_KEY');
    url.searchParams.set('query', '123+main+st+calgary');

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

    return data;
}

(async () => {
let data: SearchResponse = await houski_data();

// Log the response
console.log(data);
})();
API response
JSON
{
  "cache_hit": true,
  "cost_cents": 0.19999998807907104,
  "data": [
    {
      "address": "1215 19489 Main Street SE",
      "property_id": "1a0d9646b3b7fee4"
    },
    {
      "address": "20913 Main Street Southeast",
      "property_id": "1bb955452668e179"
    },
    {
      "address": "1206 19489 Main Street SE",
      "property_id": "25dbe5737d863d68"
    },
    {
      "address": "20693 Main Street Southeast",
      "property_id": "265563c5cf7aaeb"
    },
    {
      "address": "1203 19489 Main Street SE",
      "property_id": "2cb6522c907d3cad"
    },
    {
      "address": "1217 19489 Main Street SE",
      "property_id": "3c360263b5035097"
    },
    {
      "address": "1218 19489 Main Street SE",
      "property_id": "3e9b995b7a2575cf"
    },
    {
      "address": "120 180 Legacy Main Street SE",
      "property_id": "4715657394081588"
    },
    {
      "address": "1209 19489 Main Street SE",
      "property_id": "4e6754f302f2956c"
    },
    {
      "address": "151 Legacy Main Street Southeast",
      "property_id": "61a5c09375eb16aa"
    }
  ],
  "error": "",
  "match_meta": [
    {
      "match_value": 0.8333333134651184,
      "property_id": "1a0d9646b3b7fee4"
    },
    {
      "match_value": 0.8333333134651184,
      "property_id": "1bb955452668e179"
    },
    {
      "match_value": 0.8333333134651184,
      "property_id": "25dbe5737d863d68"
    },
    {
      "match_value": 0.8333333134651184,
      "property_id": "265563c5cf7aaeb"
    },
    {
      "match_value": 0.8333333134651184,
      "property_id": "2cb6522c907d3cad"
    },
    {
      "match_value": 0.8333333134651184,
      "property_id": "3c360263b5035097"
    },
    {
      "match_value": 0.8333333134651184,
      "property_id": "3e9b995b7a2575cf"
    },
    {
      "match_value": 0.8333333134651184,
      "property_id": "4715657394081588"
    },
    {
      "match_value": 0.8333333134651184,
      "property_id": "4e6754f302f2956c"
    },
    {
      "match_value": 0.8333333134651184,
      "property_id": "61a5c09375eb16aa"
    }
  ],
  "price_quote": false,
  "result_total": 10,
  "time_ms": 1007
}

That returns the property_id for an address, with a match confidence score so you can route low-confidence matches to a human instead of silently monitoring the wrong house. Run your whole book through once, store the identifiers next to your loan numbers, and never do it again.

Step two: sweep the book on a schedule

With identifiers in hand, each quarter is one batched query pattern:

API request
TypeScript code
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', '1a0d9646b3b7fee4,10169c4adca227cb');
    url.searchParams.set('results_per_page', '25');
    url.searchParams.set('select', 'address,estimate_list_price,estimate_days_on_market_until_sale,assessment_value');

    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);
})();
API response
JSON
{
  "cache_hit": false,
  "cost_cents": 0.6399999856948853,
  "data": [
    {
      "address": "2806 Ogden Road SE",
      "assessment_value": 1660000,
      "estimate_days_on_market_until_sale": 11,
      "estimate_list_price": 1987480,
      "property_id": "10169c4adca227cb"
    },
    {
      "address": "1215 19489 Main Street SE",
      "assessment_value": 371000,
      "estimate_days_on_market_until_sale": 13,
      "estimate_list_price": 344399,
      "property_id": "1a0d9646b3b7fee4"
    }
  ],
  "error": "",
  "pagination": {
    "current_page": 1,
    "has_next_page": false,
    "has_previous_page": false,
    "page_total": 1
  },
  "price_quote": false,
  "result_total": 2,
  "time_ms": 189,
  "ui_info": {}
}

Three numbers per loan, each doing a different job:

estimate_list_price is the modelled market value today. Store it each quarter and the time series is your drift detector. A property whose estimate has fallen while the loan balance amortizes slowly is a loan to value ratio quietly getting worse, and it surfaces here years before a renewal file would have caught it.

estimate_days_on_market_until_sale is the liquidity read. Two properties at the same value are not the same collateral if one is estimated to move in eleven days and the other in ninety. In a workout scenario, that difference is the difference.

assessment_value gives you a second, independently produced reference point, useful for flagging properties where the two numbers disagree hard enough to warrant a closer look.

Step three: escalate only what moved

The sweep is cheap because it is shallow, and it should stay shallow. Its job is not to produce a defensible valuation for any single loan. Its job is to sort ten thousand loans into "nothing happened" and "look at this one."

Set a threshold - say, estimated value down more than ten percent since origination, or a loan to value ratio crossing your covenant line - and for the loans that trip it, escalate to the automated valuation model (AVM) endpoint. That costs $5.00 per request and returns the full workup: confidence intervals, model accuracy metrics, comparables, and a shareable report a credit committee can actually sit with.

The economics of the two-tier design are the whole point. A quarterly sweep of the entire book plus full reports on the two percent that moved costs less than a single traditional appraisal. You are no longer choosing which loans deserve to be watched. All of them are watched, and the reports go where the movement is.

The upside direction pays for the whole program

Monitoring language is always about risk, but half the signal points the other way. A borrower whose property estimate has climbed forty percent since origination is sitting on equity, and every one of your competitors would love to lend against it. A quarterly sweep hands your retention and home equity teams a list of exactly which customers to call before someone else does, sorted by how much room is there.

The same three fields, the same thirty dollars. Defence and offence in one query.

Market-level triggers without pulling a single loan

Sometimes the question is not "which loan moved" but "which neighbourhood moved." The aggregate endpoint answers at that level directly:

API request
TypeScript code
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', 'calgary');
    url.searchParams.set('community', 'Sunnyside');
    url.searchParams.set('country_abbreviation', 'ca');
    url.searchParams.set('field', 'estimate_list_price');
    url.searchParams.set('province_abbreviation', 'ab');

    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);
})();
API response
JSON
{
  "cache_hit": false,
  "cost_cents": 1.0,
  "data": [
    {
      "aggregation": "median",
      "field": "estimate_list_price",
      "value": "448707"
    }
  ],
  "error": "",
  "price_quote": false,
  "time_ms": 118
}

Median estimated value for one community, one call. Run it across the communities where your book concentrates and you have an early-warning layer that costs almost nothing and requires no per-loan processing at all. When a community median dips, that is your cue to sweep the loans in it off-cycle.

What an estimate will not tell you

Condition. The model does not know the basement flooded in April or that the furnace died. A property can be impaired in ways no dataset sees, which is why the sweep flags files for review rather than writing anything down on its own.

A defensible single-loan number. The per-property estimate is a triage instrument. When a specific loan needs a number that holds up in front of a committee, a regulator, or a court, that is the AVM report tier, or a human appraisal, and the sweep's job was simply to tell you which handful of loans need one.

We would rather tell you where the line is than have you discover it during a workout.

The pre-built version

The datasets page carries portfolio-shaped cuts including Portfolio acquisition analysis, and if your book is large enough that you would rather receive a file than run queries - your loan identifiers in, current estimates and drift flags out, delivered on your schedule - our data team builds exactly that as a custom dataset. Talk to us.

Getting started

  1. Sign up for API access
  2. Resolve your book to property identifiers through the search endpoint, once
  3. Run the first sweep and store it as your baseline quarter
  4. Set drift thresholds and wire the trips to your review queue
  5. Escalate trips to AVM reports at $5.00 each, only for the loans that moved

Pricing details on the pricing page.


The book was never too big to monitor. Monitoring was just priced for a world where every valuation cost hundreds of dollars, and that world is over. Explore the API or browse the datasets.