# DistrictAPI — LLM Reference DistrictAPI is a REST API for US public school district and school data, built on free federal datasets (NCES CCD, NCES EDGE, Census TIGER). Every US public school district and school is covered. Base URL: https://api.districtapi.dev Current version: v1 Data vintage: NCES 2024-25 (released December 2025) --- ## Authentication Pass an API key on every request using one of: Header: X-API-Key: sk_live_... Header: Authorization: Bearer sk_live_... API keys are obtained free at https://districtapi.dev/dashboard (500 requests/month, no credit card). --- ## Rate Limits | Plan | Per minute | Per month | |------------|------------|-----------| | Free | 10 | 500 | | Starter | 60 | 10,000 | | Pro | 120 | 50,000 | | Growth | 300 | 200,000 | Exceeding per-minute limit → 429 RATE_LIMIT_EXCEEDED Exceeding monthly limit → 402 QUOTA_EXCEEDED Monthly quotas reset on the 1st of each calendar month. --- ## Response Envelope Every successful response uses this envelope: { "data": , "meta": { "requestId": "req_9f4b2a1c8e3d", "creditsUsed": 1, "creditsRemaining": 499 }, "source": { "ncesYear": "2024-25", "updatedAt": "2025-12-15", "freshnessDays": 131 } } All field names in responses are camelCase. Each API call costs 1 credit regardless of results returned. --- ## Important: Overlapping Districts Some US addresses are served by multiple school districts — for example, a city may have a separate elementary district (K-8) and high school district (9-12) whose boundaries overlap. The GET /v1/districts endpoint always returns an array. Most addresses return one district; split-district areas return two. Always iterate over the array rather than assuming a single result. --- ## Endpoints ### GET /v1/districts Look up all school districts serving an address or coordinates. Returns an array of District objects (usually 1, sometimes 2 for overlapping elementary/high districts). Query parameters: address string Street address, e.g. "350 Fifth Ave, New York, NY" — geocoded then spatial lookup lat number Latitude (use with lng) lng number Longitude (use with lat) nces_id string 7-digit NCES LEA ID (e.g. "0600017") Provide exactly one of: address, lat+lng, or nces_id. Example request: GET /v1/districts?address=1060+W+Addison+St+Chicago+IL Example response: { "data": [ { "ncesId": "1709930", "name": "Chicago Public Schools Dist 299", "state": "IL", "county": "Cook County", "locale": { "code": "11", "name": "City, Large" }, "type": { "code": 1, "name": "Regular local school district" }, "status": "open", "grades": { "low": "PK", "high": "12" }, "address": { "street": "42 W Madison St", "city": "Chicago", "state": "IL", "zip": "60602" }, "phone": "(773) 553-1000", "website": "http://www.cps.edu", "geo": { "lat": 41.8338, "lng": -87.6243, "boundary": { "type": "MultiPolygon", "coordinates": [...] } }, "enrollment": { "total": 323278, "year": "2024-25" }, "finance": { "perPupilExpenditure": 16288, "totalRevenue": 5437000000, "federalRevenuePct": 18.2, "stateRevenuePct": 32.1, "localRevenuePct": 49.7, "fiscalYear": "2022-23" }, "schoolsCount": 514, "schools": null } ], "meta": { "requestId": "req_4a2b9c1d", "creditsUsed": 1, "creditsRemaining": 499 }, "source": { "ncesYear": "2024-25", "updatedAt": "2025-12-15", "freshnessDays": 131 } } --- ### GET /v1/districts/{nces_id} Fetch the full profile for a single district by its 7-digit NCES LEA ID. Returns a single District object (not an array). Path parameter: nces_id string 7-digit NCES LEA ID Example request: GET /v1/districts/1709930 Response: same District schema as above, wrapped in "data": { ... } (not an array). --- ### GET /v1/districts/{nces_id}/schools List all open schools in a district. Path parameter: nces_id string 7-digit NCES LEA ID Query parameters: type integer Filter by school type: 1=Regular, 2=Special Ed, 3=Vocational, 4=Alternative charter boolean If true, return only charter schools Example request: GET /v1/districts/1709930/schools Example response: { "data": [ { "ncesId": "170993000869", "name": "Alcott Elementary School", "grades": { "low": "PK", "high": "08" }, "type": { "code": 1, "name": "Regular School" }, "status": "open", "flags": { "isCharter": false, "isMagnet": false, "isVirtual": false }, "enrollment": { "total": 412, "year": "2024-25" }, "geo": { "lat": 41.9241, "lng": -87.6557 }, "address": { "street": "2625 N Orchard St", "city": "Chicago", "state": "IL", "zip": "60614" } } ], "meta": { "requestId": "req_7e3f1a2b", "creditsUsed": 1, "creditsRemaining": 498 }, "source": { "ncesYear": "2024-25", "updatedAt": "2025-12-15", "freshnessDays": 131 } } --- ### GET /v1/districts/search Search districts by name, state, or county. Provide at least one parameter. Query parameters: name string District name, full-text search (e.g. "Cupertino") state string Two-letter state abbreviation (e.g. "CA") county string County name, partial match (e.g. "San Bernardino") limit integer Results per page, max 100, default 20 offset integer Pagination offset, default 0 Example request: GET /v1/districts/search?name=Cupertino&state=CA Example response: { "data": [ { "ncesId": "0610290", "name": "Cupertino Union", "state": "CA", "county": "Santa Clara County", "status": "open", "grades": { "low": "KG", "high": "08" }, "enrollmentTotal": 17842, "lat": 37.3229, "lng": -122.0322 } ], "meta": { "requestId": "req_2c8d4e1f", "creditsUsed": 1, "creditsRemaining": 497 }, "source": { "ncesYear": "2024-25", "updatedAt": "2025-12-15", "freshnessDays": 131 } } --- ### GET /v1/schools Find schools near an address or coordinates. Query parameters: address string Center address for radius search lat number Latitude lng number Longitude radius_miles number Search radius in miles, max 50, default 5 limit integer Max results, max 100, default 20 Example request: GET /v1/schools?lat=37.3229&lng=-122.0322&radius_miles=2 Example response: { "data": [ { "ncesId": "061029001234", "name": "Lincoln Elementary", "state": "CA", "county": "Santa Clara County", "grades": { "low": "KG", "high": "05" }, "type": { "code": 1, "name": "Regular School" }, "status": "open", "flags": { "isCharter": false, "isMagnet": false, "isVirtual": false }, "enrollment": { "total": 528, "year": "2024-25" }, "geo": { "lat": 37.3189, "lng": -122.0298 } } ], "meta": { "requestId": "req_5b1e9d3a", "creditsUsed": 1, "creditsRemaining": 496 }, "source": { "ncesYear": "2024-25", "updatedAt": "2025-12-15", "freshnessDays": 131 } } --- ### GET /v1/schools/{nces_id} Get the full profile for a school by its 12-digit NCES school ID. Path parameter: nces_id string 12-digit NCES school ID Response fields: same School schema as above with full detail. --- ### GET /v1/schools/{nces_id}/district Get the parent district for a school. Path parameter: nces_id string 12-digit NCES school ID Response: single District object (same schema as GET /v1/districts/{nces_id}). --- ### POST /v1/districts/batch Resolve multiple addresses to districts in a single call. Requires Pro plan (100 addresses max) or Growth plan (500 addresses max). Each address costs 1 credit. Results are returned in input order. Request body (JSON): { "addresses": [ { "address": "350 Fifth Ave, New York, NY", "ref": "property_001" }, { "address": "1060 W Addison St, Chicago, IL", "ref": "property_002" } ] } The "ref" field is optional — any string you provide is echoed back in the result for correlation. Example response: { "data": [ { "address": "350 Fifth Ave, New York, NY", "ref": "property_001", "ok": true, "district": { ...District object... } }, { "address": "1060 W Addison St, Chicago, IL", "ref": "property_002", "ok": true, "district": { ...District object... } } ], "meta": { "requestId": "req_8a2c5f3d", "creditsUsed": 2, "creditsRemaining": 494 }, "source": { "ncesYear": "2024-25", "updatedAt": "2025-12-15", "freshnessDays": 131 } } If an address can't be geocoded or no district is found, "ok" will be false and "error" will contain a message. The overall request still returns 200 — check "ok" per item. --- ### GET /v1/health Health check. Does not consume credits. Response: { "status": "ok", "version": "1.0.0" } --- ## District Object Schema ncesId string 7-digit NCES LEA ID — stable federal identifier name string Official district name state string 2-letter state abbreviation county string County name locale.code string NCES locale code (11=City Large, 21=Suburb Large, 41=Rural Fringe, etc.) locale.name string Human-readable locale description type.code integer LEA type code (1=Regular district, 3=Supervisory union, etc.) type.name string Human-readable LEA type status string "open" | "closed" | "inactive" grades.low string Lowest grade served (e.g. "PK", "KG", "01") grades.high string Highest grade served (e.g. "08", "12") address.street string District office street address address.city string address.state string address.zip string phone string website string geo.lat number District centroid latitude geo.lng number District centroid longitude geo.boundary object GeoJSON MultiPolygon of the district boundary (null if unavailable) enrollment.total integer Total student enrollment enrollment.year string School year for enrollment figure (e.g. "2024-25") finance.perPupilExpenditure number Per-pupil expenditure in USD finance.totalRevenue number Total district revenue in USD finance.federalRevenuePct number Percentage of revenue from federal sources finance.stateRevenuePct number Percentage of revenue from state sources finance.localRevenuePct number Percentage of revenue from local sources finance.fiscalYear string Fiscal year for finance data (e.g. "2022-23") schoolsCount integer Number of open schools in the district Finance data lags enrollment by ~2 years (most recent: 2022-23 fiscal year). Some fields may be null if not reported to NCES. --- ## Error Response Schema All errors return: { "detail": { "code": "ERROR_CODE", "message": "Human-readable description" } } Error codes: 400 INVALID_PARAMS Required parameters missing or conflicting 400 INVALID_ADDRESS Address could not be geocoded 401 INVALID_API_KEY Key missing, invalid, or revoked 402 QUOTA_EXCEEDED Monthly request quota reached 403 TIER_NOT_SUPPORTED Endpoint requires a higher plan (e.g. batch on free tier) 404 DISTRICT_NOT_FOUND No district found for location or ID 404 SCHOOL_NOT_FOUND No school found for ID 429 RATE_LIMIT_EXCEEDED Too many requests per minute 500 INTERNAL_ERROR Server error --- ## Data Sources All data is sourced from free US federal datasets: - NCES Common Core of Data (CCD): district and school directory, enrollment, finance - NCES EDGE: lat/lng geocodes for all districts and schools - Census TIGER: school district boundary polygons - Data URL: nces.ed.gov/ccd/files.asp Data is updated annually following each NCES CCD release (typically December). Current dataset: 2024-25 school year (released December 2025). --- ## Common LLM Use Cases Finding a district by address: GET /v1/districts?address=
→ Returns array of districts. Use data[0] for the primary district, check length > 1 for split-district areas. Checking if two addresses share a school district: GET /v1/districts?address= → save ncesId GET /v1/districts?address= → compare ncesId Finding all schools near a location: GET /v1/schools?address=
&radius_miles=5 Getting district financial health: GET /v1/districts?address=
→ Check finance.perPupilExpenditure and finance.federalRevenuePct (higher federal % often indicates higher-need district) Bulk real estate enrichment (requires Pro): POST /v1/districts/batch with up to 100 addresses --- ## SDK and MCP Server Python SDK: pip install districtapi (github.com/districtapi/districtapi-python) Node.js SDK: npm install districtapi (github.com/districtapi/districtapi-node) MCP Server: uvx districtapi-mcp (github.com/districtapi/districtapi-mcp) Use directly inside Claude, Cursor, and any MCP-compatible AI assistant. --- ## Links Homepage: https://districtapi.dev Docs: https://districtapi.dev/docs Pricing: https://districtapi.dev/pricing Dashboard: https://districtapi.dev/dashboard GitHub: https://github.com/districtapi Support: hello@districtapi.dev