Quick start

Read a season for one species in one place: two requests with any HTTP client, or a few lines with the package.

1. Find the current release

Every file sits inside a dated release that never changes. current.json names the current one. Read it once, then read everything else from that release.

Shell
curl https://api.openphenology.com/current.json
Response
{
  "id": "current.json",
  "kind": "current",
  "format": "current/1.0",
  "provenance": { "release": "2026-11-13", … },
  "data": { "release": "2026-11-13", "published_at": "2026-11-13T09:14:00Z" }
}

2. Read a result

A county result lives at results/<state>/<county>/<species_key>.json. States use lowercase ISO 3166-2 codes (us-oh) and counties their Census GEOID (39049 is Franklin County). Species keys come from the catalogue.

Shell
curl https://api.openphenology.com/releases/2026-11-13/results/us-oh/39153/32NKH.json

3. Or use the package

@openphenology/api reads the files for you, in Node.js and in browsers, with types for every format. It pins one release per client, retries network errors and can check each file against the manifest.

Shell
npm install @openphenology/api
TypeScript
import { createClient } from "@openphenology/api";

const release = await createClient().release();
const result = await release.countyResult("us-oh", "39153", "32NKH");

if (result) console.log(result.data.season); // [early, middle, late] weeks, or []

The package's source on GitHub (opens in a new tab)

4. Or explore in Postman

A Postman collection has a request for every published file, each with a description, an example response and tests. No keys are needed. In Postman, choose Import and paste this link:

Link
https://raw.githubusercontent.com/openphenology/openphenology-api/main/postman/openphenology.postman_collection.json

Send Start here › Current release first. It fills in the current release, so the rest of the collection runs without typing anything. The collection's guide (opens in a new tab) explains its variables and tests.

When a file is missing

A result with too few records, or one withheld to protect a sensitive species, is never written. It looks exactly like a result that does not exist: the request returns 404, and the package returns null. Missing does not mean absent.

Good to know

  • OpenPhenology is in beta: the site and the @openphenology/api package may change before 1.0.0. File formats change only by version.
  • Results pool complete years, from pooled_from in methods.json through the last year before the release. Records from the release's own year are stored but not yet counted. pooled_from moves forward one year each new year. Records before it are kept but not counted.
  • Only GET, from any site: CORS is open and there are no keys.
  • The data files have no fixed rate limit. They are cached at the edge, and a client that abuses them may be blocked. To fetch a whole release, download its archive.tar.gz once instead. The sites allow 100 page requests per IP address in any 10 seconds; over that, pages get HTTP 429 for 10 seconds.
  • Release files are cached for a year; current.json for about 5 minutes.
  • Responses are compressed when your client accepts it. No file is over 500 KB compressed; larger lists are split into numbered shards.
  • No analytics or request logs are kept beyond Cloudflare's aggregate traffic figures.