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, the field list, 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 108 million properties 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
/locationProvinces, cities and communities 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 listcommunity_in=Kensington,Beltline
_regexpattern matchaddress_regex=^123
_nregexpattern does not matchaddress_nregex=^123

Sorting uses the same shape: bedroom_sort=desc.

More than 450 fields

  • Physical: bedrooms, bathrooms, interior and lot area, construction year, storeys, property type
  • Financial: estimated list, sale and rent values, estimated property taxes, assessment values, cap rate, return on investment
  • Location: coordinates, postal code, community, city, province, country
  • Scores: 52 of them, including walkability, transit, education, air quality, flood safety and fire safety. Every score reads higher is better
  • Demographics: 123 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. This trips people up: a bare city=calgary alongside agg0_ parameters is ignored, and you get national numbers back.

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
  • Batch your aggregates instead of firing several requests

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.0001, and a full valuation is $5.00. Pay-as-you-go has a $99 per month minimum. 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.

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('http://127.0.0.1:8080/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.959999978542328,
  "data": [
    {
      "address": "31 Hawkside Park NW",
      "bathroom_full": 2,
      "bedroom": 2,
      "estimate_list_price": 679786,
      "property_id": "10000f97f5cb7b9f"
    },
    {
      "address": "6 1744 7 Street SW",
      "bathroom_full": 2,
      "bedroom": 3,
      "estimate_list_price": 985289,
      "property_id": "10004f7afe0c1946"
    },
    {
      "address": "384 Copperpond Landng SE",
      "bathroom_full": 2,
      "bedroom": 3,
      "estimate_list_price": 590394,
      "property_id": "10007f9761f49940"
    }
  ],
  "error": "",
  "pagination": {
    "current_page": 1,
    "has_next_page": true,
    "has_previous_page": false,
    "page_total": 221173
  },
  "price_quote": false,
  "result_total": 663518,
  "time_ms": 87,
  "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('http://127.0.0.1:8080/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": "657230"
    },
    {
      "aggregation": "count",
      "field": "property_id",
      "value": "663518"
    }
  ],
  "error": "",
  "price_quote": false,
  "time_ms": 68
}

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. Every billed endpoint returns data, error, time_ms, cost_cents and cache_hit, and 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": [],
  "error": "",
  "time_ms": 45,
  "cost_cents": 0.96,
  "cache_hit": false,
  "pagination": {
    "current_page": 1,
    "has_next_page": true,
    "has_previous_page": false,
    "page_total": 10
  }
}

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, and queries need a country_abbreviation, ca for Canada or us for the United States. 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.

My aggregate numbers look national. In batch mode every filter needs the agg0_ style prefix.

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 written as YAML frontmatter:

yaml
---
name: houski-api
description: Integrate the Houski property database 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