School District Finder API

A free JSON API for US public school district data, addressable by ZIP code.

33,559 ZIP codes 56 states & territories No API key CORS enabled CC BY 4.0

Every response is JSON served over HTTPS from https://api.schooldistrictfinder.us. There is no authentication, no API key and no signup — issue a GET and you get data. Access-Control-Allow-Origin: * is set on every response, so the API can be called directly from a browser.

A machine-readable OpenAPI 3.0 description of everything below lives at /openapi.json.

Endpoints

GET /zip/{zip}.json

School district serving a single 5-digit US ZIP code. Covers all 33,559 ZIP codes in the dataset. Unknown ZIP codes return 404 with a JSON error body.

Example: /zip/90210.json

GET /state/{state}.json

Every ZIP record in one state or territory, as { state, count, source, license, records[] }. {state} is the uppercase two-letter postal abbreviation. 56 files exist: the 50 states plus DC, PR, VI, GU, AS and MP.

Example: /state/CA.json — 1,803 records.

GET /bulk/all-districts.json

The entire dataset in one file — all 33,559 records under a records array, with total, source, license and updated metadata. Roughly 17 MB uncompressed.

Example: /bulk/all-districts.json

GET /bulk/all-districts.csv

The same 33,559 records as CSV (roughly 7 MB), served as a file download. Columns: zip, district, city, state, county, rating, rating_label, students, schools, per_pupil, grade_span, phone, website, page_url, updated.

Example: /bulk/all-districts.csv

GET /index.json

Master index of every covered ZIP code with its district, city, state, rating and API URL. Useful for discovering coverage without downloading the full dataset.

Example: /index.json

Example response

GET https://api.schooldistrictfinder.us/zip/90210.json

{
  "zip": "90210",
  "district": "Beverly Hills Unified School District",
  "city": "Beverly Hills",
  "state": "CA",
  "county": "Los Angeles County",
  "rating": 9,
  "rating_label": "Excellent",
  "students": "3,140",
  "schools": "6",
  "per_pupil": "$21,000/yr",
  "grade_span": "Kindergarten – 12th",
  "phone": "(310)551-5100",
  "website": "http://www.bhusd.org",
  "page_url": "https://www.schooldistrictfinder.us/zip/90210/",
  "source": "NCES Common Core of Data 2024-2025",
  "source_url": "https://nces.ed.gov/ccd/",
  "license": "https://creativecommons.org/licenses/by/4.0/",
  "updated": "2026-05-30"
}

Record fields

FieldDescription
zip5-digit US ZIP code, zero-padded.
districtFull official name of the school district serving the ZIP code.
cityPrimary city served.
stateTwo-letter state or territory abbreviation.
countyCounty name. May be an empty string where none is recorded.
ratingDistrict rating from 1 (lowest) to 10 (highest), or null when the district has no rating.
rating_labelText label for the rating (Excellent, Good, Average, Below Average, Poor). Empty string when rating is null.
studentsTotal enrollment, formatted string.
schoolsNumber of schools in the district, formatted string.
per_pupilPer-pupil spending, formatted string. Values marked (est.) are estimates.
grade_spanGrade range served, e.g. Kindergarten – 12th.
phoneDistrict main phone number. May be an empty string.
websiteDistrict website URL. May be an empty string.
page_urlHuman-readable page for this ZIP code on schooldistrictfinder.us.
sourceData source name.
source_urlData source URL.
licenseLicense URL for the data.
updatedDate this record was last built, YYYY-MM-DD.

A field that has no value is returned as an empty string rather than being omitted, so every record has the same shape. The single exception is rating, which is null for districts without a rating.

Usage

curl https://api.schooldistrictfinder.us/zip/90210.json
const r = await fetch("https://api.schooldistrictfinder.us/zip/90210.json");
const district = await r.json();
console.log(district.district); // "Beverly Hills Unified School District"
import requests
r = requests.get("https://api.schooldistrictfinder.us/state/CA.json")
print(r.json()["count"])  # 1803

Responses are cached for 24 hours (Cache-Control: public, max-age=86400, stale-while-revalidate=604800). If you need the whole dataset, please pull /bulk/all-districts.json once rather than looping over the 33,559 per-ZIP endpoints.

Data source and license

ZIP-code-to-district assignment is a geographic approximation: ZIP codes and school district boundaries do not align exactly, and a single ZIP code can be split across more than one district. Each record names the district covering the largest share of the ZIP code. Verify enrollment eligibility with the district itself.