Houski API Skill: Teach Your Coding Assistant To Build With Property Data

Photo of Alex Wilkinson
Alex Wilkinson
CEO of Houski
2026-08-12

Summary: Download our skill file and your coding assistant learns the Houski API: every endpoint, the filter syntax, how to look up fields and places instead of guessing them, and how to keep requests cheap. It follows the Agent Skills open standard, so the same folder works in Claude Code, Cursor, Gemini CLI, Codex and dozens of other tools.


Skill or Model Context Protocol (MCP) server, which do you need?

SkillModel Context Protocol server
PurposeYour assistant writes code that calls our APIYour assistant queries our data during the conversation
Use whenYou are building an app that needs property dataYou are researching properties or checking what the data looks like
OutputCode you can deployAnswers and data in the chat
SetupDrop a folder in your projectPoint your client at our server

Most people want both. Use the Model Context Protocol server to explore the data, then the skill when you start writing code.


What a skill actually is

A skill is a folder with a SKILL.md file inside it. The file opens with a name and a description, and the rest is plain instructions.

Your assistant reads only the name and description at startup, which costs almost nothing. When you ask for something that matches the description, it loads the full instructions. So the skill sits quietly in your project until you say "add property search to my app", and then it knows the entire API.

Without it, you end up explaining the API yourself in every session: which endpoint, which filter suffix, why a missing select parameter just cost you fifty times more than it needed to.

Where it works

The Agent Skills format was released as an open standard, and support is now broad. The same folder works in:

  • Claude Code, at .claude/skills/houski-api/SKILL.md in your project
  • Cursor, Gemini CLI, Codex, Amp, Goose, OpenCode, Roo Code, Kiro, Junie, Factory, Tabnine and many others

Each tool has its own skills directory, so check its docs for the exact path. Write once, use everywhere.

What is in the skill

All nine endpoints

EndpointPurpose
/propertiesQuery more than 220 million properties in sixteen countries with filtering, sorting and field selection
/searchFuzzy address lookup that survives typos and half-typed addresses
/aggregateStatistics: count, sum, mean, median, mode, min, max and ten quantile levels
/mapPins, clusters and heatmaps for map displays
/geocodingProperties near a set of coordinates, by radius
/predictHistorical values over time, from January 2021 to today
/locationThe countries, provinces, cities and communities that hold data, as a hierarchy
/avmAutomated valuation model, $5.00 per request
/authCheck an API key, never billed

Filter operators

Filters are written as field, then operator, then value.

OperatorMeaningExample
_eqequalsproperty_type_eq=House
_neqnot equalsproperty_type_neq=Apartment
_gteat leastbedroom_gte=3
_lteat mostestimate_list_price_lte=500000
_gtgreater thaninterior_sq_m_gt=100
_ltless thanconstruction_year_lt=2000
_inone of a listproperty_type_in=House,Townhouse
_regexpattern matchaddress_regex=^123
_nregexpattern does not matchaddress_nregex=^123

Sorting uses the same shape: bedroom_sort=desc. Text values match exactly, case included, and fields ending in _percent hold a fraction from 0 to 1, so the skill tells your assistant to copy values from a response rather than guess them.

More than 450 fields, looked up rather than guessed

The skill does not hand your assistant a frozen field list. It sends it to the field reference, or to the free field_list and field_detail tools of the Model Context Protocol server, and it builds every place menu from the /location endpoint, so the code keeps up as coverage grows. The skill names the common starting points:

  • Building: bedrooms, bathrooms, interior and land area, construction year, property type
  • Value: estimated list, sale and rent values, assessment values with their land and improvement parts, property taxes, cap rate, return on investment
  • Records: parcel numbers, zoning, council tax bands in England and Wales, and permit history with permit values
  • Place: coordinates, postal code, community, city, province, country
  • Climate: warmest month highs, coldest month lows, annual precipitation and annual snowfall
  • Scores: 26 of them, including walkability, transit, education, air quality, flood and fire. Each runs from 0 to 10 and every score reads higher is better
  • Demographics: more than 120 fields covering income, ages, household types, education and employment

Beyond the basics

Expand pulls related rows into the same response, at $0.001 per nested row:

expand=permits
expand=listings
expand=listings_rent
expand=assessments

Map modes: pins by default, cluster=true or cluster_over=1000 for clustering, heatmap=true for density or value shading. Bounding box and polygon queries both work.

Predict scenarios: override characteristics such as bedroom or interior_sq_m to see how a change moves the value, which is what you want for renovation and investment modelling.

Batch aggregates: several statistics in one request using agg0_, agg1_ and so on. Each aggregation carries its own filters with the same prefix, so agg0_city=calgary filters the first statistic and nothing else. A bare city=calgary alongside agg0_ parameters is refused with an error that names the prefixed form, so a batch can never quietly hand back national numbers.

Model Context Protocol server: the skill also says when an agent should query the data directly through the server at /mcp instead of writing code, and which of its twelve tools cost nothing.

What it teaches about cost

The API bills on data returned, never on how much was searched. The skill knows the levers:

  • select= is the big one. A request with no select returns just property_id and address, which costs $0.0002 per row. Ask for what you need and nothing more
  • price_quote=true returns the exact cost of a request, with an empty data field and no charge
  • Filter before you fetch, since a tighter filter means fewer rows to pay for
  • Paginate with results_per_page (up to 1000) and page, keeping rows times columns at or under the 10,000 values one response can hold
  • Batch your aggregates instead of firing several requests
  • Test for related records with has_expand_listings_eq=true and its siblings, and expand only when the code needs the rows themselves

Rates: a typical field is $0.001 per field per row, identifiers and links are a tenth of that, an aggregation value is $0.01, a location row is $0.00001, and a full valuation is $5.00. Pay-as-you-go has a $99 per month minimum, and every account has a maximum monthly spend that the owner sets on the dashboard. Full pricing.

Getting started

1. Get an API key

Start here, or grab your existing key from your dashboard.

2. Download the skill

Download houski-api-skill.zip

3. Install it

Unzip it and drop the houski-api folder into your tool's skills directory. For Claude Code that is .claude/skills/ in your project root, so the file lands at .claude/skills/houski-api/SKILL.md. The zip also holds a short README with the same steps.

Put your key in an environment variable such as HOUSKI_API_KEY. The skill tells your assistant to read it from there and never write it into source code.

4. Ask for what you want to build

Describe the feature. The skill loads itself when the request matches.

A live request

The block below is a real call against the live API. The request and the response are regenerated every time this page loads.

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('city', 'calgary');
    url.searchParams.set('country_abbreviation', 'ca');
    url.searchParams.set('province_abbreviation', 'ab');
    url.searchParams.set('results_per_page', '3');
    url.searchParams.set('select', 'address,bedroom,bathroom_full,estimate_list_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);
})();
API response
JSON
{
  "cache_hit": true,
  "cost_cents": 0.96,
  "data": [
    {
      "address": "518 Rochester Terrace NW",
      "bathroom_full": 2,
      "bedroom": 3,
      "estimate_list_price": 1494309,
      "property_id": "103f92f6cf7bbdd9"
    },
    {
      "address": "36 Crimson Ridge Heights NW",
      "bathroom_full": 2,
      "bedroom": 3,
      "estimate_list_price": 702800,
      "property_id": "104fb85a9c002e5d"
    },
    {
      "address": "54 Rowmont Link NW",
      "bathroom_full": 2,
      "bedroom": 3,
      "estimate_list_price": 820503,
      "property_id": "1055f97323e53f25"
    }
  ],
  "error": "",
  "pagination": {
    "current_page": 1,
    "has_next_page": true,
    "has_previous_page": false,
    "page_total": 220226
  },
  "price_quote": false,
  "result_total": 660677,
  "time_ms": 30,
  "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"
  }
}

And a batch aggregate, with the filters carried on each aggregation:

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('agg0_aggregation', 'median');
    url.searchParams.set('agg0_city', 'calgary');
    url.searchParams.set('agg0_country_abbreviation', 'ca');
    url.searchParams.set('agg0_field', 'estimate_list_price');
    url.searchParams.set('agg0_province_abbreviation', 'ab');
    url.searchParams.set('agg1_aggregation', 'count');
    url.searchParams.set('agg1_city', 'calgary');
    url.searchParams.set('agg1_country_abbreviation', 'ca');
    url.searchParams.set('agg1_field', 'property_id');
    url.searchParams.set('agg1_province_abbreviation', 'ab');
    url.searchParams.set('api_key', 'YOUR_API_KEY');

    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": true,
  "cost_cents": 2.0,
  "data": [
    {
      "aggregation": "median",
      "field": "estimate_list_price",
      "value": "631924"
    },
    {
      "aggregation": "count",
      "field": "property_id",
      "value": "660677"
    }
  ],
  "error": "",
  "price_quote": false,
  "time_ms": 19
}

Prompts worth trying

Search and browse

"Add a property search page with filters for bedrooms, price and type, with pagination."

"Build an autocomplete address box using fuzzy matching."

Market analysis

"Chart median estimated list price by community in Calgary."

"Compare houses against apartments: median estimated price, average bedrooms, count."

Maps

"Show properties in this bounding box, clustered when zoomed out."

"Build a heatmap of median estimated prices."

Permits and development

"Find properties with renovation permits in the last two years."

"Build a permit search page filtered by date and type."

Investment

"Work out cap rate and price per square metre for these properties."

"Find properties where the list price sits below the estimated value."

Values over time

"Get two years of value history for this property."

"Model how adding a bedroom changes this property's estimated value."

What a response looks like

This is a response from the properties endpoint, one page of one row with bedroom selected. Every billed endpoint returns data, error, time_ms, cost_cents, cache_hit and price_quote, and most add result_total. The free auth endpoint returns only api_key_authorized, error and time_ms. Only the endpoints that page their results, which are properties, geocoding and map pins, add the pagination object.

JSON
{
  "data": [{ "address": "123 Example St NW", "property_id": "bd9c6fb24c31c772", "bedroom": 3 }],
  "error": "",
  "result_total": 1290,
  "pagination": {
    "current_page": 1,
    "has_next_page": true,
    "has_previous_page": false,
    "page_total": 1290
  },
  "time_ms": 45,
  "cost_cents": 0.12,
  "cache_hit": false,
  "price_quote": false
}

The 0.12 cents is the bedroom value at 0.1 cents plus address and property_id at 0.01 cents each.

Failures use this same shape, with data empty, error filled in and cost_cents at zero, so one type covers both paths. A repeat of an identical request comes back with cache_hit set to true at the same price, because you are paying for the data and not for the work.

Troubleshooting

My assistant does not know the API. Check the folder is in the right skills directory for your tool and that SKILL.md kept its name. Saying "Houski" in the prompt helps it match.

The generated code hits the wrong endpoint. Try "use the Houski API skill to ...". If that fixes it, the skill was never loaded.

Requests come back with errors. Every request needs api_key. A city needs its country and province beside it, as in country_abbreviation=ca&province_abbreviation=ab&city=calgary, and the values come from the /location endpoint. Filters always carry an operator suffix, so bedroom_eq=3 rather than bedroom=3. The error text names the parameter it did not recognise and suggests the closest valid ones.

A filter matches nothing. Text values match exactly, case included, so property_type_eq=House works and property_type_eq=house finds nothing. Copy the value from a response.

My batch aggregate is refused. In batch mode every parameter except price_quote and polygon needs the agg0_ style prefix, and the aggregations are numbered from agg0 with no gaps.

Costs are higher than expected. Add select=, preview with price_quote=true, and check usage on your dashboard.

Making it yours

The file starts with a small configuration header, called frontmatter:

yaml
---
name: houski-api
description: Write code that calls the Houski property data API...
---

Edit the description to change when your assistant reaches for it, or append your own project conventions to the instructions below it.


Resources: API documentation | Quick start | Design philosophy | Pricing | Contact