Read-only REST over published impact fee schedules. Base URL https://levy.thrain.ai. All endpoints are GET; responses are JSON.
Send your key on every request: Authorization: Bearer <key>. Quota rides the response headers (x-quota-day, x-quota-remaining). No key yet? Request one.
curl -H "Authorization: Bearer $KEY" \
"https://levy.thrain.ai/v1/fees/schedules?state=FL&land_use_class=single_family&unit=per_dwelling_unit&as_of=2026-08-29&limit=5"
Each row carries the jurisdiction (GEOID, name, type, state), the fee as the jurisdiction names it plus its normalised category, the printed land-use label and its class, the unit as printed and normalised, the amount and the exact printed token, the stated effective window, any footnote or extractor note, and source_url + source_page — the .gov document and page the line was read from.
| Endpoint | Returns |
|---|---|
/v1/fees/schedules | Fee lines, filterable, paginated (limit ≤ 500, offset) |
/v1/fees/schedules/{schedule_key} | One fee line |
/v1/fees/jurisdictions | Per-jurisdiction rollup: lines, categories, service areas, effective range |
/v1/fees/stats | Dataset totals |
/v1/fees/changes | The change feed: fee lines by the run that first observed them. Poll with since= (date or ISO timestamp, exclusive); filter state, jurisdiction_geoid, fee_category, change_type (baseline = corpus at feed start, added = observed later). Newest first. |
/v1/fees/index | The Levy Index: national series by default, state=XX for a state, since=YYYY-MM-DD to trim. Methodology travels with the rows |
/v1/fees/index/categories | The index by fee category: how many panel jurisdictions levy each category and the middle of that charge |
| Param | Meaning |
|---|---|
state | 2-letter state code |
jurisdiction_geoid | Census GEOID: 5-digit county or 7-digit place |
fee_category | transportation, water, wastewater, stormwater, parks, schools, fire, police, ems, library, general_government, housing, power, other |
land_use_class | Normalised class, e.g. single_family, multifamily, retail, industrial (land_use_label keeps the printed wording) |
unit | Normalised charging unit, e.g. per_dwelling_unit, per_1000_sqft, per_meter |
amount_kind | collected (what is charged) or max_assessable (a published ceiling) |
basis | flat or formula (formula lines state a rate × lookup; amount is null) |
service_area | Exact service-area name as printed; citywide means the whole jurisdiction |
as_of | YYYY-MM-DD — only lines in force on that date, keeping the latest where a later schedule restates one (the explorer's rule). Without it, every published line is returned, superseded and future included. |
effective_since / effective_until | Bounds on effective_start |
min_amount / max_amount | Bounds on the printed amount |
source_id | One registry source |
sort, dir | jurisdiction (default), effective_start, amount, state; asc/desc |
Every field ships on every tier. Amounts are the printed figures; nothing is computed.
schedule_key | Stable id of the line: a hash of jurisdiction, fee, service area, land-use tier, unit and effective date |
jurisdiction_geoid | Census GEOID: 5-digit county or 7-digit place |
jurisdiction_type | county or place |
jurisdiction_name | Census name, e.g. Glendale city |
state_code | 2-letter state code |
levying_entity | Who levies the fee when it is not the jurisdiction itself (a school district, a utility); null otherwise |
service_area | As printed; citywide means the whole jurisdiction |
fee_category | Normalised category (see the filter above) |
fee_name | The fee's printed name |
land_use_class | Normalised land-use class (see the filter above) |
land_use_label | The land-use tier as printed |
unit | Normalised charging unit, e.g. per_dwelling_unit |
unit_raw | The unit as printed |
amount_kind | collected or max_assessable |
basis | flat or formula |
amount | The printed dollar figure; null on formula lines |
amount_raw | The printed token, e.g. $1,282 |
effective_start | When the line took effect |
effective_end | When a later schedule superseded it; null while in force |
footnote_text | The printed footnote attached to the line, if any |
notes | Collection notes, e.g. where an effective date was taken from when the body does not print one |
source_id | The registry source the line came from |
source_url | The document the line was read from |
source_page | Page number within that document |
fetch_timestamp | When the document was last fetched (UTC) |
first_seen_timestamp | When this line first appeared (UTC) |
last_seen_timestamp | When this line was last observed (UTC) |
curl -H "Authorization: Bearer $KEY" \
"https://levy.thrain.ai/v1/fees/changes?since=2026-08-01&change_type=added&state=FL"
Append-only: every fee line, stamped with the run that first observed it. Watched-market jurisdictions are re-checked daily, so a newly adopted schedule shows up here within a day of detection. Store the newest first_seen_at you have seen and pass it back as since=.
The impact fee on one single-family home, month by month. Per jurisdiction the stack is the in-force per-dwelling-unit fees, citywide, collected, without water, wastewater or power. A jurisdiction is in the panel when its stack covers at least three fee categories. The level is the panel median; the chained index links month to month on the common panel from its base month, so coverage growth moves the level but never the index. Nothing is a figure a jurisdiction did not print; the index sums them and says so.
index_key | Stable id of the (as-of date, scope, scope key) row |
as_of_date | Month-end the index is computed for (today, for the current month) |
scope | national or state |
scope_key | US, or the 2-letter state code |
panel_size | Jurisdictions in the panel that month: their in-force stack covers at least panel_min_categories fee categories |
median_total | Median total single-family impact fee across the panel, dollars |
p25_total | 25th percentile of panel totals |
p75_total | 75th percentile of panel totals |
mean_total | Mean of panel totals |
common_panel | Jurisdictions present in both this month and the previous one |
link_ratio | The common panel's aggregate fee this month over last month |
base_date | First month the panel reached 10 jurisdictions; the chained index is 100 there |
chained_index | 100 at base_date, linked forward by link_ratio; null before the base |
chain_gap | Months since the base with no common panel, where the index was carried flat |
panel_min_categories | The panel rule in force when the row was built |
category_key | Categories view: stable id of the (as-of date, scope, scope key, category) row |
fee_category | Categories view: the normalised category |
jurisdictions_levying | Categories view: panel jurisdictions with a fee in this category |
share_levying | Categories view: jurisdictions_levying / panel_size |
median_amount | Categories view: median of the category charge across those jurisdictions |
p25_amount | Categories view: 25th percentile |
p75_amount | Categories view: 75th percentile |
conformed_timestamp | When the row was built (UTC) |
| Status | Meaning |
|---|---|
400 | Bad parameter; the message names it |
401 | Missing or unknown key |
403 | Key revoked |
405 | Anything but GET |
429 | Daily quota exceeded |