§API · v1

The Rootfast API

A small, JSON-only HTTP API over USDA PLANTS, USDA Plant Hardiness Zones, and the GBIF taxonomic backbone — joined together, served plain. No keys, no rate limits in v1, no terms beyond attribution. Try every example below — it hits the live service.

Base URL · https://api.rootfast.org

OpenAPI spec · https://api.rootfast.org/v1/openapi.json  ·  Interactive · https://api.rootfast.org/v1/docs

Source · github.com/cjscrofani/rootfast ↗


§1Service health & version

GET

/healthz

Returns dataset version and applied schema migration. Useful as a liveness check.

Request

curl 'https://api.rootfast.org/healthz'

Response · 200

{
  "ok": true,
  "dataset_version": "0.0.1",
  "schema_version": "001"
}

Try it → https://api.rootfast.org/healthz

§2One plant, in full

GET

/v1/plants/{usda_symbol}

Returns a plant record with growth habit, duration, native status by region, every USDA characteristic, and all Montana counties where the taxon is recorded. Resolves synonyms transparently.

Request

curl 'https://api.rootfast.org/v1/plants/PIPO'

Response · 200

{
  "plant": {
    "usda_symbol": "PIPO",
    "scientific_name": "Pinus ponderosa Lawson & C. Lawson",
    "scientific_name_canonical": "Pinus ponderosa",
    "common_name": "ponderosa pine",
    "family": "Pinaceae Spreng. ex Rudolphi",
    "gbif_taxon_key": 5285053,
    "gbif_match_type": "EXACT",
    "rank": "Species",
    "...": "..."
  },
  "growth_habits": ["Tree"],
  "durations": ["Perennial"],
  "native_status": [
    { "region_code": "L48", "status": "Native" },
    { "region_code": "CAN", "status": "Native" }
  ],
  "characteristics": { "drought_tolerance": "High", "...": "..." },
  "counties": [
    { "county_fips": "30031", "county_name": "Gallatin", "state_code": "MT", "nativity": "Native" }
  ]
}

Try it → https://api.rootfast.org/v1/plants/PIPO

§3Flat catalogue

GET

/v1/plants?{filters}&format={json|csv|ndjson}

Every taxon in the catalogue as a flat list, one row per plant — no county aggregation. Accepts the filter parameters under §F (except `nativity`, which requires a distribution join). Use `format=csv` or `format=ndjson` to download in bulk; the response is sent as an attachment with a `rootfast-plants.csv` filename. JSON pagination defaults to 5000 (max 10000); bulk downloads return up to 50000 in a single call.

Request

curl 'https://api.rootfast.org/v1/plants?family=Pinaceae&limit=2'

Response · 200

{
  "count": 2,
  "total": 45,
  "paging": { "limit": 2, "offset": 0, "has_more": true },
  "filters": { "family": "Pinaceae" },
  "plants": [
    {
      "usda_symbol": "ABAM",
      "scientific_name": "Abies amabilis (Douglas ex Loudon) Douglas ex Forbes",
      "common_name": "Pacific silver fir",
      "family": "Pinaceae Spreng. ex Rudolphi",
      "genus": "Abies",
      "rank": "Species",
      "gbif_taxon_key": 5285101,
      "...": "..."
    }
  ]
}

Try it → https://api.rootfast.org/v1/plants?family=Pinaceae&limit=2

§4Plant finder

POST

/v1/plants/search

Cross-cutting search that takes a geographic scope (counties or states) plus filter criteria and returns plants ranked by how many of the requested counties they appear in. Useful for "I live near these places — what fits my conditions?" queries that don't fit a single county or state. Accepts every filter param from §F inside a `filters` object. Default limit 200, max 1000.

Request

curl -X POST 'https://api.rootfast.org/v1/plants/search' \
  -H 'content-type: application/json' \
  -d '{
  "counties": ["30031", "30057", "30077"],
  "nativity": "Native",
  "filters": {
    "growth_habit": "Tree",
    "drought_tolerance": "High"
  },
  "limit": 5,
  "include_counties": true
}'

Response · 200

{
  "scope": { "counties_requested": 3, "states_requested": null },
  "filters": { "growth_habit": "Tree", "drought_tolerance": "High" },
  "nativity": "Native",
  "count": 5,
  "limit": 5,
  "plants": [
    {
      "usda_symbol": "ARTR2",
      "scientific_name": "Artemisia tridentata Nutt.",
      "common_name": "big sagebrush",
      "family": "Asteraceae Bercht. & J. Presl",
      "matching_county_count": 3,
      "requested_county_count": 3,
      "match_score": 1.0,
      "nativity_rollup": "Native",
      "matching_counties": ["30031", "30057", "30077"]
    }
  ]
}

§5Plant synonyms

GET

/v1/plants/{usda_symbol}/synonyms

List every synonym known for the plant, drawn from two sources: USDA's Synonyms tab (`usda_synonyms_tab` — names without their own plant record) and any sibling rows in the plants table whose `accepted_plant_id` points back to this taxon (`plants_table`). The endpoint accepts either an accepted symbol or a synonym symbol — synonyms transparently resolve to the canonical plant and the response reports whether resolution happened via `resolved_from_synonym`.

Request

curl 'https://api.rootfast.org/v1/plants/EQAR/synonyms'

Response · 200

{
  "accepted": {
    "usda_symbol": "EQAR",
    "scientific_name": "Equisetum arvense L.",
    "scientific_name_canonical": "Equisetum arvense",
    "common_name": "field horsetail",
    "family": "Equisetaceae Michx. ex DC.",
    "gbif_taxon_key": 7924597
  },
  "queried_symbol": "EQAR",
  "resolved_from_synonym": false,
  "count": 5,
  "synonyms": [
    { "usda_symbol": "EQARA", "scientific_name": "Equisetum arvense L. var. alpestre Wahlenb.",  "source": "usda_synonyms_tab" },
    { "usda_symbol": "EQARB", "scientific_name": "Equisetum arvense L. var. boreale (Bong.) Rupr.", "source": "usda_synonyms_tab" },
    { "usda_symbol": "EQCA",  "scientific_name": "Equisetum calderi B. Boivin",                    "source": "usda_synonyms_tab" }
  ]
}

Try it → https://api.rootfast.org/v1/plants/EQAR/synonyms

§6Reverse lookup by GBIF

GET

/v1/plants/by-gbif/{taxon_key}

Fetch the plant detail document by its GBIF Backbone taxon_key instead of by USDA symbol. Useful for joining rootfast to any dataset that already speaks GBIF (iNaturalist, ITIS, eBird, BHL, etc.). Response shape is identical to `/v1/plants/{usda_symbol}`. When multiple USDA plants map to the same GBIF key (synonyms), the accepted entry wins.

Request

curl 'https://api.rootfast.org/v1/plants/by-gbif/5285053'

Response · 200

{
  "plant": {
    "usda_symbol": "PIPO",
    "scientific_name": "Pinus ponderosa Lawson & C. Lawson",
    "common_name": "ponderosa pine",
    "gbif_taxon_key": 5285053,
    "gbif_match_type": "EXACT",
    "...": "..."
  },
  "photo": { "url": "...", "thumb_url": "...", "license": "cc-by-nc" },
  "growth_habits": ["Tree"],
  "durations": ["Perennial"],
  "characteristics": { "...": "..." },
  "counties": [ { "county_fips": "30031", "county_name": "Gallatin", "state_code": "MT", "nativity": "Native" } ]
}

Try it → https://api.rootfast.org/v1/plants/by-gbif/5285053

§7A random plant

GET

/v1/plants/random

Returns one random photographed species from the catalogue. Good for "plant of the day" widgets and seed examples. Cached at the edge for 60 s so it rotates often but cheaply.

Request

curl 'https://api.rootfast.org/v1/plants/random'

Response · 200

{
  "plant": {
    "usda_symbol": "EPSA",
    "scientific_name": "Epilobium saximontanum Hausskn.",
    "common_name": "Rocky Mountain willowherb",
    "family": "Onagraceae Juss.",
    "photo_thumb_url": "https://inaturalist-open-data.s3.amazonaws.com/photos/.../square.jpg",
    "photo_url":       "https://inaturalist-open-data.s3.amazonaws.com/photos/.../medium.jpg"
  }
}

Try it → https://api.rootfast.org/v1/plants/random

§8All counties, paginated

GET

/v1/counties?state={code}&limit={n}&offset={n}

Flat list of every county in the catalogue, optionally filtered by state. Default limit is 500, max 5000. Each row carries the FIPS code, state code, centroid lat/lon for mapping.

Request

curl 'https://api.rootfast.org/v1/counties?state=RI'

Response · 200

{
  "count": 5,
  "total": 5,
  "limit": 500,
  "offset": 0,
  "has_more": false,
  "counties": [
    {
      "county_fips": "44001",
      "county_name": "Bristol",
      "state_code": "RI",
      "centroid_lat": 41.7,
      "centroid_lon": -71.28
    }
  ]
}

Try it → https://api.rootfast.org/v1/counties?state=RI

§9Plants in a county

GET

/v1/counties/{county_fips}/plants?{filters}

All taxa recorded in the given county, with nativity. FIPS is the 5-digit Census code (Gallatin County, MT is 30031). Accepts the filter parameters under §F.

Request

curl 'https://api.rootfast.org/v1/counties/30031/plants'

Response · 200

{
  "county": {
    "county_fips": "30031",
    "county_name": "Gallatin",
    "state_code": "MT"
  },
  "count": 1362,
  "plants": [
    {
      "usda_symbol": "ABLA",
      "scientific_name": "Abies lasiocarpa (Hook.) Nutt.",
      "common_name": "subalpine fir",
      "family": "Pinaceae Spreng. ex Rudolphi",
      "nativity": "Native"
    }
  ]
}

Try it → https://api.rootfast.org/v1/counties/30031/plants

§10List of states

GET

/v1/states

States with ingested data, plus county and taxon counts. Filters out states present in the catalogue but lacking any distribution data — currently just Connecticut, pending USDA's republish against the new planning regions (see /about). CT remains addressable via /v1/states/CT for direct lookups.

Request

curl 'https://api.rootfast.org/v1/states'

Response · 200

{
  "count": 54,
  "states": [
    {
      "state_code": "MT",
      "state_name": "Montana",
      "state_fips": "30",
      "country": "US",
      "county_count": 56,
      "taxa_count": 3215
    }
  ]
}

Try it → https://api.rootfast.org/v1/states

§11State header

GET

/v1/states/{state_code}

Single-state header with county and taxon counts. State code is the two-letter postal abbreviation (case-insensitive).

Request

curl 'https://api.rootfast.org/v1/states/MT'

Response · 200

{
  "state": {
    "state_code": "MT",
    "state_name": "Montana",
    "state_fips": "30",
    "country": "US",
    "county_count": 56,
    "taxa_count": 3215
  }
}

Try it → https://api.rootfast.org/v1/states/MT

§12Plants in a state

GET

/v1/states/{state_code}/plants?limit&offset&{filters}

Every taxon in the state, aggregated across counties. county_count is how many counties the taxon appears in; native_counties / introduced_counties / both_counties give the breakdown. nativity is the state-level rollup: "Native" if no introduced records, "Introduced" if no native records, "Both" if mixed or any county records "Both". Paginated (default limit 5000, max 10000) and accepts the filter parameters under §F.

Request

curl 'https://api.rootfast.org/v1/states/MT/plants'

Response · 200

{
  "state": {
    "state_code": "MT",
    "state_name": "Montana",
    "state_fips": "30",
    "country": "US"
  },
  "counts": { "taxa": 3215, "counties": 56 },
  "paging": { "limit": 5000, "offset": 0, "count": 3215, "has_more": false },
  "plants": [
    {
      "usda_symbol": "PIPO",
      "scientific_name": "Pinus ponderosa Lawson & C. Lawson",
      "common_name": "ponderosa pine",
      "family": "Pinaceae Spreng. ex Rudolphi",
      "photo_thumb_url": null,
      "county_count": 22,
      "native_counties": 22,
      "introduced_counties": 0,
      "both_counties": 0,
      "nativity": "Native"
    }
  ]
}

Try it → https://api.rootfast.org/v1/states/MT/plants

§13Counties in a state

GET

/v1/states/{state_code}/counties

Lightweight listing of every county in the state with its taxa count. Useful for state-overview pages and county pickers.

Request

curl 'https://api.rootfast.org/v1/states/MT/counties'

Response · 200

{
  "state": { "state_code": "MT", "state_name": "Montana", "state_fips": "30", "country": "US" },
  "count": 56,
  "counties": [
    {
      "county_fips": "30001",
      "county_name": "Beaverhead",
      "state_code": "MT",
      "centroid_lat": 45.07,
      "centroid_lon": -112.86,
      "taxa_count": 755
    }
  ]
}

Try it → https://api.rootfast.org/v1/states/MT/counties

§14Hardiness zone reference

GET

/v1/hardiness/zones

Canonical 26-row USDA Plant Hardiness Zone (2023) reference: every half-zone from 1a (-60 to -55 °F) to 13b (65 to 70 °F), with the count of ZIPs and counties currently mapped to each. zone_class_code is the USDA-published integer index (1=1a, 2=1b, …, 26=13b).

Request

curl 'https://api.rootfast.org/v1/hardiness/zones'

Response · 200

{
  "count": 26,
  "zones": [
    {
      "zone_code": "1a",
      "zone_class_code": 1,
      "temp_min_f": -60,
      "temp_max_f": -55,
      "description": "1a (-60 to -55 °F)",
      "zip_count": 5,
      "county_count": 0
    }
  ]
}

Try it → https://api.rootfast.org/v1/hardiness/zones

§15Single hardiness zone

GET

/v1/hardiness/zones/{zone_code}

Same shape as one row of /v1/hardiness/zones. zone_code is the half-zone label like "5a" or "13b" (case-insensitive).

Request

curl 'https://api.rootfast.org/v1/hardiness/zones/5a'

Response · 200

{
  "zone": {
    "zone_code": "5a",
    "zone_class_code": 9,
    "temp_min_f": -20,
    "temp_max_f": -15,
    "description": "5a (-20 to -15 °F)",
    "zip_count": 2426,
    "county_count": 226
  }
}

Try it → https://api.rootfast.org/v1/hardiness/zones/5a

§16Hardiness zone by ZIP

GET

/v1/hardiness/zip/{zip}

USDA-published hardiness zone for the given US ZIP code. Accepts 5-digit ZIP and ZIP+4 (extra digits are ignored). Sourced from the PHZM 2023 Zip Code Table, 40,502 ZIPs total. Pair with a plant's temperature_min_f to filter the catalogue by what survives the winter where you live.

Request

curl 'https://api.rootfast.org/v1/hardiness/zip/59715'

Response · 200

{
  "zip_code": "59715",
  "zone": {
    "zone_code": "5a",
    "zone_class_code": 9,
    "temp_min_f": -20,
    "temp_max_f": -15,
    "description": "5a (-20 to -15 °F)"
  }
}

Try it → https://api.rootfast.org/v1/hardiness/zip/59715

§17Hardiness zone by county

GET

/v1/hardiness/county/{county_fips}

Predominant hardiness zone for a county, sampled at the county centroid against the USDA PHZM polygon layer. A 5-digit FIPS code (e.g. 30031 for Gallatin, MT). Mainland and Hawaii are well-covered (3,199 / 3,227 counties). The 28 missings — mostly American Samoa, Northern Mariana Islands, and a handful of water-heavy coastal counties whose centroid falls outside the zone polygons — return `zone: null` with a note.

Request

curl 'https://api.rootfast.org/v1/hardiness/county/30031'

Response · 200

{
  "county": {
    "county_fips": "30031",
    "county_name": "Gallatin",
    "state_code": "MT"
  },
  "zone": {
    "zone_code": "5a",
    "zone_class_code": 9,
    "temp_min_f": -20,
    "temp_max_f": -15,
    "description": "5a (-20 to -15 °F)"
  }
}

Try it → https://api.rootfast.org/v1/hardiness/county/30031

§19OpenAPI 3.0 spec

GET

/v1/openapi.json

Machine-readable description of every endpoint, parameter, response shape, and error code. Drop it into Postman / Insomnia / Bruno, generate typed clients with openapi-generator, validate responses in CI, or feed it to LLM tool-calling frameworks so AI agents can use the API directly. The companion interactive UI lives at /v1/docs (Scalar). Spec version 1.0.0.

Request

curl 'https://api.rootfast.org/v1/openapi.json'

Response · 200

{
  "openapi": "3.0.3",
  "info": {
    "title": "Rootfast API",
    "version": "1.0.0",
    ...
  },
  "servers": [
    { "url": "https://api.rootfast.org" }
  ],
  "paths": { /* 19 paths */ },
  "components": { /* schemas, parameters, responses */ }
}

Try it → https://api.rootfast.org/v1/openapi.json

§BBulk download

Take the data.

The list endpoints accept ?format=csv or ?format=ndjson for archival / spreadsheet / pipeline use. The response is sent as an attachment with a sensible filename; Content-Type is set to text/csv or application/x-ndjson as appropriate. Bulk downloads default to no pagination cap (50 000 rows max per call); apply filters under §F to scope the result.

Endpoints that support bulk

  • · /v1/plants — flat catalogue dump
  • · /v1/counties — every US county (also accepts format=geojson — see below)
  • · /v1/states/{code}/plants — one state's taxa
  • · /v1/counties/{fips}/plants — one county's taxa

GeoJSON output

/v1/counties?format=geojson returns a standard GeoJSON FeatureCollection. Each feature is a Point at the county centroid (we don't store full polygons yet); properties carry the FIPS code, county name, and state. Drop the URL straight into Leaflet, Mapbox GL, deck.gl, QGIS, or Mapshaper. Content-Type is application/geo+json.

# Every Rhode Island county as GeoJSON
curl 'https://api.rootfast.org/v1/counties?state=RI&format=geojson'

# In Leaflet:
fetch('https://api.rootfast.org/v1/counties?state=RI&format=geojson')
  .then(r => r.json())
  .then(fc => L.geoJSON(fc).addTo(map));

Examples

# Whole catalogue as CSV
curl -O 'https://api.rootfast.org/v1/plants?format=csv'

# All MT plants as NDJSON (one JSON object per line)
curl 'https://api.rootfast.org/v1/states/MT/plants?format=ndjson' \
  > mt-plants.ndjson

# Drought-tolerant native trees in Gallatin County as CSV
curl 'https://api.rootfast.org/v1/counties/30031/plants?\
growth_habit=Tree&nativity=Native&drought_tolerance=High&format=csv'

# Every US county as CSV (FIPS, name, state, centroid)
curl 'https://api.rootfast.org/v1/counties?format=csv&limit=5000'

All data is CC0 / public domain — use it freely. A citation back to rootfast.org is appreciated but not required.

§FFilter parameters

Narrow the list.

The list endpoints /v1/states/{code}/plants and /v1/counties/{fips}/plants accept query parameters that filter the result set. Multiple parameters AND together. Enum parameters accept comma-separated lists (OR within the parameter). Invalid values return 400 bad_request.

Plant-level

family
Prefix match against the USDA family string. Example: ?family=Pinaceae.
genus
Exact match. Example: ?genus=Pinus.
rank
One of Species,Subspecies,Variety,Form.
growth_habit
One of Tree,Shrub,Subshrub,Vine,Forb/herb,Forb,Graminoid,Nonvascular,Lichenous.
duration
One of Annual,Biennial,Perennial.
nativity
One of Native,Introduced,Both. Filters at the county-record level.

Characteristics — enums

drought_tolerance
High,Medium,Low,None
shade_tolerance
Intolerant,Intermediate,Tolerant
moisture_use
High,Medium,Low,None
growth_rate
Slow,Moderate,Rapid
toxicity
None,Slight,Moderate,Severe
lifespan
Short,Moderate,Long
commercial_availability
No Known Source,Routinely Available,Field Collections Only,Contracting Only
fire_tolerance
High,Medium,Low,None
salinity_tolerance
High,Medium,Low,None
nitrogen_fixation
High,Medium,Low,None

Characteristics — booleans

fire_resistant
Accepts 1/0, true/false, or yes/no.
palatable_human
Same.
nursery_stock_product
Same.
berry_nut_seed_product
Same.
lumber_product
Same.

Characteristics — colors (exact, case-insensitive)

flower_color
e.g. Yellow
foliage_color
e.g. Green
fruit_color
e.g. Red

Characteristics — numeric ranges

min_height_ft / max_height_ft
Mature height in feet.
min_ph / max_ph
Soil pH tolerance.
min_precipitation_in / max_precipitation_in
Inches of annual precipitation.
min_frost_free_days
Minimum required frost-free days.
min_temperature_f / max_temperature_f
Minimum tolerable temperature in °F.
min_root_depth_in
Minimum root depth in inches.

Examples

# Drought-tolerant native trees in Gallatin County, MT
GET /v1/counties/30031/plants?growth_habit=Tree&nativity=Native&drought_tolerance=High

# Mature shrubs 3–10 ft, full-sun-tolerant, found in Rhode Island
GET /v1/states/RI/plants?growth_habit=Shrub&shade_tolerance=Intolerant&min_height_ft=3&max_height_ft=10

# Pinaceae statewide in Montana
GET /v1/states/MT/plants?family=Pinaceae

# Trees or shrubs with high or medium drought tolerance
GET /v1/states/AL/plants?growth_habit=Tree,Shrub&drought_tolerance=High,Medium

§EErrors

Errors are structured.

Every error returns a JSON body of { "error": { "code": "<machine-readable>", "message": "<human-readable>" } }. The HTTP status reflects the failure category and the code string is stable so clients can branch on it.

400
bad_request — Malformed query (e.g. invalid limit).
404
not_found — Unknown plant symbol, county FIPS, state code, or route.
405
method_not_allowed — Only GET and HEAD are supported.
500
internal_error — Server-side fault. Rare; please include the URL when reporting.

§CCaching

Cache aggressively.

The dataset only changes when we re-import a SQLite chunk (rarely; never silently). Every response includes a Cache-Control header tuned to that reality. s-maxage applies at Cloudflare's edge; max-age is the browser-side hint.

/healthz
no-store — always fresh.
/v1/plants/{symbol}
max-age=3600, s-maxage=86400
/v1/plants/random
max-age=0, s-maxage=60 — rotates ~every minute.
/v1/counties[/...]
max-age=600–3600, s-maxage=86400
/v1/states[/...]
max-age=600, s-maxage=86400
/v1/search
max-age=60, s-maxage=300

ETag + 304 Not Modified

Every cacheable response carries a weak ETag header derived from the body content. Send it back as If-None-Match on a follow-up request and the API will respond with 304 Not Modified and no body if nothing changed. Browsers handle this automatically; library clients should opt in by storing the ETag and including it on subsequent fetches.

# Conditional GET — second request is empty + 304 if unchanged
ETAG=$(curl -sI 'https://api.rootfast.org/v1/plants/PIPO' \
        | awk '/^etag:/ {print $2}' | tr -d '\r')

curl -sI -H "If-None-Match: $ETAG" \
     'https://api.rootfast.org/v1/plants/PIPO'
# HTTP/2 304
# etag: W/"abcdef1234567890"
# cache-control: public, max-age=3600, s-maxage=86400

§RRate limits

Be polite. Limits are generous.

The API is open and uncapped at the dataset level — CC0, no keys, no commercial gating. We do enforce per-IP rate limits to keep a single client from squeezing the service for everyone else. Limits are intentionally loose for normal browsing and tight only on the bulk-export and search endpoints, which are the only ones that can do real damage to the underlying D1.

Default (most endpoints)
120 req / 60 s / IP — ≈ 2 requests/second sustained.
Bulk export (?format=csv or ?format=ndjson)
5 req / 60 s / IP — pull whole-state catalogues sparingly.
Search (/v1/search & POST /v1/plants/search)
60 req / 60 s / IP — debounce live-search UIs.
/healthz, /v1/openapi.json, /v1/docs
No limit. Cheap, edge-cached, frequently polled.

When you hit one

The API returns a 429 Too Many Requests with a Retry-After: 60 header and a structured JSON body so you can react properly.

# 429 response body
{
  "error": {
    "code": "rate_limited",
    "message": "Bulk-export quota exceeded (5 req/min/IP). Slow down or filter the export."
  },
  "tier": "bulk",
  "retry_after": 60
}

Hitting the limits regularly under legitimate use? Get in touch via contact and we'll sort out a higher quota — limits are calibrated against today's traffic, not against any particular user.

§PPlanned

On the roadmap.

Items below are intentionally not implemented yet. They will land as the API matures and as real usage tells us they're needed. If one of these is blocking you, send a note via contact.

API keys

No keys exist today. Anonymous rate limits (see §R) are generous enough for nearly every legitimate use case. If you have a workload that consistently bumps against them, send a note via contact — we'll set up a self-serve key flow with a higher quota if there's real demand. Keys, if they land, will be free for non-commercial use; commercial use is already allowed under CC0 with no key needed.

No timeline — added only when real users need them.

§LLicense & attribution

Use it freely. Cite the sources.

The Rootfast dataset is derived from public-domain federal data. The original source records are in the public domain. The merged dataset and this API are published as a public good. No API key is required and there is no commercial gating planned.

  • · USDA PLANTS — public domain
  • · USDA-ARS Plant Hardiness Zone Map (2023) — public domain
  • · GBIF Backbone Taxonomy — CC0
  • · iNaturalist photos — hot-linked, per-photo CC license preserved on each record
  • · Rootfast code — MIT
  • · Rootfast data — CC0 (excluding the photo URLs above)

If you build something with this — a tool, a garden plan, a research paper — we would love to hear about it. Full source, ETL pipelines, and the discovery notes for each upstream API live at github.com/cjscrofani/rootfast ↗.