Home › Data

Teacher pension tax API

The figures behind every calculator on this site, served as typed JSON. All 50 states: how each treats pension income, its retirement system and benefit formula, what members contribute, what they earn on average, and whether they are covered by Social Security.

Base URL https://www.retirement-tax.com/data/v1

No key, no sign-up, no rate limit. Static JSON on a CDN, readable from the browser.

One record, read closely

Nevada is the record worth starting with, because it is the one a flat number gets wrong. Teachers there have nothing deducted from their pay — the employer contributes the full 36.75% instead, in exchange for a correspondingly lower base salary. A single employee_contribution: 36.75 would state the opposite of what happens.

Live response GET /data/v1/states/nevada.json
{
  "api_version": 1,
  "license": "https://creativecommons.org/licenses/by/4.0/",
  "attribution": "Teacher Retirement Tools — https://www.retirement-tax.com",
  "schema": "https://www.retirement-tax.com/data/v1/schema.json",
  "data_updated": "2026-07-28",
  "state": {
    "slug": "nevada",
    "name": "Nevada",
    "abbr": "NV",
    "pension_system": {
      "name": "Public Employees' Retirement System of Nevada",
      "acronym": "NVPERS"
    },
    "supplemental_account_type": "403(b)",
    "benefit_formula": "AMC × 2.5% × years (2.25% if enrolled on/after 7/1/2015; 2.67% for service after 7/1/2001)",
    "employee_contribution": {
      "rate_pct": {
        "min": 0.0,
        "max": 0.0
      },
      "employer_pays_pct": 36.75,
      "display": "0% deducted (employer pays 36.75%)"
    },
    "avg_teacher_salary_usd": 74812,
    "social_security": "not_covered",
    "state_income_tax": false,
    "pension_income_exempt": false,
    "pension_tax_rate_pct": 0.0,
    "pension_tax_condition": null
  }
}
employee_contribution.rate_pct

A range, not a figure. Six states are not a single percentage: New York and Washington tier or elect theirs, so min and max differ. Where a rate is fixed, both are equal.

employee_contribution.employer_pays_pct

Present only where the employer pays the member’s share outright. This field exists because Nevada needs it; in the other 49 states it is null.

pension_tax_condition

null means no condition is recorded — not that none exists. Where a value is present it names the cliff, age tier or credit inside the rate, which is the part a single number cannot show.

Endpoints

GET /data/v1

The service index: every endpoint below as an absolute URL, plus the licence and these docs. The base URL is what most people paste first, so it answers rather than 404s.

GET /data/v1/states.json

All 50 records in one response, with a metadata envelope. Around 60 KB — small enough to fetch once and filter client-side.

GET /data/v1/states/{slug}.json

One state. slug is the lower-case hyphenated state name, the same identifier used in this site’s page paths — nevada, new-york, rhode-island. An unknown slug returns 404 with a JSON body, not an HTML page.

GET /data/v1/schema.json

JSON Schema (draft 2020-12) for a state record. Generated from the same declaration that builds the records, so it cannot describe a field the API does not return.

GET /data/v1/openapi.json

OpenAPI 3.1. Import it into Postman, Bruno, or an SDK generator.

Try it

curl -s https://www.retirement-tax.com/data/v1/states.json \
  | jq '.states[] | select(.pension_income_exempt) | .name'

# states where teachers are not covered by Social Security
curl -s https://www.retirement-tax.com/data/v1/states.json \
  | jq -r '.states[] | select(.social_security=="not_covered") | .abbr'

Response fields

Every value is a JSON type a machine can use directly, or null. Nothing here is formatted for display — no currency symbols, no "Yes" where a boolean belongs.

FieldTypeMeaning
slugstringStable identifier and the key for /data/v1/states/{slug}.json.
namestringState name in full.
abbrstringUSPS two-letter abbreviation.
pension_systemobjectThe retirement system covering public-school teachers.
  • namestring | nullFull legal name.
  • acronymstring | nullCommon short form.
supplemental_account_typestring | nullTax-deferred account teachers in this state normally use alongside the pension.
benefit_formulastring | nullHow the annuity is calculated, as published by the plan. Prose, deliberately: multipliers and averaging periods differ by tier and hire date, and a single machine-readable formula would be wrong for most members of most states.
employee_contributionobject | nullWhat the member contributes. A range rather than a single figure because several states tier it by salary or let the member elect it.
  • rate_pctobject | nullPercent of salary deducted from the member. min == max where the rate is fixed. null where the published wording could not be read as a number.
  • employer_pays_pctnumber | nullPresent only where the employer pays the member's share outright. Nevada is the case this exists for: the deduction is 0% because the employer pays 36.75%, in exchange for a correspondingly lower base salary.
  • displaystringThe published wording, unmodified.
avg_teacher_salary_usdinteger | nullAverage public-school teacher salary, US dollars, whole units.
social_security"covered" | "not_covered" | "partial" | nullWhether teaching employment is covered by Social Security. 'partial' means coverage varies by district within the state.
state_income_taxboolean | nullWhether the state levies a personal income tax at all.
pension_income_exemptboolean | nullWhether pension income is fully exempt from that tax at the modelled income. Exemptions that phase out with income are false here and explained in pension_tax_condition.
pension_tax_rate_pctnumber | nullEFFECTIVE state income-tax rate on an $80,000 teacher pension, single filer, age 65, after the state's standard retirement exclusion. This is NOT the top marginal rate, and comparing it against a published marginal-rate table will disagree for most states by construction.
pension_tax_conditionstring | nullThe allowance, cliff or credit inside pension_tax_rate_pct, where one applies. null means no condition is recorded, not that none exists.

Stability and versioning

Additive within a version
Inside v1, fields are only ever added. Nothing is removed, renamed, or changes type. Write your parser to ignore fields it does not recognise and it will keep working.
Breaking changes ship as a new path
A change that would break a v1 consumer becomes /data/v2/. Both serve side by side.
Twelve months of overlap
A superseded version keeps serving for at least 12 months, carrying Deprecation and Sunset response headers (RFC 9745, RFC 8594) for the whole period.
Freshness you can poll
data_updated and revision change only when a figure changes — not when the site is redeployed. Responses carry an ETag; send If-None-Match and expect 304.

Bulk downloads

For a spreadsheet or a one-off analysis, the flat files are easier than the API. They stay published and are not going away.

JSON
teacher-pension-tax-by-state.json
50 rows · display-formatted
CSV
teacher-pension-tax-by-state.csv
50 rows · opens in Excel or Sheets

In Google Sheets: =IMPORTDATA("https://www.retirement-tax.com/data/teacher-pension-tax-by-state.csv"). Prefer the API for anything a program reads — the flat files keep their display formatting for people.

Want the rates on your own page instead? One script tag, no request back to us at load time: see the embed widget →

Licence: CC BY 4.0. Use it anywhere, including commercially. The one condition is attribution — credit “TRS Calculator” with a link back to https://www.retirement-tax.com.

What the tax rate means

pension_tax_rate_pct is not a state’s top marginal rate. It is the effective rate on an $80,000 teacher pension — single filer, age 65, after the state’s standard retirement exclusion. A state whose top bracket reads 13.3% does not tax that pension at 13.3%, and comparing top marginal rates across states — which many published tables do — systematically overstates the difference between them.

Exemptions are handled first: where a state exempts public pension income outright, the rate is zero regardless of its income tax. Full derivation is on the Methodology page.

How it is maintained

Limits — read before citing

Found something wrong? Tell us — corrections with a primary source get applied fast, and a dataset people correct is worth more than one nobody reads.