Market context tools
Besides your own data, Ontyx offers a small set of public-data tools for market context: US Census figures by zip code and tract, housing supply and rent benchmarks by county, geocoding, nearby places and maps. They answer from public sources, not from your organization’s data, and every member can use them, readers included.
Not every Ontyx environment offers all of them: the tools your assistant lists are the ones yours has. Where live Census data isn’t turned on, get_population and get_average_income answer from a small built-in sample, and their descriptions say so.
Monthly allowance
Unlike the tools for your own data, these count toward a monthly allowance. Each successful call counts once, and the answer carries a quota field with how much is used (used, limit, percent, state and period; left out of the examples below). Failed calls (a rejected input, an unknown zip, an upstream failure) aren’t counted. When the allowance is used up, these calls can be refused with QUOTA_EXCEEDED until it resets on the 1st of the next month.
Coordinate order. Every coordinate in the location tools is
[longitude, latitude](WGS84, the GeoJSON order): longitude first, in inputs and in thepositionof every result.get_underwriting_bundle,get_supply_pipelineandget_rent_benchmarktakelatandlngas separate fields instead.
Demographic lookups
From the latest US Census American Community Survey (ACS) 5-year estimates. The zip tools resolve a 5-digit zip to its ZIP Code Tabulation Area (ZCTA), the Census geography that approximates a zip, so results carry the ACS geoid, the vintage (acs_year, survey) and a margin of error (moe).
get_population
The resident population of a US zip code.
Who can call it: anyone connected, readers included.
| Input | Required | What it is |
|---|---|---|
zip | yes | A 5-digit US zip code. |
Answers with ok, zip, population, moe, acs_year, survey and geoid. For a zip the ACS has no data for, ok is false and reason is "unknown_zip".
{
"ok": true,
"zip": "90210",
"population": 19004,
"moe": 1101,
"acs_year": 2024,
"survey": "5yr",
"geoid": "860Z200US90210"
}get_average_income
The median household income of a US zip code (ACS table B19013). The name is kept for compatibility, but the value is a median, not a mean. A top-coded median (such as 250001) means “that amount or more”.
Who can call it: anyone connected, readers included.
| Input | Required | What it is |
|---|---|---|
zip | yes | A 5-digit US zip code. |
Answers with ok, zip, median_household_income_usd, moe_usd, currency ("USD"), acs_year, survey and geoid, or reason: "unknown_zip".
get_underwriting_bundle
A commercial real estate underwriting snapshot for a US Census tract: about 22 demographic, housing, income and employment figures.
Who can call it: anyone connected, readers included.
| Input | Required | What it is |
|---|---|---|
tract_geoid | one of the two | An 11-digit Census tract geoid. |
lat, lng | one of the two | A coordinate, resolved to its tract. |
Answers with ok, tract_geoid, acs_year, survey and the figures: total_population, total_households, median_household_income_usd, median_gross_rent_usd, median_home_value_usd, median_owner_costs_usd, rent_to_income_ratio, owner_cost_to_income_ratio, total_housing_units, vacancy_rate, five share_built_* era shares, bachelors_share, total_employed, industry_hhi and four transport_*_share commute shares. A figure is null where the ACS doesn’t publish a value.
Market outlook
Two county-level tools for what current demographics can’t say: what supply is coming, and what a fair rent is. Both accept a tract or a coordinate for convenience, but the answer is always for the county: building permits are only complete monthly at county level, and fair-market rents have no smaller form in most of the country. Every answer says so in geography_grain and resolved_from.
get_supply_pipeline
Forward-looking housing supply for a county, from Census building-permit authorizations.
Who can call it: anyone connected, readers included.
| Input | Required | What it is |
|---|---|---|
county_geoid | one of the three | A 5-digit state and county geoid. |
tract_geoid | one of the three | An 11-digit tract geoid, rolled up to its county. |
lat, lng | one of the three | A coordinate, resolved to its county. |
Answers with geography_grain and resolved_from, and keeps what was observed apart from what’s forecast:
observed: arithmetic on authorized permit counts: trailing 12-month units, multifamily share, year-over-year change, the standing pipeline, and permits per 1,000 existing homes.outlook: modelled: expected deliveries over the next 12 months, expected stock growth, andsupply_pressureandsupply_momentumlabels.supply_pressureis relative:elevatedmeans the top fifth of counties nationally for expected stock growth,limitedthe bottom fifth.assumptions: the permit-to-completion lags and completion rates used foroutlook. They’re calibration defaults, not measurements.benchmarks: national and in-state percentile ranks.data_quality: whether the trailing windows are complete, and how much of the count was reported rather than estimated by the survey.
get_rent_benchmark
A standardized fair-market rent for a county, by unit size from studio to four bedrooms.
Who can call it: anyone connected, readers included.
| Input | Required | What it is |
|---|---|---|
county_geoid | one of the three | A 5-digit state and county geoid. |
tract_geoid | one of the three | An 11-digit tract geoid, rolled up to its county. |
lat, lng | one of the three | A coordinate, resolved to its county. |
Answers with geography_grain, resolved_from, rents, trend (growth with and without inflation), vs_market (against the median rent tenants pay now), affordability (against local incomes and area income limits; empty where income limits aren’t available) and benchmarks. Three things to carry into any answer built on it:
- Rents are gross: rent plus tenant-paid utilities. They compare with gross-rent survey figures, not contract rent, and aren’t a current asking rent.
fmr_percentile(40 or 50) is definitional. An area measured at the 50th percentile isn’t more expensive than one measured at the 40th; it’s measured at a different point of its own range. Don’t rank across the two without saying which is which.fmr_2br_to_acs_median_rent_ratiois a screening ratio that overstates the gap to market, because the survey median it divides by is a five-year average across every unit size.
Location
Geocoding, reverse geocoding, nearby places and static maps. Results with a position (geocode, reverse_geocode, search_nearby) also carry h3, the H3 cell id of that point; h3Resolution (0 to 15, default 9) sets the cell size.
geocode
Turns an address or place name into candidate positions.
Who can call it: anyone connected, readers included.
| Input | Required | What it is |
|---|---|---|
query | yes | Free-form address or place text. |
maxResults | no | 1 to 50 (default 5). |
biasPosition | no | [lon, lat] to favour results near. |
countryFilter | no | ISO 3166-1 alpha-3 country codes to keep to, such as ["USA"]. |
h3Resolution | no | 0 to 15, default 9. |
Answers with results, each with label, position, h3 and, where known, relevance, country, region and postalCode.
{
"results": [
{
"label": "Golden Gate Brg, San Francisco, CA 94129, United States",
"position": [-122.47846, 37.8183],
"country": "USA",
"region": "CA",
"postalCode": "94129",
"relevance": 1,
"h3": "89283087037ffff"
}
]
}reverse_geocode
Turns a position into nearby addresses.
Who can call it: anyone connected, readers included.
| Input | Required | What it is |
|---|---|---|
position | yes | [lon, lat]. |
maxResults | no | 1 to 50 (default 1). |
h3Resolution | no | 0 to 15, default 9. |
Answers with results, each with label, position, h3 and, where known, distanceMeters, country, region and postalCode.
search_nearby
Places around a position, filtered by category. There’s no free-text search: filter with categories.
Who can call it: anyone connected, readers included.
| Input | Required | What it is |
|---|---|---|
position | yes | [lon, lat], the centre of the search. |
radiusMeters | no | 1 to 50,000 (default 1,000). |
maxResults | no | 1 to 50 (default 10). |
categories | no | AWS Location place category ids to keep to. |
h3Resolution | no | 0 to 15, default 9. |
Answers with results, each with placeId, label, position, h3 and, where known, distanceMeters, categories and address.
static_map
Renders a map image.
Who can call it: anyone connected, readers included.
| Input | Required | What it is |
|---|---|---|
framing | yes | Exactly one of { "type": "center", "center": [lon, lat], "zoom": 0-20 }, { "type": "boundingBox", "boundingBox": [west, south, east, north] } or { "type": "boundedPositions", "positions": [[lon, lat], …] } (two or more points). |
aspectRatio | no | 16:9 (default), 3:2, 4:3, 5:4 or 1:1. |
orientation | no | landscape (default) or portrait. |
quality | no | standard (default) or high (1080p-class, such as 1920×1080 at 16:9). |
style | no | standard (road map, default, and the best base under an overlay) or satellite. |
geojsonOverlay | no | A GeoJSON FeatureCollection to draw, at most 4,200 characters. |
pois | no | Show built-in place icons (default false). |
Answers with an inline preview image and a text block whose first line is a link to the full-resolution JPEG (Full map (JPEG, W×H): <signed url>), then a caption, then { url, expiresAt, width, height, bucketKey }. The link is short-lived; expiresAt says when it stops working. The inline image is left out when the whole answer would be too large (see Answer size); the link always carries the map.
Maps of a metric
map_metric
A map of one Census-tract figure around a place, coloured by value, for when someone wants to see how it varies. For the numbers themselves, use get_underwriting_bundle.
Who can call it: anyone connected, readers included.
| Input | Required | What it is |
|---|---|---|
location | yes | Exactly one of { "address": "…" } (its top geocode match is used) or { "position": [lon, lat] }. |
metric | yes | median_household_income, median_gross_rent, median_home_value, rent_burden, vacancy_rate, population_density, bachelors_share, share_built_post_2010, transit_share or wfh_share. |
radius_km | no | 1 to 25 (default 5). Every tract touching the circle is drawn. |
preset | no | report (muted base map, default) or presentation (higher-contrast labels). |
classes | no | Number of colour classes, 3 to 7 (default 5). |
palette | no | Blues, Greens, Oranges, Purples, Reds or YlGnBu. Default: one chosen per metric. |
Answers with a text block whose first line links to the 1080×1080 PNG (Full map (PNG, 1080×1080): <signed url>), then a caption, then the details: url, expiresAt, width, height, legend, metric, label, format, place, center, radius_km, acs_year, breaks (worked out by quantile over the tracts with data), classes, palette, stats (n_tracts, n_with_data, min, max, median), and highest and lowest (the three tracts at each end). An inline 800×800 preview image comes first for clients that show images. Without a map renderer configured, the tool answers with a render_unavailable error.
Answer size
Map tools can return large answers: an 800×800 preview image is about 117,000 characters on its own.
- Clients that show the interactive map card (MCP Apps hosts) get the text block only. The card loads the full image from the link, so the inline copy isn’t needed, which keeps a
map_metricanswer under 6,000 characters. - Every other client gets the image too, unless the whole answer would pass 120,000 characters. Then the image is dropped, never the link, the caption or the details, and the caption says so.
Errors
These tools answer errors as structured JSON in the tool result. Errors from Ontyx itself use these codes:
UNAUTHENTICATED: the sign-in or key was missing, invalid or revoked.RATE_LIMITED: too many requests in a short time;retryAfterMssays how long to wait.QUOTA_EXCEEDED: the monthly allowance is used up (see Monthly allowance).INVALID_REQUEST: the input didn’t fit the tool’s inputs.
Errors from the location and Census services come through as { "error": { "code", "message" } }:
invalid_request: parameters the service rejected.unknown_route: the service doesn’t recognize the operation.not_found: no data for that place (the zip tools answer{ "reason": "unknown_zip" }instead).upstream_error: the service failed, for example on a coordinate out of range.upstream_timeout: a lookup ran out of time.
None of these failed calls is counted.