{"openapi":"3.1.0","info":{"title":"Texas School Finance API","description":"Public API for querying Texas ISD financial data (2009-2025) with natural language support","version":"1.0.0"},"paths":{"/api":{"get":{"tags":["General"],"summary":"Api Info","description":"API information and endpoint directory","operationId":"api_info_api_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/query":{"post":{"tags":["NLP"],"summary":"Nlp Query","description":"Process natural language query about Texas school finances\n\nExample queries:\n- \"Show Dallas ISD spending per student 2020-2024\"\n- \"Which districts have declining enrollment?\"\n- \"Compare Austin ISD and Houston ISD budgets\"","operationId":"nlp_query_query_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NLPQueryRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NLPQueryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/districts":{"get":{"tags":["Districts"],"summary":"List Districts","description":"List all districts with optional search","operationId":"list_districts_districts_get","parameters":[{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"description":"Search districts by name","title":"Search"},"description":"Search districts by name"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/district/{district_number}/summary":{"get":{"tags":["Districts"],"summary":"Get District Summary","description":"Get financial summary for a specific district","operationId":"get_district_summary_district__district_number__summary_get","parameters":[{"name":"district_number","in":"path","required":true,"schema":{"type":"string","title":"District Number"}},{"name":"start_year","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":2025,"minimum":2009},{"type":"null"}],"title":"Start Year"}},{"name":"end_year","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":2025,"minimum":2009},{"type":"null"}],"title":"End Year"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/anomalies":{"get":{"tags":["Anomalies"],"summary":"Get Anomalies","description":"Get districts with anomaly flags","operationId":"get_anomalies_anomalies_get","parameters":[{"name":"year","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":2025,"minimum":2009},{"type":"null"}],"title":"Year"}},{"name":"district_number","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":6},{"type":"null"}],"description":"Filter to one district","title":"District Number"},"description":"Filter to one district"},{"name":"flag_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by flag type","enum":["revenue_drop","spend_spike","per_student_spike","enrollment_decline"],"title":"Flag Type"},"description":"Filter by flag type"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/benchmarks":{"get":{"tags":["Benchmarks"],"summary":"Get Benchmarks","description":"Statewide per-year medians — the 'what's normal?' context that\ndistrict numbers are meaningless without.","operationId":"get_benchmarks_benchmarks_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/district/{district_number}/peers":{"get":{"tags":["Districts"],"summary":"Get District Peers","description":"Peer comparison, plus this district's statewide percentile. The #1\ndemand in admin usage simulation (docs/UX_RESEARCH.md).\n\nPeers come from the precomputed similarity graph (k-NN on EXOGENOUS\nfeatures only — size, enrollment trajectory, funding capacity, local-tax\nshare — so benchmarking spending against them is not circular; see\nscripts/build_similarity_graph.py). Falls back to an enrollment window\nif the graph has no edges for this district.","operationId":"get_district_peers_district__district_number__peers_get","parameters":[{"name":"district_number","in":"path","required":true,"schema":{"type":"string","title":"District Number"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/district/{district_number}/breakdown":{"get":{"tags":["Districts"],"summary":"Get District Breakdown","description":"Function-level spending breakdown (MECE categories from TEA function\ncodes) for every year — where the money actually goes.","operationId":"get_district_breakdown_district__district_number__breakdown_get","parameters":[{"name":"district_number","in":"path","required":true,"schema":{"type":"string","title":"District Number"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/dollar/texas":{"get":{"tags":["General"],"summary":"Get Texas Dollar","description":"The whole state's dollar, pooled: every category summed across every\ndistrict and divided by total spending. Unlike the per-district peer bars\nthis needs no rescaling — it is one real dollar made of real dollars.","operationId":"get_texas_dollar_dollar_texas_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/district/{district_number}/dollar":{"get":{"tags":["Districts"],"summary":"Get District Dollar","description":"Where one dollar goes, as 100 pennies — for this district, for its\nstructural peers, and for Texas as a whole, with the dollar amount at stake\nin each category if the district spent at the peer rate.\n\nPeer shares are the MEDIAN share across peer districts, renormalised to 100\npennies (medians of separate categories do not sum to a whole dollar on\ntheir own). Dollars at stake use median dollars *per student*, so they are\nreal money, not renormalised.","operationId":"get_district_dollar_district__district_number__dollar_get","parameters":[{"name":"district_number","in":"path","required":true,"schema":{"type":"string","title":"District Number"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/district/{district_number}/turnarounds":{"get":{"tags":["Districts"],"summary":"Get District Turnarounds","description":"Walk the similarity graph and find structural peers that reversed a\nsustained deficit (>=2 deficit years then >=2 surplus years) or a\nsustained enrollment decline (>=3 down years then >=2 up years).\nSee docs/GRAPH_INSIGHTS.md.","operationId":"get_district_turnarounds_district__district_number__turnarounds_get","parameters":[{"name":"district_number","in":"path","required":true,"schema":{"type":"string","title":"District Number"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/district/{district_number}/insights":{"get":{"tags":["Districts"],"summary":"Get District Insights","description":"Actionable intelligence: where this district materially differs from\nits similarity-graph peers, each finding quantified in dollars and ranked\nby magnitude. Peers come from the exogenous k-NN graph so the comparison\nis apples-to-apples.","operationId":"get_district_insights_district__district_number__insights_get","parameters":[{"name":"district_number","in":"path","required":true,"schema":{"type":"string","title":"District Number"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/district/{district_number}/spending-detail":{"get":{"tags":["Districts"],"summary":"Get District Spending Detail","description":"Two more spending dimensions the summarized data already carries:\nOBJECT (what was bought — payroll/contracted/supplies/other, sums to\noperating) and PROGRAM (who it served — regular/special-ed/bilingual/\ncareer-tech/gifted/compensatory/athletics), every year.","operationId":"get_district_spending_detail_district__district_number__spending_detail_get","parameters":[{"name":"district_number","in":"path","required":true,"schema":{"type":"string","title":"District Number"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/district/{district_number}/outcomes":{"get":{"tags":["Districts"],"summary":"Get District Outcomes","description":"What the money buys: student population, teaching workforce, and\nresults, each against this district's structural peers and the state.\n\nIncludes how the district scored versus what its student demographics\npredict. That is a question worth asking about a district, never a verdict\non it — the model explains only part of the spread, and the rest is real\ndifference, local context and noise. See docs/WHAT_A_DOLLAR_BUYS.md.","operationId":"get_district_outcomes_district__district_number__outcomes_get","parameters":[{"name":"district_number","in":"path","required":true,"schema":{"type":"string","title":"District Number"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/district/{district_number}/economics":{"get":{"tags":["Districts"],"summary":"Get District Economics","description":"What you pay, where it goes, what it buys, and who does better.\n\nFour things a tax statement cannot tell you: the school tax on a $300,000\nhome in this district and how much of it leaves under recapture; how the\nbudget splits between teaching and servicing debt, including that debt in\nteacher-equivalents; how reliably this district beats what its student need\npredicts, measured over eleven years rather than one; and the named\ndistricts of the same size and student need that do so more reliably.\n\n`tax` is null for charters, which levy no property tax, and for any\ndistrict where two independent estimates of its tax base disagree by more\nthan 25% — a wrong number on someone's tax bill is worse than no number.","operationId":"get_district_economics_district__district_number__economics_get","parameters":[{"name":"district_number","in":"path","required":true,"schema":{"type":"string","title":"District Number"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/economics/texas":{"get":{"tags":["Statewide"],"summary":"Get Texas Economics","description":"The statewide series behind every district page.\n\nPer-student spending in constant dollars beside nominal, the split of the\nschool tax rate between operating and debt over nineteen years, recapture\nby year and how concentrated it is, and the measured return on each lever\na district actually controls. Serves with no database.","operationId":"get_texas_economics_economics_texas_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/district/{district_number}/bonds":{"get":{"tags":["Districts"],"summary":"Get District Bonds","description":"Every bond this district ever put on a ballot, and how the vote went.\n\nTEA's financial data can say how much a district spends servicing debt but\nnot what the debt was for — it does not itemise facilities, so a stadium is\nnot separable from a roof. The ballot is the only public record that names\nwhat the money bought, with a date and a vote count attached.\n\nReturns each proposition (date, stated purpose, amount asked, carried or\ndefeated, votes for and against) plus this district's totals, and the\nstatewide context needed to read them.","operationId":"get_district_bonds_district__district_number__bonds_get","parameters":[{"name":"district_number","in":"path","required":true,"schema":{"type":"string","title":"District Number"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/bonds/texas":{"get":{"tags":["Statewide"],"summary":"Get Texas Bonds","description":"66 years of Texas school bond elections, without the per-district detail.\n\nPass rate by stated purpose, the shift in what districts ask for and what\nvoters approve, and what bundling a stadium with classrooms does to both\nthe odds and the size of the ask.","operationId":"get_texas_bonds_bonds_texas_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/district/{district_number}/forensics":{"get":{"tags":["Districts"],"summary":"Get District Forensics","description":"The four money questions Texas reports in four incompatible places.\n\nWhat sits OUTSIDE the operating total (debt service is not in it, so a\ndistrict can look lean on instruction while carrying the state's heaviest\ndebt); who actually pays, from GROSS local collections rather than the\nnet-of-recapture figure TEA publishes; what the ballot said the debt was\nfor, which is the only public itemisation of school facilities that exists;\nand where the results landed against what this district's own student need\npredicts.\n\n`flags` are descriptions, not accusations: each one states a published\nnumber against a threshold that is published beside it in `meta.thresholds`.\nThere is deliberately no combined score — the four measures are unrelated\nand adding them would invent a ranking the data cannot support.","operationId":"get_district_forensics_district__district_number__forensics_get","parameters":[{"name":"district_number","in":"path","required":true,"schema":{"type":"string","title":"District Number"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/forensics/texas":{"get":{"tags":["Statewide"],"summary":"Get Texas Forensics","description":"Statewide totals, the ranked tables, and one compact row per district.\n\n`table` carries every district so the page can sort and filter without a\nround trip; the full per-district file is at\n`/district/{district_number}/forensics`. Serves with no database.","operationId":"get_texas_forensics_forensics_texas_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/district/{district_number}/trends":{"get":{"tags":["Districts"],"summary":"Get District Trends","description":"Seventeen fiscal years of this district, against the state's own line.\n\nEvery other view on this site reports one year, which can tell a board\nwhere it stands but not which way it is moving. This returns the series\nfor six measures — instruction's share of the operating dollar, instruction\nper student, debt service, security, operating balance and federal revenue\n— in constant 2024 dollars, plus each measure's first-to-last change and\nhow that change compares with the statewide one.\n\n`vs_state.steeper_than_state` is true when this district is moving in the\nworrying direction faster than Texas as a whole. It describes a direction,\nnot a cause: a falling instruction share can be a district cutting\nclassrooms or a district opening them, and this data cannot tell the two\napart.\n\nDistricts under 500 students carry `small_district`, because one retirement\nmoves their per-student figures more than a policy would.","operationId":"get_district_trends_district__district_number__trends_get","parameters":[{"name":"district_number","in":"path","required":true,"schema":{"type":"string","title":"District Number"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/trends/texas":{"get":{"tags":["Statewide"],"summary":"Get Texas Trends","description":"The seventeen-year statewide series and the six findings in it.\n\nCarries the balanced-panel check: every headline was re-derived on only the\ndistricts reporting in both the first and last year, so a trend cannot be\nan artefact of which districts report. Serves with no database.","operationId":"get_texas_trends_trends_texas_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/national/texas":{"get":{"tags":["Statewide"],"summary":"Get Texas National","description":"Texas against the other 49 states, on the federal government's ruler.\n\nEverything else on this site compares Texas districts to Texas. This is\nthe missing axis: NCES's per-pupil current expenditure ranks the 50\nstates and DC, and the payload carries Texas's rank, the dollar figure,\nand the numerator and denominator behind it — plus the same ranking\nrecomputed by fall membership instead of average daily attendance, so a\nreader can see the denominator choice does not drive the story. The\nfigures live in the payload, never in this text, so a fiscal-year\nrefresh cannot leave stale numbers here (that has happened before).\n\nDistrict-level: Census F-33 per-pupil current spending for every Texas\nindependent school district, each with its percentile among the U.S.\ndistricts with 500+ students. Current spending is the Census's own\nfigure and EXCLUDES construction, land and debt — it is deliberately not\ncomparable to the all-in per-student total elsewhere on this site, and\nthe two are never mixed.\n\nCensus fiscal 2024, one year behind the TEA fiscal 2025 data here.\nTexas charters have no F-33 row (the Census surveys governments), so\nthey carry an explained absence instead of a percentile. Serves with no\ndatabase.","operationId":"get_texas_national_national_texas_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/district/{district_number}/national":{"get":{"tags":["Districts"],"summary":"Get District National","description":"One district against every other district in the country.\n\nThe Census's own per-pupil current spending figure for this district and\nits percentile among the U.S. districts with 500+ students (the pool\nsize travels in the payload), plus the statewide rank for context.\nDistricts under 500 students show the figure but no percentile — the\nsite-wide rule, because per-student figures in tiny districts move on a\nsingle hire.\n\nCharters return an explained absence: the Census surveys governments,\nso a charter has no row anywhere in the country, which is different\nfrom being unranked.","operationId":"get_district_national_district__district_number__national_get","parameters":[{"name":"district_number","in":"path","required":true,"schema":{"type":"string","title":"District Number"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/erate/texas":{"get":{"tags":["Statewide"],"summary":"Get Texas Erate","description":"Federal E-Rate money for school connectivity — the dollars TEA's\nbooks never see.\n\nE-Rate discounts district internet and telecom, and USAC pays most of\nit straight to vendors, so it appears nowhere in PEIMS. Roughly a\nquarter of a billion dollars a year flows to Texas this way; the\npayload carries the year-by-year committed and disbursed series, the\napplicant-type buckets (district money attributed to TEA numbers;\nconsortium money counted but deliberately never attributed to member\ndistricts), and the service-type split.\n\nSums cover FRNs with status **Funded** only — a Pending row's\n\"commitment\" is the amount asked, not granted, and summing every\nstatus inflates a year by hundreds of millions. Years still inside\ntheir invoicing window are flagged `invoicing_open`; their drawn\npercentage is a floor, not a finding. Serves with no database.","operationId":"get_texas_erate_erate_texas_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/district/{district_number}/erate":{"get":{"tags":["Districts"],"summary":"Get District Erate","description":"One district's E-Rate history as its own applicant.\n\nCommitted and disbursed by funding year, the dominant service type,\nand the running totals. Districts with no record get an explained\nabsence — many buy connectivity through a regional consortium, whose\napplication cannot be split back to members, so 'no record' is never\npresented as 'no federal help'.","operationId":"get_district_erate_district__district_number__erate_get","parameters":[{"name":"district_number","in":"path","required":true,"schema":{"type":"string","title":"District Number"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/district/{district_number}/equity":{"get":{"tags":["Districts"],"summary":"Get District Equity","description":"How this district does for the students it actually serves.\n\nA district average hides who it is failing. This reports how the district's\neconomically disadvantaged students do at TEA's Meets grade level bar, and\nwhere that places them among poor students statewide — plus the same for\nemergent bilingual and special education students, the reading/maths split,\nand the change since last year.\n\nThe poor/non-poor gap is included but is deliberately NOT the headline: it\ncorrelates about zero with how well poor students actually do, because the\nnarrowest gaps belong to districts where nobody does well.","operationId":"get_district_equity_district__district_number__equity_get","parameters":[{"name":"district_number","in":"path","required":true,"schema":{"type":"string","title":"District Number"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/equity/texas":{"get":{"tags":["Statewide"],"summary":"Get Texas Equity","description":"Statewide results by student group, and who does best for poor students.","operationId":"get_texas_equity_equity_texas_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/takeover/houston":{"get":{"tags":["Statewide"],"summary":"Get Houston Takeover","description":"Did the June 2023 state takeover of Houston ISD change results?\n\nHouston's own before-and-after cannot answer that: every Texas district was\nclimbing out of the same pandemic hole at the same time. This compares\nHouston with districts that were in the same hole and were not taken over —\nat least 40,000 students and at least 60% economically disadvantaged as of\n2023, chosen on pre-takeover traits so the comparison cannot be picked to\nfit the answer.\n\nShips the checks alongside the result: whether the pre-takeover trends were\nparallel, where Houston's swing ranks against the same calculation run on\nevery Texas district, whether its student body changed, and which student\ngroups the gains did and did not reach.\n\nOne treated district means no meaningful p-value, and none is claimed.","operationId":"get_houston_takeover_takeover_houston_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/forensics/quality":{"get":{"tags":["Statewide"],"summary":"Get Forensic Quality","description":"Forensic-accounting tests on the filings themselves.\n\nThree questions a forensic accountant asks of any book of account, applied\nto 20,587 district-years of TEA's own data:\n\n**Do the numbers look real?** Benford's Law across all 1.2M filed figures —\nMAD 0.0004, close conformity. The per-district version is deliberately NOT\npublished: run naively it labels 1,104 of 1,211 districts \"nonconforming\",\nand a null simulation shows perfect Benford data scores the same way at\nthese sample sizes. The refusal ships with its evidence.\n\n**Does each filing add up?** Objects and revenue reconcile for 100% of\ndistrict-years; functions for 98.83%, and the gaps are named.\n\n**Who approved the debt?** Texas permits school debt with no election, and\nTEA does not record how debt was authorised. Districts paying debt service\nwith no voter-approved bond in the ballot record are listed.\n\nNone of this is evidence of wrongdoing, and every payload says so. What\nthese have in common is that the public record does not answer an obvious\nquestion. Serves with no database.","operationId":"get_forensic_quality_forensics_quality_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/debt/texas":{"get":{"tags":["Statewide"],"summary":"Get Texas Debt","description":"What Texas school districts still OWE — the stock, not the yearly payment.\n\nEvery other debt figure on this site comes from PEIMS and is a flow: what a\ndistrict paid out in one year. This is the balance. As of fiscal 2025 Texas\nschool districts owed **$236.7 billion** — $148.4B of principal not yet\nrepaid and **$88.3B of interest nobody has paid yet**, 37.3% of the whole.\nOn debt already sold, it clears in **2061**.\n\nSplit by instrument, because the two are not the same promise:\n\n**CIB** — current interest bonds. Interest paid twice a year, as expected.\n\n**CAB** — capital appreciation bonds. Nothing is paid until maturity;\ninterest compounds for the life of the bond and lands in a lump at the end.\n169 districts still carry them, with **$2.36B of interest deferred** against\n$440m of principal outstanding. Texas capped the practice in 2015, but bonds\nsold before then are still owed.\n\nDollars repaid per dollar borrowed is reported at each district's **peak**\nyear, never the current one: on a shrinking balance that ratio rises by\nitself (Leander ISD reads 4.5x in 2014 and would read 396x in 2030 with\nnothing having changed), so the current-year figure would be fiction.\n\nBorrowing to build schools is lawful and ordinary. None of this is evidence\nof wrongdoing. Serves with no database.","operationId":"get_texas_debt_debt_texas_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/district/{district_number}/debt":{"get":{"tags":["Districts"],"summary":"Get District Debt","description":"What one district still owes, and the year it clears.\n\nPrincipal and interest outstanding, the interest share, the per-student\nbalance, the history of the balance since 2005, and — where the district\nsold capital appreciation bonds — the interest deferred to maturity and the\nterms at its peak year.\n\nDistricts the Bond Review Board tracks no debt for return an `absence`\nsaying so rather than an empty object: carrying no bonded debt is a finding\nabout a district, not missing data.","operationId":"get_district_debt_district__district_number__debt_get","parameters":[{"name":"district_number","in":"path","required":true,"schema":{"type":"string","title":"District Number"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/campuses/texas":{"get":{"tags":["Statewide"],"summary":"Get Texas Campuses","description":"What the district rating hides.\n\nEvery other figure on this site is measured at the district, because that is\nwhere money is reported. It is the wrong unit for the question a family\nasks: a district rating is an average over campuses, and an average hides\nits own tails.\n\n**138,664 Texas students attend a campus the state rates D or F inside a\ndistrict the state rates A or B** — 221 campuses across 73 districts, with\n21,415 of those students at a campus rated F.\n\nAnd the spread is the rule: **779 of the 890 districts** with more than one\nrated campus contain campuses at different letter grades, and 196 span three\nor more. \"The district is a B\" is true and describes almost nobody's school.\n\nThree refusals are carried in the payload. \"Not Rated\" is not a bad rating\nand its 525 campuses are excluded rather than counted as failure.\nAlternative-education campuses are rated on a different scale and are\nexcluded from the headline, with the including-them figure published beside\nit. And no campus is ranked against a campus in another district — the claim\nis about the gap INSIDE a district, which is what a district rating conceals.\n\nNone of this is an accusation: a large district containing a struggling\ncampus is arithmetic, not misconduct. Serves with no database.","operationId":"get_texas_campuses_campuses_texas_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/district/{district_number}/campuses":{"get":{"tags":["Districts"],"summary":"Get District Campuses","description":"Every rated campus in one district, worst first, against the district's\nown rating.\n\nA district with no rated campus returns an `absence` saying which of the two\nreasons applies rather than an empty list.","operationId":"get_district_campuses_district__district_number__campuses_get","parameters":[{"name":"district_number","in":"path","required":true,"schema":{"type":"string","title":"District Number"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/spending/texas":{"get":{"tags":["Statewide"],"summary":"Get Texas Spending Detail","description":"Where the operating dollar actually goes — all sixteen PEIMS functions.\n\nEvery other figure on this site sorts spending into three buckets:\ninstruction, security, and \"operating\". The other fourteen function codes\nhave been in the warehouse since the first import and were published\nnowhere — so the site could say what a district spends in total and could\nnot say what it spends on **buses, meals, counsellors, nurses, sport, or\nthe superintendent's own office**.\n\nStatewide in fiscal 2025, of every operating dollar: **54.5% instruction**,\n5.3% school meals, 4.2% counsellors, 3.3% central administration, 3.1%\nbuses, 3.1% sport and band.\n\nTwo rules the figures obey. **Every share is of OPERATING spending**, never\nof total disbursements — total also carries bond-funded construction and\ndebt service, so a share against it would make a district mid-build look\nlike it spends less on children. And **a percentile is over districts that\nreported the function**, never over all 1,202: a district with no food\nservice line usually runs none, and scoring it a zero would rank every\nother district up.\n\nServes with no database.","operationId":"get_texas_spending_detail_spending_texas_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/district/{district_number}/spending":{"get":{"tags":["Districts"],"summary":"Get District Spending Breakdown","description":"One district's operating dollar, split sixteen ways, against the state.\n\nEach function carries what it is in plain English, the dollars, the\nper-student figure, its share of operating spending, a percentile among\ndistricts that reported it, and its share in the first year of the record\nso a reader can see which way it has moved.\n\nA function this district did not report is **left out rather than written\nas zero** — a district with no food service line usually runs none, and a\nzero would read as a finding about children's meals that nobody measured.\n\n`reconciles` is the sixteen functions summed back against the district's own\noperating total, published so a reader can check the arithmetic instead of\ntrusting it.","operationId":"get_district_spending_breakdown_district__district_number__spending_get","parameters":[{"name":"district_number","in":"path","required":true,"schema":{"type":"string","title":"District Number"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/tax/texas":{"get":{"tags":["Statewide"],"summary":"Get Texas Tax History","description":"What school tax rates have actually done since 2009.\n\nThe site could say what you pay now and not whether it had gone up, which\nis the question people actually arrive with.\n\n**The statewide median rate fell from $1.1951 to $0.9760 per $100 between\n2009 and 2024 — and the rate fell in 930 of 1,015 districts.** Bills still\nrose, because taxable values rose faster. A rate-only answer gets that\nbackwards, so both are published and the district payload separates them.\n\nThe bill quoted is the same $300,000 home priced under each year's rate. It\nis not anyone's actual bill: no appraisal roll is used and exemptions are\nnot modelled. Serves with no database.","operationId":"get_texas_tax_history_tax_texas_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/district/{district_number}/tax-history":{"get":{"tags":["Districts"],"summary":"Get District Tax History","description":"One district's rate since 2009, and why a bill moved.\n\nCarries the rate, its maintenance and debt halves, the taxable value roll,\nand a `reading` that names which of the two moved — because a bill can rise\nwith the rate untouched, and across most of Texas that is exactly what\nhappened.\n\nA charter returns an `absence`: it levies no property tax, which is not the\nsame as a missing figure.","operationId":"get_district_tax_history_district__district_number__tax_history_get","parameters":[{"name":"district_number","in":"path","required":true,"schema":{"type":"string","title":"District Number"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/performance/texas":{"get":{"tags":["Statewide"],"summary":"Get Texas Performance","description":"STAAR by student group, statewide, at the Meets bar.\n\nTwo figures per group, and they are not interchangeable. `meets` is\ntest-weighted — the share of Texas TESTS that met the bar, which is how the\ntypical STUDENT did. `meets_district_mean` averages district rates, which\nis how the typical DISTRICT did, and is what the equity layer reports.\n\nOn all students they read 49.7% and 46.4%. On White students the gap is\nwider still — 63.2% against 53.3% — because a district average counts a\n150-student district the same as Houston. Neither is wrong; they answer\ndifferent questions, and publishing only one would hide that.\n\nServes with no database.","operationId":"get_texas_performance_performance_texas_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/district/{district_number}/performance":{"get":{"tags":["Districts"],"summary":"Get District Performance","description":"One district's STAAR results by student group and by subject.\n\nGroups are published at DISTRICT grain deliberately: campus-by-group cells\nare mostly masked by TEA to protect identifiable students, and a table of\nblanks with a few children visible in it is worse than no table.\n\nA group missing from the response had **too few test-takers to report** —\nit did not score zero. TEA suppresses those cells and they are omitted here\nrather than rendered as 0%.","operationId":"get_district_performance_district__district_number__performance_get","parameters":[{"name":"district_number","in":"path","required":true,"schema":{"type":"string","title":"District Number"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/district/{district_number}/campus-performance":{"get":{"tags":["Districts"],"summary":"Get District Campus Performance","description":"Every campus in one district with its own STAAR scores, by subject.\n\nThe campus layer publishes a LETTER per campus; this publishes what its\nstudents actually scored, and in which subject — which is the question a\nparent is really asking when they ask how a school is doing.\n\nCampuses are returned for THIS district only. No campus is ranked against a\ncampus in another district: the finding is the spread inside a district,\nand a statewide campus league table is a far more dangerous artefact.","operationId":"get_district_campus_performance_district__district_number__campus_performance_get","parameters":[{"name":"district_number","in":"path","required":true,"schema":{"type":"string","title":"District Number"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/provenance":{"get":{"tags":["General"],"summary":"Get Provenance","description":"Where every number came from, and how to check it yourself.\n\n\"Is this accurate?\" is not answerable by asserting yes. It is answerable by\nnaming the government file a figure came from, the exact column, the\narithmetic, and the download link for the original — so a sceptic can redo\nit and disagree.\n\nReturns the upstream sources (publisher, product, URL, coverage, what each\nis authoritative for), every published measure tied to its source and to\nthe test that re-derives it from that source rather than from our own\noutput, the steps to verify the whole thing, and what none of it can\nestablish. Serves with no database.","operationId":"get_provenance_provenance_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/district/{district_number}/lineage/{metric}":{"get":{"tags":["Districts"],"summary":"Get Metric Lineage","description":"Why is this number this number?\n\nReturns the evidence behind one published figure — numerator, denominator,\nwhat the denominator MEANS, the formula, the fiscal year, the publisher and\nthe vintage — plus the publication gate's verdict.\n\nThe gate asks four questions, and each has a real failure behind it:\ncorrectness (does an independent recomputation agree), freshness (has the\npublisher moved on), aim (did we check the file we actually publish from),\nand computability (can this be computed at all). A figure that cannot be\ncomputed is REFUSED in public rather than guessed or left blank.\n\nWhat each check does and does not prove\n--------------------------------------\n`arithmetic` is narrow on purpose: the numerator and the denominator live in\nthe same file as the value, so it proves the division, never the inputs. It\nis reported under its own name rather than folded into `correctness`,\nbecause a figure would otherwise wear a badge reading checked-against-the-\nstate when nothing had left the artefact.\n\n`correctness` carries a recomputation the BUILD stamped in, from\nscripts/recompute_revenue.py — a longhand re-read of the source CSV with the\nstandard-library csv module, no pandas, nothing shared with the builder.\nThat is genuinely a second road through the pandas pipeline, but both roads\nread prepare_data.py's cleaned CSV rather than TEA's workbook, so a wrong\ncolumn mapping upstream of both would be reproduced by both. That last link\nis held by the SHA-256 in tests/fixtures/provenance.json and by\nscripts/verify_sources.py, not by this check.\n\nA figure with no recomputation at all is UNVERIFIED, not VERIFIED. A badge\nnobody earned is worse than no badge.","operationId":"get_metric_lineage_district__district_number__lineage__metric__get","parameters":[{"name":"district_number","in":"path","required":true,"schema":{"type":"string","title":"District Number"}},{"name":"metric","in":"path","required":true,"schema":{"type":"string","title":"Metric"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/lineage/texas/{metric}":{"get":{"tags":["Statewide"],"summary":"Get Statewide Lineage","description":"The working behind the statewide headline itself.\n\n\"Public schools spent $109.4 billion\" is the first number on the site, and\nfor a long time it was the only major one a reader could not open up. This\nreturns its evidence on the same contract as the district figures: the sum,\nwhich districts were summed and under what filter, the fiscal year, the\npublisher — and the verdict of the same publication gate, fed by an\nindependent longhand re-read of TEA's own CSV\n(scripts/recompute_spending.py, standard-library csv, nothing shared with\nthe builder).\n\nThe total is a SUM, not a division, so the gate reports arithmetic \"n/a\"\nfor it rather than inventing a denominator; the per-student companion\ndivides that sum by summed enrollment over the SAME districts and names\nthat denominator in full.","operationId":"get_statewide_lineage_lineage_texas__metric__get","parameters":[{"name":"metric","in":"path","required":true,"schema":{"type":"string","title":"Metric"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/district-geo":{"get":{"tags":["Districts"],"summary":"District Geo","description":"Simplified Texas school-district boundaries (Census TIGER/Line 2025, public\ndomain) joined to TEA district numbers, with the headline measures merged\nin. Charter districts are absent — they have no geographic boundary.","operationId":"district_geo_district_geo_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/fallback-index":{"get":{"tags":["General"],"summary":"Fallback Index","description":"The district picker and statewide figures, with no database involved.\n\nFourteen endpoints here are pure static JSON and survive a database outage\nuntouched. The front door did not: the page awaited /stats and /benchmarks\nbefore rendering, and the search box called /districts, so a paused\nSupabase free tier turned a working site into a blank one — including the\nsections that were still perfectly healthy.\n\nThe page falls back to this and keeps going, labelling the statewide\nfigures as a snapshot. Built by scripts/build_fallback_index.py.","operationId":"fallback_index_fallback_index_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/map-data":{"get":{"tags":["Districts"],"summary":"Similarity Map Data","description":"Precomputed 2D similarity-map coordinates (PCA of the exogenous\nfeature space; see scripts/graph_insights.py).","operationId":"similarity_map_data_map_data_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/sample-queries":{"get":{"tags":["NLP"],"summary":"Get Sample Queries","description":"Get sample natural language queries","operationId":"get_sample_queries_sample_queries_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/briefing":{"get":{"tags":["Intelligence"],"summary":"Get Briefing","description":"The most recent daily ISD intelligence briefing.\n\nReads from the isd_briefings table when a database is configured, and falls\nback to a committed snapshot (static/isd_briefing.json) so the page works\nwith no database at all — the same Tier-1 principle as the rest of the site.\n\nCarries an hour of shared cache: the front page's news strip reads this on\nevery visit, the content changes once a day via cron, and without the\nheader every front-page view was one database round trip. An hour of\npossible staleness on a daily product is the right trade. Same guard as\nthe cache middleware: a locked site must never prime a shared cache one\nauthorised reader could fill for everyone else.","operationId":"get_briefing_briefing_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/cron/runs":{"get":{"tags":["Intelligence"],"summary":"Get Cron Runs","description":"Has the scheduled work actually been running?\n\nA job that never fires and a job that fires and writes nothing look\nidentical from outside — which is how the daily intelligence run failed\nsilently for four days, with a briefing that simply stopped changing.\n\nThis reports the firings themselves, so **absence is visible**: `gap_days`\ncounts the days since the last successful run, and `wrote_nothing` counts\nruns that reported success while producing zero rows, which is the exact\nshape the original failure took. No request data, no identifiers — one row\nper firing and nothing else.","operationId":"get_cron_runs_api_cron_runs_get","parameters":[{"name":"job","in":"query","required":false,"schema":{"type":"string","default":"isd-intelligence","title":"Job"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":30,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/stats":{"get":{"tags":["General"],"summary":"Get Stats","description":"Get database statistics","operationId":"get_stats_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health":{"get":{"tags":["General"],"summary":"Health Check","description":"Health check endpoint.\n\nReports which language-model provider is actually live, so a provider\nswitch can be confirmed from outside without reading env vars. `llm` is a\nkey-free description (provider:model via host) — never the API key itself.","operationId":"health_check_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"NLPQueryRequest":{"properties":{"question":{"type":"string","maxLength":500,"minLength":3,"title":"Question","description":"Natural language question about Texas school finances"},"district_number":{"anyOf":[{"type":"string","maxLength":6},{"type":"null"}],"title":"District Number"},"conversation_id":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Conversation Id"},"turn":{"anyOf":[{"type":"integer","maximum":200.0,"minimum":1.0},{"type":"null"}],"title":"Turn"},"followup_label":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}],"title":"Followup Label"}},"type":"object","required":["question"],"title":"NLPQueryRequest"},"NLPQueryResponse":{"properties":{"success":{"type":"boolean","title":"Success"},"question":{"type":"string","title":"Question"},"answer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answer"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"structured":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Structured"},"timestamp":{"type":"string","format":"date-time","title":"Timestamp"}},"type":"object","required":["success","question"],"title":"NLPQueryResponse"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}