API

Read-only REST over the verified record. Base URL https://harvest.thrain.ai. All endpoints are GET; responses are JSON. Two products share one key and one quota: the farmland record below, and the impact fee schedules further down.

Two tables of transactions. Sales are auction and listing results as the seller published them: a cleared, competitive price with acreage, soil rating and crop economics attached. Transfers are recorded deeds a county publishes as open data, filtered to ground the county's own land-use code calls agricultural — the gifts, foreclosures and intra-family conveyances included, each labelled rather than hidden. Buyer and seller names are never published on either.

Authentication

Authorization: Bearer tract_live_…

Keys are issued by hand while the API is in private beta — Request access. The free tier is limited to 1,000 requests/day, sees data lagged 90 days, and omits source_url. The live tier is 10,000/day, current data, sources included. Remaining quota is returned on every response in x-ratelimit-remaining.

Endpoints

EndpointReturns
/v1/farmland/salesSales, filterable, paginated (limit ≤ 500, offset)
/v1/farmland/sales/{sale_key}One sale
/v1/farmland/transfersRecorded agricultural deeds, filterable, paginated
/v1/farmland/transfers/{transfer_key}One transfer
/v1/farmland/countiesPer-county rollup: sales, acres, avg $/acre, date range
/v1/farmland/statsDataset totals

Filters

These apply to both /v1/farmland/sales and /v1/farmland/transfers, with the same names and the same meanings.

ParamMeaning
state2-letter code, e.g. IA
county_fips5-digit FIPS, e.g. 19167
since / untilSale-date bounds, YYYY-MM-DD
min_acres / max_acresAcreage bounds
min_ppa / max_ppaPrice-per-acre bounds
sort / dirsale_date (default), price_per_acre, acres; desc/asc
limit / offsetPage size (≤ 500, default 100) and start

Only on /v1/farmland/sales:

ParamMeaning
sale_typeauction, online_auction, sealed_bid, listing
county_sourcesource_stated (the page named the county) or town_lookup (resolved from a town it named). Pass source_stated when you need only counties the source stated outright.
has_coordinatestrue / false — keep only sales that carry a point, or only those that do not. Read geo_precision for how close each point is before mapping.

Only on /v1/farmland/transfers:

ParamMeaning
deed_typewarranty, quit_claim, trustee, sheriff, special_warranty, personal_rep, tax, other, unknown
arms_lengthtrue / false — the county's own determination. A county that publishes none leaves it null, and null is not false: arms_length=false returns the deeds a county judged not arm's-length, never the ones it said nothing about.
is_market_saletrue / false — whether the record looks like a genuine market transaction. Same null rule.

Example

curl -H "Authorization: Bearer $TRACT_KEY" \
  "https://harvest.thrain.ai/v1/farmland/sales?state=IA&min_acres=100&since=2024-01-01&limit=5"
{
  "data": [ { "sale_key": "…", "sale_date": "2026-04-23", "state_code": "IN",
    "county_fips": "18127", "acres": 102.0, "price_per_acre": 14588.56,
    "soil_index_value": 140.5, "soil_index_system": "WAPI",
    "organization": "Geswein Farm & Land Realty LLC", "source_url": "…" } ],
  "total": 252, "limit": 5, "offset": 0, "tier": "live", "lag_days": 0
}
curl -H "Authorization: Bearer $TRACT_KEY" \
  "https://harvest.thrain.ai/v1/farmland/transfers?state=IL&arms_length=true&min_acres=40&limit=5"
{
  "data": [ { "transfer_key": "fa0a3033…", "sale_date": "2025-11-03", "state_code": "IL",
    "county_fips": "17075", "county_name": "Iroquois County",
    "parcel_id": "08-34-400-004", "acres": 77.0, "sale_price": 1008700.0,
    "price_per_acre": 13100.0, "deed_type": "warranty", "arms_length": 1,
    "is_market_sale": 1, "land_use_code": "J",
    "grantor_entity_type": "individual", "grantee_entity_type": "llc",
    "record_ref": "20251003820756", "source_url": "…" } ],
  "total": 21027, "limit": 5, "offset": 0, "tier": "live", "lag_days": 0
}

Columns on /v1/farmland/sales

Every column the endpoint returns, and nothing else. Any of them can be null: a source that did not state a figure leaves it null rather than guessing, and a derived figure is null wherever its input is. source_url is returned on the live tier only.

The row atlas lists more columns than this, because it describes the whole dataset. What the API leaves off the row is the county-wide constants — soil shares, NCCPI, cash rent, growing-season rainfall — which are identical for every sale in a county and belong in a county rollup rather than repeated on each of thousands of rows. Everything below either describes this sale or was computed as of its year.

The sale

ColumnWhat it is
sale_keyStable id for this sale. Safe as a primary key across releases.
auction_keyGroups tracts sold at the same auction event.
sale_dateThe date it sold. For third-party compilations this is the publication date.
sale_typeHow it sold: auction, online_auction, sealed_bid, listing (private treaty), unknown.
sold1 when the source reports it sold, 0 when it did not clear.
tract_labelThe tract's label at the auction, e.g. "Tract 3".
tract_countHow many tracts the property was offered in.
organizationThe company that published the result.
source_urlThe page the row was read from. Every figure can be checked there.

Where

ColumnWhat it is
state_codeTwo-letter state code.
county_fips5-digit census county FIPS, the key to join on (not the name). The county the page named; where it named only a town, the county that town resolves into — county_source says which. Null when the source named neither.
county_nameCounty as the source named it.
county_sourceWhere county_fips came from. source_stated: the page named the county. town_lookup: the page named no county, so this is the county the town it did name resolves into, via the Census geocoder — right about 83% of the time, measured against sales that name both. Null when the row has no county. The county-wide figures on a sale (yields, soil, cash rent, crop risk) stay joined on a stated county and are null under town_lookup: a town-derived county is good enough to find a sale by, not to hang a county average on.
township_nameCivil township the source named, e.g. "Chalmers".
plss_sectionSurvey section (1–36) from the stated legal description.
plss_townshipSurvey township from the legal description, e.g. "98N".
plss_rangeSurvey range from the legal description, e.g. "64W".
legal_descriptionThe legal description as the source wrote it.
location_textDirections as the source wrote them: "6 miles southwest of Amboy, IL".
addressA road or street address, where the source states one.
latitude / longitudeWGS84 coordinates.
geo_sourceWhere the coordinates came from, best first. source_stated: the page published them. plss_section_centroid: resolved from the stated section-township-range through the federal survey polygons, county-checked. town_offset: the page gave a distance and direction from a named town ("6 miles SW of Amboy, IL") and the town's point was moved along that bearing. town_centroid: the page gave only a direction or "near", so the point is the town's. A town reference never displaces a stated point or a resolved section.
geo_precisionHow close the point is — read this before you map anything. point: the parcel's own coordinates. section: the centroid of the surveyed square mile the legal description names, within about a mile. locality: a town reference within about three miles — the town itself or a short offset. area: a town offset of ten to thirty miles, where the point may sit several miles off across the bearing. Offsets beyond thirty miles are not published: they place the reader, not the farm.

The land and the price

ColumnWhat it is
land_useLand use as the source described it: cropland, pasture, recreational, building site, mixed.
acresTotal acres in this tract.
tillable_acresTillable or crop acres, when the source states them.
is_dwelling1 when the sale carries a house or building site, so its per-acre price is partly a building price. Null when the source stated no land use — null is not 0. Exclude these before averaging.
price_totalTotal sale price, US dollars.
price_per_acrePrice per acre. The source's figure when stated, otherwise total ÷ acres.
price_per_tillable_acrePrice per tillable acre. Null unless tillable acres are known.
price_per_soil_pointPrice per acre ÷ the tract's soil productivity index: the standard way to compare farms of different soil quality.

Soil under this farm

ColumnWhat it is
soil_index_valueSoil productivity rating as published for this tract.
soil_index_systemWhich rating system that value uses (CSR2, PI, WAPI, CPI, NCCPI, SPI). Values are not comparable across systems.
soil_map_unit_nameThe USDA soil map unit under the sale's own coordinates: series, texture and slope phase, e.g. "Drummer silty clay loam, 0 to 2 percent slopes".
soil_capability_classUSDA non-irrigated land capability class of that map unit, 1 (best) to 8.
soil_drainage_classDrainage class of that map unit.
soil_hydrologic_groupHydrologic soil group (A, B, C, D or dual) — how fast water leaves.
soil_flood_frequencyNone, Very rare, Rare, Occasional, Frequent, Very frequent. The sale's own flood signal.
soil_slope_pctRepresentative slope of that map unit, percent.
soil_farmland_classUSDA farmland classification: prime, prime if drained, statewide importance, not prime.
soil_grainWhich grain of soil this row carries. map_unit_at_point: the soil_* columns come from the sale's own coordinates. county_aggregate: only county-level soil is known for it. Null: neither.

Crop economics

The price a bushel fetched around the sale, the county's yield, and the revenue an acre produced. Each yield carries the crop year it came from: counties report intermittently, and a figure two seasons old should say so.

ColumnWhat it is
corn_price_at_sale_usd_buState corn price received in the calendar month this farm sold. What the market looked like when the bid was made.
corn_price_marketing_year_usd_buState marketing-year average corn price as of the sale year. The figure behind revenue.
county_corn_yield_bu_acreCounty corn yield, the most recent year at or before the sale and within five crop years of it. Null rather than stale beyond that.
county_corn_yield_yearWhich crop year that yield is from.
corn_gross_revenue_per_acreYield × marketing-year price: gross revenue an acre produced, before costs.
price_to_revenue_multiplePrice per acre ÷ gross corn revenue per acre — how many years of gross crop revenue the buyer paid. The earnings multiple for farmland. Corn-based; soybean and wheat revenue sit alongside rather than blended in.
soybean_price_at_sale_usd_buState soybean price received in the month it sold.
soybean_price_marketing_year_usd_buState marketing-year average soybean price as of the sale year.
county_soybean_yield_bu_acreCounty soybean yield, same five-year rule as corn.
county_soybean_yield_yearWhich crop year that yield is from.
soybean_gross_revenue_per_acreThe other half of a corn/soy rotation, before costs.
wheat_price_at_sale_usd_buState all-wheat price in the month it sold. Not every state still has a monthly wheat series — Iowa's ended in 1976 — and it is null where none exists.
wheat_price_marketing_year_usd_buState marketing-year average all-wheat price as of the sale year.
county_wheat_yield_bu_acreCounty all-wheat yield. From 2008 on, the harvested-acre-weighted combination of the winter, spring and durum series.
county_wheat_yield_yearWhich crop year that yield is from. Wheat is reported intermittently across much of the Corn Belt.
wheat_gross_revenue_per_acreWheat yield × marketing-year price, before costs.

Crop insurance risk

Federal crop insurance experience for this county over the ten commodity years before the sale (USDA Risk Management Agency). A county figure, but not a county constant: the same county in 2015 and in 2025 carries a different window, so it is this sale's number.

ColumnWhat it is
county_corn_indemnified_policy_pct_10yrShare of the county's corn policies paid a claim over those ten years, percent. "One year in six" reads as about 17.
county_corn_loss_ratio_10yrCorn indemnity per premium dollar. Above 1: the crop paid out more than it cost to insure.
county_corn_top_loss_cause_10yrWhat took the most corn indemnity — Drought, Excess Moisture, Hail, Decline in Price, and so on.
county_soybean_indemnified_policy_pct_10yrThe same, for soybeans.
county_soybean_loss_ratio_10yrThe same, for soybeans.
county_soybean_top_loss_cause_10yrThe same, for soybeans.
county_crop_risk_through_yearThe last commodity year that ten-year window covers.

Wind and solar

The energy build-out around the sale as it stood in the sale year, from the USGS turbine and large-scale solar databases. A sale in 2013 is not credited with a wind farm built in 2020.

ColumnWhat it is
county_wind_turbines_at_saleUtility-scale turbines online in the county by the end of the sale year. 0 is a real answer; null only means the county is unknown.
county_wind_mw_at_saleWind capacity online in the county by then, MW.
county_solar_mw_ac_at_saleLarge-scale (1 MW-AC and up) solar capacity online in the county by then, MW-AC.
nearest_wind_turbine_km_at_saleKilometres from this sale's coordinates to the nearest turbine already online. Null when the sale has no coordinates, or nothing stands within about 100 km.
nearest_solar_project_km_at_saleThe same, for large-scale solar.

Audit trail

ColumnWhat it is
first_seen_timestampWhen we first observed this record.
last_seen_timestampWhen we last observed it in a source.
conformed_timestampRow last-updated stamp. Use it to pull incrementals.

Columns on /v1/farmland/transfers

One row per recorded deed on ground the county's own land-use code calls agricultural. Buyer and seller names are never published — entity type is the analytically useful half and carries no personal data. source_url is returned on the live tier only.

ColumnWhat it is
transfer_keyStable id for this transfer. Safe as a primary key across releases.
county_fips5-digit census county FIPS. The key to join on.
county_nameCounty name from the census list, suffix included ("Iroquois County", "Catahoula Parish").
state_codeTwo-letter state code.
parcel_idThe county's own parcel identifier. Join key back to that county's parcel records.
sale_dateThe date the transfer was recorded.
sale_priceStated consideration, US dollars. Nominal amounts ($0–$1) are real records, not errors — see deed_type and is_market_sale before treating one as a price.
acresParcel acreage, where the county publishes a land area.
price_per_acrePrice ÷ acres, where both are known and positive.
deed_typeNormalised instrument: warranty is an ordinary sale; sheriff and tax mean distress; quit_claim is usually not a market sale; trustee, special_warranty, personal_rep, other, unknown.
arms_length1/0 — the county's own arm's-length determination. Null where the county publishes none, and null is not 0. Today Indiana, Illinois and Florida publish it.
is_market_sale1/0 — whether this looks like a genuine market transaction: the county's flag where there is one, otherwise inferred from price and deed type. Null when undetermined.
sale_validityThe county's own validity or qualification note, verbatim — "24 Current Use", "10 Gift or Love and Affection Deed", "15 Forced Sale". Codes differ by county on purpose; this is what the county said, not our reading of it.
land_use_codeThe county land-use code that classified this parcel agricultural. County-specific.
grantor_entity_typeSeller type: individual, llc, trust, corporation, government, other, unknown.
grantee_entity_typeBuyer type, same set. The individual-to-LLC shift over time is a real ownership signal.
record_refInstrument number, deed book/page or receipt number — what you would quote to the recorder. Null where the county publishes none.
source_urlA live-tested query link to the county's own service, filtered to this record. Null where no query pattern has been verified against the live service: an untested link is not shipped.
source_idWhich county service published it.
fetch_timestampWhen the page or file this record came from was fetched.
first_seen_timestampWhen we first observed this record.
last_seen_timestampWhen we last observed it.
conformed_timestampWhen this published row was last written.

Coverage today: 272,749 transfers across 267 counties in ten states — Indiana and Illinois statewide, plus counties in Washington, Ohio, Florida, Iowa, Colorado, Virginia, North Carolina and Minnesota. 205,770 carry a price and 174,194 carry a price per acre.

Impact fee endpoints

Development impact fees, system development charges and impact taxes — what a local government charges new construction — one row per published fee line at the grain the jurisdiction prints it: service area × fee × land-use label × unit × amount kind × effective date. Every amount is the verbatim printed figure and every row links the .gov document and page it was read from. The same rows are free to browse at /fees/explore/; the API adds filters, stability and quota. Unlike the farmland endpoints, both tiers see current data and source_url.

EndpointWhat it returns
/v1/fees/schedulesFee lines, filterable, paginated (limit ≤ 500, offset)
/v1/fees/schedules/{schedule_key}One fee line
/v1/fees/jurisdictionsPer-jurisdiction rollup: lines, categories, service areas, effective range
/v1/fees/statsDataset totals

Filters on /v1/fees/schedules

ParamMeaning
state2-letter state code
jurisdiction_geoidCensus GEOID: 5-digit county or 7-digit place
fee_categorytransportation, water, wastewater, stormwater, parks, schools, fire, police, ems, library, general_government, housing, power, other
land_use_classNormalised class, e.g. single_family, multifamily, retail, industrial (land_use_label on each row keeps the printed wording)
unitNormalised charging unit, e.g. per_dwelling_unit, per_1000_sqft, per_meter
amount_kindcollected (what is charged) or max_assessable (a published ceiling)
basisflat or formula (formula lines state a rate × lookup; amount is null)
service_areaExact service-area name as the schedule prints it; citywide means the whole jurisdiction
as_ofYYYY-MM-DD — only lines in force on that date, keeping the latest line where a later schedule restates one (the same rule the explorer applies). Without it, every published line is returned, superseded and future included.
effective_since / effective_untilBounds on effective_start
min_amount / max_amountBounds on the printed amount
source_idOne registry source
sort, dirjurisdiction (default), effective_start, amount, state; asc/desc

Example

curl -H "Authorization: Bearer $KEY" \
  "https://harvest.thrain.ai/v1/fees/schedules?state=FL&land_use_class=single_family&unit=per_dwelling_unit&as_of=2026-08-23&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.

Errors

StatusMeaning
400Bad parameter; the message names it
401Missing or unknown key
403Key revoked
405Anything but GET
429Daily quota exceeded