{
  "name": "Far Better Off API",
  "version": "v1",
  "description": "Free US personal-finance math as JSON. No API key, no signup, no rate-limit tier, no tracking of your inputs. The same @calcwise/finance functions that power farbetteroff.com, so the API and the site can never disagree.",
  "documentation": "https://farbetteroff.com/api",
  "openapi": "https://farbetteroff.com/api/v1/openapi.json",
  "index": "https://farbetteroff.com/api/v1",
  "website": "https://farbetteroff.com",
  "license": "MIT",
  "usage": {
    "methods": "GET with a query string, or POST with a JSON object body.",
    "cors": "Open to every origin. No cookies, no credentials, nothing to leak.",
    "caching": "Responses are pure functions of their inputs and are served with a long Cache-Control. Cache them freely.",
    "rateLimit": "60 requests per 60 seconds per IP, best effort. Cached responses do not count.",
    "errors": "Non-2xx responses are {\"error\": {\"code\", \"message\", ...}}. Validation failures list every bad parameter at once in \"issues\". A misspelling corrects itself there, in the same two keys a wrong slug uses: \"didYouMean\" names the spelling you probably meant, and where several are equally close \"candidates\" names them all rather than choosing. That works at both levels — a name that is not a parameter, and a value that is not one an enum accepts, so status=marrried reads as \"married\" and state=Ohioo as \"OH\" — so guess rather than reading the whole table. \"docs\" is the failing endpoint's own section at farbetteroff.com/api#<slug>, not this index.",
    "datasets": "The \"datasets\" list below is not the endpoint list. An endpoint is a pure function of its query string — same URL, same answer, forever. A dataset takes no parameters at all and publishes figures Far Better Off derives from dated public series or transcribes from the documents that set them, so the same URL returns a different number when the body behind it publishes; its Cache-Control says how long each answer is good for, and its \"asOf\" is the date the figure last changed rather than the date it was served. Both live under this version prefix, and a misspelled slug of either kind is corrected by the same 404.",
    "wrongSlug": "A slug that is not in this list is answered with a 404 that corrects it: \"didYouMean\" names the endpoint you probably meant — a case difference, a near miss, or the calculator page slug it answers for, so /api/v1/mortgage-calculator points at \"mortgage\" — and where two endpoints answer for one page, \"candidates\" names both rather than guessing between them. Guess a slug rather than giving up; the error will tell you the right one, and \"available\" always carries the full list.",
    "percentages": "Every percentage here is a whole number: send rate=6.5 for 6.5%, never 0.065. A percent parameter given a value under 1 is taken at face value — 0.065 means 0.065% — and the response carries a \"warnings\" entry saying so, with \"didYouMean\" holding the value you probably meant. The answer is still a real answer to what you sent; the warning is how you find out you sent the wrong one. Absent when there is nothing to say, so checking for the key is the whole check.",
    "rounding": "Money is rounded to cents. Rates and percentages carry more precision where it matters.",
    "dataVintage": "Most answers here are arithmetic and never go out of date. The ones that carry a figure a government body set or measured for a named year say so: each such endpoint lists its edition ids in \"dataVintage\" below, resolved in the \"dataVintages\" table at the end of this document, and repeats the full block in \"meta.dataVintage\" of its own responses. Each carries \"supersededFrom\", the date a newer edition is reliably out — compare it against your clock, because responses are cacheable and so cannot carry a live verdict on their own freshness."
  },
  "disclaimer": "Educational estimates, not financial advice. Figures sourced from a regulator cite that regulator in the endpoint's notes.",
  "endpoints": [
    {
      "slug": "pay",
      "title": "Pay, converted",
      "summary": "One wage restated in every period: per hour, per day, per week, every two weeks, twice a month, per month and per year — in either direction.",
      "url": "https://farbetteroff.com/api/v1/pay",
      "example": "https://farbetteroff.com/api/v1/pay?amount=25&per=hour",
      "calculator": "https://farbetteroff.com/calculators/salary-to-hourly-calculator",
      "params": [
        {
          "name": "amount",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 0,
          "max": 1000000000,
          "description": "The pay figure you have.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        },
        {
          "name": "per",
          "type": "enum",
          "required": true,
          "values": [
            "hour",
            "day",
            "week",
            "biweek",
            "semimonth",
            "month",
            "year"
          ],
          "description": "The period that amount is for. `biweek` is every two weeks (26 paychecks a year), `semimonth` twice a month (24).",
          "accepts": "one of hour, day, week, biweek, semimonth, month, year"
        },
        {
          "name": "hoursPerWeek",
          "type": "number",
          "unit": "count",
          "required": false,
          "default": 40,
          "min": 0.5,
          "max": 168,
          "description": "Hours worked in a week.",
          "accepts": "number, a count, between 0.5 and 168"
        },
        {
          "name": "weeksPerYear",
          "type": "number",
          "unit": "count",
          "required": false,
          "default": 52,
          "min": 1,
          "max": 52,
          "description": "Weeks **paid** in a year. Drop it for unpaid time off: two weeks off is 50.",
          "accepts": "number, a count, between 1 and 52"
        },
        {
          "name": "daysPerWeek",
          "type": "number",
          "unit": "count",
          "required": false,
          "default": 5,
          "min": 1,
          "max": 7,
          "description": "Days worked in a week, which is what the daily figure divides by.",
          "accepts": "number, a count, between 1 and 7"
        },
        {
          "name": "overtimeAfterHours",
          "type": "number",
          "unit": "count",
          "required": false,
          "default": 40,
          "min": 1,
          "max": 168,
          "description": "Hours in the week after which the premium starts. 40 is the federal floor; a contract or a state rule can start it sooner.",
          "accepts": "number, a count, between 1 and 168"
        },
        {
          "name": "overtimeMultiplier",
          "type": "number",
          "required": false,
          "default": 1.5,
          "min": 1,
          "max": 3,
          "description": "What an hour past the threshold pays, as a multiple of the base rate. Send `1` for a schedule with no premium — a salaried exempt job — and every figure is straight time again.",
          "accepts": "number, between 1 and 3"
        }
      ],
      "returns": {
        "hourly": "Pay for one hour worked, averaged over the week: above the threshold this is higher than `baseHourly`, because some of those hours pay the premium.",
        "daily": "Pay for one worked day.",
        "weekly": "Pay for one paid week.",
        "biweekly": "One paycheck when payroll runs every two weeks (26 a year).",
        "semiMonthly": "One paycheck when payroll runs twice a month (24 a year).",
        "monthly": "One month's pay — a twelfth of the year, not four weeks.",
        "annual": "The yearly total.",
        "hoursPerYear": "Paid hours in the year the hourly figure divides by.",
        "baseHourly": "The straight-time rate behind the answer — what one of the first `overtimeAfterHours` hours pays. Sent an hourly `amount`, it is that amount; sent a salary, it is what an hourly job would have to pay to reach it once the premium is counted, which is less than the average hour.",
        "overtimeHours": "Hours a week above the threshold. Zero on a schedule that never reaches it.",
        "overtimeRate": "What an hour past the threshold pays: `baseHourly × overtimeMultiplier`. Quoted even on a week that never reaches it, because it is what the next hour would earn.",
        "overtimePremiumAnnual": "What the premium alone adds over the year, against the same hours at straight time. Zero when there is no premium."
      },
      "notes": [
        "Gross pay, before tax and deductions. /api/v1/paycheck takes federal income tax and FICA out of the annual figure; /api/v1/state-tax adds state wage tax where Far Better Off models it.",
        "Hourly, daily and weekly follow the schedule you pass, because a real schedule changes them: 40 hours a week for 52 weeks by default, a 2,080-hour year.",
        "Hours past 40 carry the overtime premium, because a paycheck does: 29 U.S.C. § 207(a)(1) requires at least one and a half times the regular rate past 40 hours in a workweek, so `amount=25&per=hour&hoursPerWeek=50` is **$71,500** a year — 40 × $25 plus 10 × $37.50 — and not the $65,000 straight-lining gives. That is the default because the salary ↔ hourly calculator and the /pay pages have answered it that way since 2026-09-12, and one wage cannot have two answers. Send `overtimeMultiplier=1` for an exempt salaried schedule that earns no premium.",
        "Sent a salary rather than an hourly rate, the yearly total is whatever you sent — a salary is already the whole year — and the premium changes what it is worth by the hour instead: `hourly` is the average across every hour, `baseHourly` is what an hourly job would have to pay for the first 40. A $60,000 salary at 50 hours a week averages $23.08 an hour but only needs a **$20.98** base rate to match, because ten of those hours pay 1.5×.",
        "This is the federal floor and nothing else. California, Alaska and a handful of other states add a daily overtime rule on top of the weekly one, and a contract can start the premium sooner — `overtimeAfterHours` is there for both. Whether a particular job is exempt from the premium at all is a question about the job, not about the arithmetic, and this endpoint does not answer it.",
        "Monthly, semi-monthly and biweekly are fixed payroll counts — 12, 24 and 26 pay periods — so they do not move when the schedule does.",
        "26 biweekly periods is the convention, not the calendar: 52 weeks is exactly 26 fortnights, but a 365-day year is 26.07, so some years contain 27 biweekly paychecks.",
        "Federal pay conversion divides an annual rate by 2,087 hours rather than 2,080 (5 U.S.C. § 5504(b), which averages the leap-year cycle in), so a federal annual rate converted here reads about 0.34% high."
      ]
    },
    {
      "slug": "paycheck",
      "title": "Take-home pay (federal)",
      "summary": "Federal income tax bracket by bracket, Social Security, Medicare and what is left of a salary — per year, per month and per paycheck.",
      "url": "https://farbetteroff.com/api/v1/paycheck",
      "example": "https://farbetteroff.com/api/v1/paycheck?salary=75000&status=single&contribPercent=5&payPeriods=26",
      "calculator": "https://farbetteroff.com/calculators/take-home-paycheck-calculator",
      "params": [
        {
          "name": "salary",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 0,
          "max": 1000000000,
          "description": "Gross annual salary.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        },
        {
          "name": "status",
          "type": "enum",
          "required": false,
          "default": "single",
          "values": [
            "single",
            "married",
            "hoh",
            "mfs"
          ],
          "description": "Filing status: single, married (filing jointly), hoh (head of household) or mfs (married filing separately).",
          "accepts": "one of single, married, hoh, mfs"
        },
        {
          "name": "contribPercent",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 100,
          "description": "401(k)/403(b) contribution as a percent of salary. See contribType for which side of the tax line it falls on.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "contribType",
          "type": "enum",
          "required": false,
          "default": "traditional",
          "values": [
            "traditional",
            "roth"
          ],
          "description": "traditional: an elective deferral, exempt from income tax but not from FICA. roth: a designated Roth contribution, which the IRS includes in gross income when it is earned, so it reduces no tax base at all and only takeHome moves.",
          "accepts": "one of traditional, roth"
        },
        {
          "name": "catchUp",
          "type": "enum",
          "required": false,
          "default": "none",
          "values": [
            "none",
            "age50",
            "age60to63"
          ],
          "description": "Which catch-up raises the § 402(g) deferral cap, by the age reached during the year: none caps the contribution at $24,500, age50 at $32,500, age60to63 at $35,750 (IRS Notice 2025-67). contribPercent is capped at whichever applies, so contribution can be less than the percent asked for — see contributionLimited.",
          "accepts": "one of none, age50, age60to63"
        },
        {
          "name": "payPeriods",
          "type": "integer",
          "unit": "count",
          "required": false,
          "default": 26,
          "min": 1,
          "max": 365,
          "description": "Paychecks per year: 52 weekly, 26 every two weeks, 24 twice a month, 12 monthly.",
          "accepts": "integer, a count, between 1 and 365"
        }
      ],
      "returns": {
        "takeHome": "Annual pay after federal tax, Social Security, Medicare and the contribution. No state tax.",
        "perPaycheck": "takeHome divided by payPeriods.",
        "perMonth": "takeHome divided by 12.",
        "taxableIncome": "salary minus pretaxContribution minus the standard deduction, floored at 0. A Roth contribution is not subtracted.",
        "standardDeduction": "The 2026 standard deduction for the filing status.",
        "contribution": "Dollars contributed over the year, of either type, after the annual limit. Never more than deferralLimit.",
        "requestedContribution": "What contribPercent asked for, before the limit: salary times the percent. Equal to contribution unless contributionLimited.",
        "deferralLimit": "The § 402(g) cap applied for catchUp: 24500, 32500 or 35750 for 2026. An employer match is outside it.",
        "contributionLimited": "Whether the percent asked for more than deferralLimit allows.",
        "contributionType": "traditional or roth, echoed back.",
        "pretaxContribution": "The part of contribution that reduced taxable income: all of it for traditional, 0 for roth. This is the figure to subtract from a state or local wage base.",
        "federalIncomeTax": "Federal income tax on taxableIncome.",
        "socialSecurity": "6.2% of wages up to the wage base.",
        "medicare": "1.45% of all wages.",
        "additionalMedicare": "0.9% of wages above $200,000. Usually 0.",
        "fica": "socialSecurity + medicare + additionalMedicare.",
        "totalTax": "federalIncomeTax + fica. Federal only.",
        "effectiveTaxRatePercent": "totalTax as a percent of gross salary.",
        "marginalRatePercent": "The top bracket the income reaches. Not the same as the effective rate.",
        "brackets": "Each bracket the income reached: rate, band, the income inside it and the tax on it.",
        "taxYear": "The tax year the brackets and deduction come from.",
        "socialSecurityWageBase": "Wages above this pay no Social Security tax.",
        "additionalMedicareThreshold": "Wages above this pay the extra 0.9% Medicare tax."
      },
      "notes": [
        "Federal only. No state or local income tax is included, so in 41 states and D.C. real take-home pay is lower than takeHome. /api/v1/state-tax answers the state line where that is a fact rather than a guess: 0 in the 9 states that tax no wages, a computed figure in the 16 with one statutory rate and in California, New Jersey, New York and Virginia, whose published bracket schedules are modelled, and null in the other 22, whose brackets Far Better Off has not verified and will not approximate. Income tax is not the whole of it either: 10 states withhold a disability or paid-leave contribution from the same wages, which the same endpoint answers in \"payrollContributions\" — so takeHome is high by $975 a year for a Californian on $75,000 before a cent of state income tax is counted, and high in Washington, which levies no income tax at all.",
        "2026 figures: brackets and standard deduction from IRS Rev. Proc. 2025-32; Social Security wage base $184,500 and the FICA rates from IRS Topic no. 751; the $24,500 elective-deferral limit and its $8,000 and $11,250 catch-ups from IRS Notice 2025-67.",
        "contribPercent is capped at the § 402(g) limit, so a percent that would exceed it returns the contribution a plan could actually take and flags contributionLimited. Traditional and Roth deferrals share the one limit; an employer match is outside it and is not modelled here.",
        "This is the employee half of FICA. It is not self-employment tax, and it does not model W-4 allowances, pre-tax health or HSA premiums, credits, or income other than wages."
      ],
      "dataVintage": [
        "irs-inflation-adjustments",
        "social-security-wage-base",
        "irs-retirement-limits"
      ]
    },
    {
      "slug": "state-tax",
      "title": "State income tax on wages",
      "summary": "What a state takes out of a salary, for the 29 jurisdictions where that is a verified fact rather than a guess — 9 that tax no wages at all, 16 that charge one statutory rate, and California, New Jersey, New York and Virginia on their own published bracket schedules. For the other 22 it answers null and says why.",
      "url": "https://farbetteroff.com/api/v1/state-tax",
      "example": "https://farbetteroff.com/api/v1/state-tax?state=OH&wages=75000&pretaxRetirement=3750&locality=oh-columbus&schoolDistrict=2514",
      "calculator": "https://farbetteroff.com/calculators/take-home-paycheck-calculator",
      "params": [
        {
          "name": "state",
          "type": "enum",
          "required": true,
          "values": [
            "AL",
            "AK",
            "AZ",
            "AR",
            "CA",
            "CO",
            "CT",
            "DE",
            "DC",
            "FL",
            "GA",
            "HI",
            "ID",
            "IL",
            "IN",
            "IA",
            "KS",
            "KY",
            "LA",
            "ME",
            "MD",
            "MA",
            "MI",
            "MN",
            "MS",
            "MO",
            "MT",
            "NE",
            "NV",
            "NH",
            "NJ",
            "NM",
            "NY",
            "NC",
            "ND",
            "OH",
            "OK",
            "OR",
            "PA",
            "RI",
            "SC",
            "SD",
            "TN",
            "TX",
            "UT",
            "VT",
            "VA",
            "WA",
            "WV",
            "WI",
            "WY"
          ],
          "description": "USPS two-letter code, or the full state name (\"Ohio\", \"District of Columbia\"). Where the bare name is taken, the spelling people actually write answers too — \"Washington DC\", \"Washington, D.C.\" and \"D.C.\" for the District, \"Washington State\" and \"New York State\" for the two states whose names those places open. Either case; the code is echoed back.",
          "accepts": "one of AL, AK, AZ, AR, CA, CO, CT, DE, DC, FL, GA, HI, ID, IL, IN, IA, KS, KY, LA, ME, MD, MA, MI, MN, MS, MO, MT, NE, NV, NH, NJ, NM, NY, NC, ND, OH, OK, OR, PA, RI, SC, SD, TN, TX, UT, VT, VA, WA, WV, WI, WY"
        },
        {
          "name": "wages",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 0,
          "max": 1000000000,
          "description": "Gross annual wages.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        },
        {
          "name": "pretaxRetirement",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000000,
          "description": "Traditional 401(k)/403(b) dollars contributed over the year. Subtracted from the taxed wages everywhere except Pennsylvania, which taxes elective deferrals.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        },
        {
          "name": "filingStatus",
          "type": "enum",
          "required": false,
          "default": "single",
          "values": [
            "single",
            "married",
            "hoh",
            "mfs"
          ],
          "description": "How this person files, which decides the state's standard deduction where we model one (Georgia exempts $15,000 single and $30,000 married filing jointly). Ignored in states whose deduction is not modelled.",
          "accepts": "one of single, married, hoh, mfs"
        },
        {
          "name": "locality",
          "type": "enum",
          "required": false,
          "values": [
            "oh-cincinnati",
            "oh-cleveland",
            "oh-columbus",
            "pa-philadelphia",
            "pa-philadelphia-nonresident",
            "mi-detroit",
            "ny-new-york-city",
            "in-marion",
            "in-allen",
            "in-lake",
            "in-hamilton",
            "in-st-joseph",
            "in-vanderburgh",
            "in-tippecanoe",
            "in-monroe",
            "ky-louisville",
            "ky-louisville-nonresident",
            "ky-lexington",
            "ky-lexington-nonresident",
            "mi-detroit-nonresident",
            "mi-grand-rapids",
            "mi-grand-rapids-nonresident",
            "mi-lansing",
            "mi-lansing-nonresident",
            "mi-flint",
            "mi-flint-nonresident",
            "mi-pontiac",
            "mi-pontiac-nonresident",
            "mi-east-lansing",
            "mi-east-lansing-nonresident",
            "mi-battle-creek",
            "mi-battle-creek-nonresident",
            "mi-saginaw",
            "mi-saginaw-nonresident",
            "mi-highland-park",
            "mi-highland-park-nonresident",
            "mi-muskegon",
            "mi-muskegon-nonresident",
            "mi-big-rapids",
            "mi-big-rapids-nonresident",
            "mi-walker",
            "mi-walker-nonresident",
            "mi-hamtramck",
            "mi-hamtramck-nonresident",
            "mi-muskegon-heights",
            "mi-muskegon-heights-nonresident",
            "mi-portland",
            "mi-portland-nonresident",
            "mi-benton-harbor",
            "mi-benton-harbor-nonresident",
            "mi-albion",
            "mi-albion-nonresident",
            "mi-ionia",
            "mi-ionia-nonresident",
            "mi-lapeer",
            "mi-lapeer-nonresident",
            "mi-springfield",
            "mi-springfield-nonresident",
            "pa-pittsburgh",
            "pa-pittsburgh-nonresident",
            "pa-allentown",
            "pa-allentown-nonresident",
            "pa-reading",
            "pa-reading-nonresident",
            "pa-erie",
            "pa-erie-nonresident",
            "pa-scranton",
            "pa-scranton-nonresident",
            "pa-bethlehem",
            "pa-bethlehem-nonresident",
            "pa-lancaster",
            "pa-lancaster-nonresident",
            "pa-harrisburg",
            "pa-harrisburg-nonresident",
            "pa-altoona",
            "pa-altoona-nonresident",
            "pa-york",
            "pa-york-nonresident",
            "pa-wilkes-barre",
            "pa-wilkes-barre-nonresident",
            "pa-state-college",
            "pa-state-college-nonresident",
            "pa-norristown",
            "pa-norristown-nonresident",
            "pa-west-chester",
            "pa-west-chester-nonresident",
            "pa-cheltenham",
            "pa-cheltenham-nonresident",
            "pa-upper-darby",
            "pa-bensalem",
            "pa-abington",
            "pa-millcreek",
            "pa-bristol-township",
            "pa-ross-township",
            "pa-mount-lebanon",
            "oh-toledo",
            "oh-akron",
            "oh-dayton",
            "oh-canton",
            "oh-springfield",
            "oh-kettering",
            "oh-parma",
            "oh-lorain",
            "oh-hamilton",
            "oh-euclid",
            "oh-cuyahoga-falls",
            "oh-middletown",
            "oh-mansfield",
            "oh-lakewood",
            "mo-st-louis",
            "ky-bowling-green"
          ],
          "description": "A local wage tax — a city, county, township or borough — to add on top of the state line, where Far Better Off models one. Omit it and every \"local\" field comes back null, which means not asked rather than none — read \"localitiesAvailable\" for what this state offers. The locality must sit in \"state\"; a mismatch is a 400 rather than a silent swap.",
          "accepts": "one of oh-cincinnati, oh-cleveland, oh-columbus, pa-philadelphia, pa-philadelphia-nonresident, mi-detroit, ny-new-york-city, in-marion, in-allen, in-lake, in-hamilton, in-st-joseph, in-vanderburgh, in-tippecanoe, in-monroe, ky-louisville, ky-louisville-nonresident, ky-lexington, ky-lexington-nonresident, mi-detroit-nonresident, mi-grand-rapids, mi-grand-rapids-nonresident, mi-lansing, mi-lansing-nonresident, mi-flint, mi-flint-nonresident, mi-pontiac, mi-pontiac-nonresident, mi-east-lansing, mi-east-lansing-nonresident, mi-battle-creek, mi-battle-creek-nonresident, mi-saginaw, mi-saginaw-nonresident, mi-highland-park, mi-highland-park-nonresident, mi-muskegon, mi-muskegon-nonresident, mi-big-rapids, mi-big-rapids-nonresident, mi-walker, mi-walker-nonresident, mi-hamtramck, mi-hamtramck-nonresident, mi-muskegon-heights, mi-muskegon-heights-nonresident, mi-portland, mi-portland-nonresident, mi-benton-harbor, mi-benton-harbor-nonresident, mi-albion, mi-albion-nonresident, mi-ionia, mi-ionia-nonresident, mi-lapeer, mi-lapeer-nonresident, mi-springfield, mi-springfield-nonresident, pa-pittsburgh, pa-pittsburgh-nonresident, pa-allentown, pa-allentown-nonresident, pa-reading, pa-reading-nonresident, pa-erie, pa-erie-nonresident, pa-scranton, pa-scranton-nonresident, pa-bethlehem, pa-bethlehem-nonresident, pa-lancaster, pa-lancaster-nonresident, pa-harrisburg, pa-harrisburg-nonresident, pa-altoona, pa-altoona-nonresident, pa-york, pa-york-nonresident, pa-wilkes-barre, pa-wilkes-barre-nonresident, pa-state-college, pa-state-college-nonresident, pa-norristown, pa-norristown-nonresident, pa-west-chester, pa-west-chester-nonresident, pa-cheltenham, pa-cheltenham-nonresident, pa-upper-darby, pa-bensalem, pa-abington, pa-millcreek, pa-bristol-township, pa-ross-township, pa-mount-lebanon, oh-toledo, oh-akron, oh-dayton, oh-canton, oh-springfield, oh-kettering, oh-parma, oh-lorain, oh-hamilton, oh-euclid, oh-cuyahoga-falls, oh-middletown, oh-mansfield, oh-lakewood, mo-st-louis, ky-bowling-green"
        },
        {
          "name": "schoolDistrict",
          "type": "enum",
          "required": false,
          "values": [
            "oh-sd-2301-amanda-clearcreek",
            "oh-sd-0502-athens",
            "oh-sd-2801-berkshire",
            "oh-sd-2302-berne-union",
            "oh-sd-5501-bethel",
            "oh-sd-1401-blanchester",
            "oh-sd-7502-botkins",
            "oh-sd-5901-cardington-lincoln",
            "oh-sd-5401-celina",
            "oh-sd-8501-chippewa",
            "oh-sd-6501-circleville",
            "oh-sd-7001-clear-fork-valley",
            "oh-sd-1402-clinton-massie",
            "oh-sd-5204-cloverleaf",
            "oh-sd-7201-clyde-green-springs",
            "oh-sd-1704-crestline",
            "oh-sd-8702-eastwood",
            "oh-sd-5101-elgin",
            "oh-sd-3204-findlay",
            "oh-sd-0404-geneva-area",
            "oh-sd-7203-gibsonburg",
            "oh-sd-8503-green",
            "oh-sd-3603-greenfield",
            "oh-sd-0302-hillsdale",
            "oh-sd-7403-hopewell-loudon",
            "oh-sd-7506-jackson-center",
            "oh-sd-6704-james-a-garfield",
            "oh-sd-4901-jefferson",
            "oh-sd-4902-jonathan-alder",
            "oh-sd-8303-kings",
            "oh-sd-2305-lancaster",
            "oh-sd-6502-logan-elm",
            "oh-sd-4904-madison-plains",
            "oh-sd-5403-marion",
            "oh-sd-5504-miami-east",
            "oh-sd-5505-milton-union",
            "oh-sd-3902-monroeville",
            "oh-sd-8605-montpelier",
            "oh-sd-8705-north-baltimore",
            "oh-sd-4508-north-fork",
            "oh-sd-1203-northeastern",
            "oh-sd-4509-northridge",
            "oh-sd-7612-northwest",
            "oh-sd-1204-northwestern",
            "oh-sd-8706-northwood",
            "oh-sd-7711-norton",
            "oh-sd-8504-norwayne",
            "oh-sd-5103-pleasant",
            "oh-sd-5104-ridgedale",
            "oh-sd-5105-river-valley",
            "oh-sd-4604-riverside",
            "oh-sd-0908-ross",
            "oh-sd-5008-sebring",
            "oh-sd-7508-sidney",
            "oh-sd-3118-southwest",
            "oh-sd-0604-st-marys",
            "oh-sd-6503-teays-valley",
            "oh-sd-7407-tiffin",
            "oh-sd-6806-tri-county-north",
            "oh-sd-0505-trimble",
            "oh-sd-8509-triway",
            "oh-sd-5509-troy",
            "oh-sd-2308-walnut-township",
            "oh-sd-2402-washington-court-house",
            "oh-sd-2607-wauseon",
            "oh-sd-2514-westerville",
            "oh-sd-3907-willard",
            "oh-sd-7107-zane-trace",
            "oh-sd-3301-ada",
            "oh-sd-7501-anna",
            "oh-sd-1901-ansonia",
            "oh-sd-6301-antwerp",
            "oh-sd-3201-arcadia",
            "oh-sd-1902-arcanum-butler",
            "oh-sd-3202-arlington",
            "oh-sd-2001-ayersville",
            "oh-sd-3901-bellevue",
            "oh-sd-2501-bexley",
            "oh-sd-2101-big-walnut",
            "oh-sd-2303-bloom-carroll",
            "oh-sd-0203-bluffton",
            "oh-sd-8701-bowling-green",
            "oh-sd-5502-bradford",
            "oh-sd-8601-bryan",
            "oh-sd-1701-buckeye-central",
            "oh-sd-2102-buckeye-valley",
            "oh-sd-2502-canal-winchester",
            "oh-sd-8801-carey",
            "oh-sd-8301-carlisle",
            "oh-sd-2902-cedar-cliff",
            "oh-sd-4201-centerburg",
            "oh-sd-2002-central",
            "oh-sd-1303-clermont-northeastern",
            "oh-sd-5402-coldwater",
            "oh-sd-1703-colonel-crawford",
            "oh-sd-1502-columbiana",
            "oh-sd-6901-columbus-grove",
            "oh-sd-6902-continental",
            "oh-sd-3203-cory-rawson",
            "oh-sd-5503-covington",
            "oh-sd-1503-crestview",
            "oh-sd-8101-crestview",
            "oh-sd-8502-dalton",
            "oh-sd-4202-danville",
            "oh-sd-2003-defiance",
            "oh-sd-0204-delphos",
            "oh-sd-6803-eaton",
            "oh-sd-8602-edgerton",
            "oh-sd-8703-elmwood",
            "oh-sd-2602-evergreen",
            "oh-sd-8001-fairbanks",
            "oh-sd-2903-fairborn",
            "oh-sd-2304-fairfield-union",
            "oh-sd-7503-fairlawn",
            "oh-sd-2603-fayette",
            "oh-sd-7504-fort-loramie",
            "oh-sd-5406-fort-recovery",
            "oh-sd-1903-franklin-monroe",
            "oh-sd-7202-fremont",
            "oh-sd-1305-goshen",
            "oh-sd-4501-granville",
            "oh-sd-2904-greeneview",
            "oh-sd-1904-greenville",
            "oh-sd-3302-hardin-northern",
            "oh-sd-7505-hardin-houston",
            "oh-sd-2004-hicksville",
            "oh-sd-5902-highland",
            "oh-sd-3604-hillsboro",
            "oh-sd-3501-holgate",
            "oh-sd-6903-jennings",
            "oh-sd-4503-johnstown-monroe",
            "oh-sd-6904-kalida",
            "oh-sd-3303-kenton",
            "oh-sd-7204-lakota",
            "oh-sd-6905-leipsic",
            "oh-sd-3502-liberty-center",
            "oh-sd-2306-liberty-union-thurston",
            "oh-sd-3205-liberty-benton",
            "oh-sd-4506-licking-valley",
            "oh-sd-4903-london",
            "oh-sd-0303-loudonville-perrysville",
            "oh-sd-0905-madison",
            "oh-sd-3206-mccomb",
            "oh-sd-1102-mechanicsburg",
            "oh-sd-8604-millcreek-west-unity",
            "oh-sd-6906-miller-city-new-cleveland",
            "oh-sd-0601-minster",
            "oh-sd-1905-mississinawa-valley",
            "oh-sd-8802-mohawk",
            "oh-sd-5903-mount-gilead",
            "oh-sd-6802-national-trail",
            "oh-sd-0602-new-bremen",
            "oh-sd-0603-new-knoxville",
            "oh-sd-5708-new-lebanon",
            "oh-sd-3903-new-london",
            "oh-sd-0907-new-miami",
            "oh-sd-7404-new-riegel",
            "oh-sd-4507-newark",
            "oh-sd-5506-newton",
            "oh-sd-8003-north-union",
            "oh-sd-5904-northmor",
            "oh-sd-8505-northwestern",
            "oh-sd-3904-norwalk",
            "oh-sd-4712-oberlin",
            "oh-sd-7405-old-fort",
            "oh-sd-8707-otsego",
            "oh-sd-6907-ottawa-glandorf",
            "oh-sd-6908-ottoville",
            "oh-sd-6909-pandora-gilboa",
            "oh-sd-5405-parkway",
            "oh-sd-3504-patrick-henry",
            "oh-sd-6302-paulding",
            "oh-sd-8708-perrysburg",
            "oh-sd-2604-pettisville",
            "oh-sd-2307-pickerington",
            "oh-sd-2605-pike-delta-york",
            "oh-sd-5507-piqua",
            "oh-sd-7007-plymouth-shiloh",
            "oh-sd-6804-preble-shawnee",
            "oh-sd-2509-reynoldsburg",
            "oh-sd-3304-ridgemont",
            "oh-sd-3305-riverdale",
            "oh-sd-7507-russia",
            "oh-sd-7406-seneca-east",
            "oh-sd-7008-shelby",
            "oh-sd-3905-south-central",
            "oh-sd-1205-southeastern",
            "oh-sd-4510-southwest-licking",
            "oh-sd-0209-spencerville",
            "oh-sd-5010-springfield",
            "oh-sd-8607-stryker",
            "oh-sd-2606-swanton",
            "oh-sd-0909-talawanda",
            "oh-sd-1906-tri-village",
            "oh-sd-1103-triad",
            "oh-sd-6805-twin-valley-community",
            "oh-sd-7106-union-scioto",
            "oh-sd-1510-united",
            "oh-sd-8803-upper-sandusky",
            "oh-sd-3306-upper-scioto-valley",
            "oh-sd-5713-valley-view",
            "oh-sd-3207-van-buren",
            "oh-sd-8104-van-wert",
            "oh-sd-3208-vanlue",
            "oh-sd-1907-versailles",
            "oh-sd-0605-wapakoneta",
            "oh-sd-6303-wayne-trace",
            "oh-sd-0606-waynesfield-goshen",
            "oh-sd-4715-wellington",
            "oh-sd-1105-west-liberty-salem",
            "oh-sd-3906-western-reserve",
            "oh-sd-3122-wyoming",
            "oh-sd-2906-xenia-community",
            "oh-sd-2907-yellow-springs"
          ],
          "description": "Ohio's school district income tax, which is a second local levy on the same paycheck and the only one here charged by where you **live** rather than where you work — so it is owed on top of \"locality\" and not instead of it. All 214 districts that levy one for 2026 are accepted, by id or by the four-digit code from box 20 of your W-2 (\"2301\"), which is the only reliable way to match one: a district's boundaries are not a city's, a township's or a ZIP code's, so a bare name is deliberately not a spelling. Omit it and every \"schoolDistrict\" field comes back null, which means not asked rather than none — read \"schoolDistrictsAvailable\" for what this state offers. The district must sit in \"state\"; a mismatch is a 400 rather than a silent swap.",
          "accepts": "one of 214 Ohio school district ids (oh-sd-2301-amanda-clearcreek), or the four-digit district code from box 20 of your W-2 (2301) — the list is in \"schoolDistrictsAvailable\" on any answer for state=OH"
        },
        {
          "name": "localExemptions",
          "type": "number",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 20,
          "description": "Personal and dependency exemptions to claim against the locality's tax, as a head count — the filer, a spouse, each dependent. Only Michigan's 40 rates allow any of the localities modelled ($600 a head in Detroit, Grand Rapids, Lansing, Flint, Pontiac, East Lansing, Highland Park, Muskegon, Big Rapids, Walker, Hamtramck, Muskegon Heights, Albion and Lapeer, and $700 a head in Ionia, and $750 a head in Battle Creek, Saginaw, Benton Harbor and Springfield, and $1000 a head in Portland, read back in \"localExemptionAmount\"); elsewhere it changes nothing. The default of 0 is the larger bill, so an omitted count never understates a city.",
          "accepts": "number, between 0 and 20"
        }
      ],
      "returns": {
        "state": "The USPS code the answer is for.",
        "stateName": "The state's full name.",
        "taxability": "Which of four cases this state is: \"none\" (taxes no wages), \"flat\" (one verified statutory rate), \"graduated\" (a verified bracket schedule, applied in full — \"ratePercent\" is null because no single rate describes it) or \"unmodeled\" (brackets Far Better Off has not verified, where there is no answer).",
        "modeled": "True when tax is a number. False only where taxability is \"unmodeled\".",
        "tax": "State income tax on the year's wages, or null where taxability is \"unmodeled\". Null is not zero.",
        "taxedWages": "The wages a rate was applied to: wages minus pretaxRetirement (the whole salary in Pennsylvania), minus standardDeduction where one is modelled, minus ficaDeduction in Massachusetts. 0 where the state taxes no wages at all, null where there is no answer.",
        "standardDeduction": "What this state exempts for this filingStatus before its rate applies, where we have verified it. Null usually means not verified, never verified as zero — but in Pennsylvania it means none exists, and in Utah it means the state grants none and hands the federal deduction back as a credit instead (see \"credit\"). It is what these wages actually got, not a table row: Illinois disallows its exemption allowance outright over $250,000 ($500,000 filing jointly), so a filer above the limit gets 0 with the label still set.",
        "standardDeductionLabel": "What the state calls it: \"standard deduction\", or \"personal exemption and standard deduction\" in Mississippi, which gives both. Null where none is modelled.",
        "standardDeductionSource": "Where the deduction figures were verified, when that isn't the same page as the rate (North Carolina's are in the statute, Kentucky's in a DOR announcement). Null otherwise.",
        "ficaDeduction": "What this state takes off for the Social Security and Medicare tax already paid on these wages — Massachusetts's, and null in every other state, where the answer is that no such deduction exists rather than that nobody checked. M.G.L. c. 62, § 3(B)(a)(3) caps it at $2,000 \"attributable to any one taxpayer\", so every salary over $26,144 gets exactly $2,000 and a smaller one gets the 7.65% it actually paid. It follows the payroll tax rather than the income tax, so pretaxRetirement does not reduce it, and filingStatus does not double it: the second $2,000 belongs to a second earner, whose pay this endpoint was not given. taxedWages already has it subtracted.",
        "ficaDeductionLabel": "What the state calls it, or null. Massachusetts: \"deduction for the Social Security and Medicare tax you paid\".",
        "ficaDeductionSource": "Where that cap and what it is taken of were verified. Null in every state that has no such deduction.",
        "filingStatus": "The filing status the answer used. Echoed so a cached response is self-describing.",
        "effectiveRatePercent": "tax as a percent of gross wages. Lower than ratePercent wherever there is an exempt band.",
        "ratePercent": "The statutory rate on wage income, or null — null in a graduated state too, where the answer is a table rather than a rate. Read \"rateLabel\" for how the state states it, and \"effectiveRatePercent\" for what these wages actually paid.",
        "marginalRatePercent": "The rate this filer's next dollar of wages meets, as a percent — the number that answers \"what does a raise cost me here\", which effectiveRatePercent and ratePercent both get wrong. 0 in a state that taxes no wages and 0 under a filing threshold or inside an exempt band, the statutory rate in a flat state, the band this income reaches in a graduated one, and null only where taxability is \"unmodeled\". It can be **higher** than ratePercent: Massachusetts adds its 4-point surtax above the threshold, and Utah's tapering credit costs another 1.3 cents a dollar while it lasts, so a Utahn inside that taper meets 5.8% and not the 4.5% the state advertises. Clamping this to the statutory rate would be wrong in both states.",
        "marginalBracket": "The band marginalRatePercent came from, as { over, ratePercent }, in a state that publishes a schedule. Null in a flat state (ratePercent is the whole answer), in a state that taxes no wages, and under a filing threshold, where no band applies because no tax does.",
        "brackets": "This state's own schedule for this filingStatus, as [{ over, ratePercent }] from the first dollar — the table \"tax\" was worked out from, so a caller can reproduce or display it without a second source. Null in a flat state and where the state taxes no wages. The bands are measured on taxable income: taxedWages less exemptBelow, not on gross wages. A schedule alone does not always reproduce \"tax\" — read \"supplementalTax\" in New York, \"baseTax\" in Ohio and \"credit\" in Utah.",
        "stateAndLocalMarginalRatePercent": "marginalRatePercent plus localMarginalRatePercent: what one more dollar of wages really costs in sub-federal income tax. Null wherever either half is null — an unmodeled state, or no locality asked for — for the same reason stateAndLocalTax is. The two add honestly because every locality modelled taxes a base that a dollar of wages enters: gross pay in Ohio's cities and Philadelphia, federal AGI in Detroit, and state taxable income in New York City and Indiana's counties.",
        "exemptBelow": "The slab this state taxes at nothing before its rate starts, after any standardDeduction (Ohio, Mississippi, Idaho). For this filingStatus: Idaho's is $4,811 on a single return and $9,622 on a joint one. Null elsewhere.",
        "noTaxBelow": "The filing threshold this state charges nothing at all under, for this filingStatus — Virginia's $11,950 ($23,900 filing jointly) and New Jersey's $10,000 ($20,000 jointly or as head of household). Null in every other state. Unlike exemptBelow this is measured on income before any standardDeduction, and clearing it does not subtract it: a dollar over, the whole schedule applies from the bottom.",
        "belowFilingThreshold": "Whether these taxedWages fall under noTaxBelow, so the state charges nothing. The two states disagree about the boundary itself and this answers for each: Virginia's statute says \"less than $11,950\", so $11,950 exactly is taxed, while New Jersey's says \"$10,000 or less ... pay no tax\", so $10,000 exactly is not. False in a state with no threshold, null where the state is unmodeled.",
        "baseTax": "Flat dollars owed once the exempt band is cleared (Ohio's $332). Null elsewhere.",
        "surtaxPercent": "Extra percentage points a state charges above a threshold, on top of ratePercent (Massachusetts: 4). Null in every other state.",
        "surtaxThreshold": "The taxable income above which surtaxPercent applies. Massachusetts indexes it annually and does not vary it by filing status, so a couple filing jointly reaches it at the same income a single filer does. Null elsewhere.",
        "surtax": "How much of tax came from that top band for these wages — 0 below the threshold, and null in a state that has no surtax. tax already includes it; this is here so ratePercent times taxedWages and our number agree.",
        "surtaxSource": "Where the surtax rate and its threshold were verified. Null where there is no surtax.",
        "supplementalTax": "How much of tax came from a state taking back the benefit of its own lower brackets — New York's supplemental tax, and nothing else here. 0 below the income where it starts, and null in a state that has no such rule. tax already includes it; this is here so a consumer applying the bracket schedule and our number agree.",
        "supplementalTaxLabel": "How the state describes that rule, or null. New York: \"New York's supplemental tax, which takes back the lower brackets above $107,650\".",
        "supplementalTaxSource": "Where those steps were verified. Null where the state has no such rule.",
        "credit": "A credit this state takes off the tax itself, for these wages — Utah's taxpayer tax credit, and nothing else here. It is 6% of the federal standard deduction, less 1.3% of income above a base amount, so it falls to 0 around $92,500 of single income. tax already has it subtracted and is floored at zero, so a low earner's credit can be larger than the tax it wiped out. Null in every other state.",
        "creditLabel": "What the state calls it, or null. Utah: \"taxpayer tax credit\".",
        "creditSource": "Where the credit's percentages and base amounts were verified. Null elsewhere.",
        "taxesPretaxRetirement": "True where 401(k) contributions are taxed as compensation anyway (Pennsylvania).",
        "rateLabel": "How the state describes its own rate, in a phrase you can print.",
        "excludes": "What this figure leaves out in this state — deductions, exemptions, credits, local taxes. Always read it.",
        "reason": "Present only where taxability is \"unmodeled\": why there is no number.",
        "source": "Where this state's figure was verified: { publisher, url, verified?, quote? } on the agency's, legislature's or code's own site. \"verified\" is an ISO day that citation was last re-opened and found to still say this, and it is absent rather than null where nobody has re-read it — which is not a doubtful rate, only an unrepeated reading. \"quote\" is the sentence on that page the day was earned on, so you can repeat the check instead of trusting it: fetch the url, strip tags to single spaces, fold curly punctuation to ASCII, and the string is still there. It is absent with no \"verified\" day, and absent on the two citations that are PDFs, where no substring search can repeat a person's reading. Null only where a rate is confirmed but not yet linked.",
        "taxYear": "The tax year the rates come from.",
        "localitiesAvailable": "Every local wage tax Far Better Off models in this state, whether a city, county, township or borough levies it, as { id, name, ratePercent, topRatePercent } — the accepted values of \"locality\" here, so a client can build the picker without a second call. \"ratePercent\" is null for a locality that publishes a schedule instead of a rate (New York City's four resident brackets), and \"topRatePercent\" is its highest rate, so a picker always has one number to show. Empty is \"none modelled\", never \"none exists\": Indiana's other 84 counties, many Kentucky and Michigan cities and much of Pennsylvania levy one that is not in this table yet, and \"excludes\" says so.",
        "locality": "The locality id the answer used, or null when none was asked for.",
        "localityName": "What that locality is called (\"Philadelphia (I live in the city)\"). Null when none was asked for.",
        "localTax": "Local income tax — city, county, township or borough — on the same year of wages, or null when no locality was asked for. Null is not zero, exactly as it is for the state line.",
        "localRatePercent": "The locality's rate on wage income, as a percent. Null when none was asked for, and null in New York City, which publishes a schedule rather than a rate — read \"localBrackets\" and \"localMarginalRatePercent\" there.",
        "localMarginalRatePercent": "The rate on the next dollar of local tax, as a percent — the locality's flat rate everywhere but New York City, and the bracket this filer's city taxable income lands in there. Null when no locality was asked for.",
        "localBrackets": "The locality's own schedule for this filing status, as [{ over, ratePercent }] from the first dollar, where it publishes one — New York City only. Null everywhere else, where there is a single \"localRatePercent\" instead.",
        "localTaxableIncome": "What the locality's rate or schedule was applied to, where that is not gross pay: New York City charges its brackets on New York State taxable income and an Indiana county charges its rate on Indiana's, so this is the state's standard deduction or personal exemption already taken off. Null for every locality that taxes gross pay (read \"localTax\" and \"localRatePercent\" there) and when none was asked for.",
        "localTaxLabel": "How the locality states its own charge, in a phrase you can print (\"Philadelphia's 3.735% resident Wage Tax\"). Null when none was asked for.",
        "localTaxesPretaxRetirement": "True where the locality taxes 401(k) elective deferrals as compensation anyway — true in Ohio's cities, which tax box 5 Medicare wages, and in Philadelphia, which follows the Pennsylvania rule. False in Michigan's 40, whose base is a federal figure the contribution was never in — the AGI on a Detroit resident's return, W-2 box 1 in every other Michigan city here and on a Detroit commuter's. Null when no locality was asked for.",
        "localExemptionAmount": "Dollars a year this locality exempts for each personal or dependency exemption, resident and non-resident alike — $600 a head in Detroit, Grand Rapids, Lansing, Flint, Pontiac, East Lansing, Highland Park, Muskegon, Big Rapids, Walker, Hamtramck, Muskegon Heights, Albion and Lapeer, and $700 a head in Ionia, and $750 a head in Battle Creek, Saginaw, Benton Harbor and Springfield, and $1000 a head in Portland. Each is the figure that city prints on its own return rather than one the state sets: the Uniform City Income Tax Ordinance caps the rate and says nothing about the exemption, which is why Battle Creek's is the largest of them. Null where the locality allows none, which is every locality outside Michigan, and null when no locality was asked for. Null here is \"the city taxes the first dollar\", not \"unverified\".",
        "localExemptionsApplied": "The exemption count actually used, which is 0 wherever the locality allows none however many you asked for. Null when no locality was asked for.",
        "localExcludes": "What the local figure leaves out — a second Ohio municipality's tax net of credit, Philadelphia's income-based refund. Always read it. Null when no locality was asked for.",
        "localSource": "Where the locality's rate was verified: { publisher, url } on the city's own revenue page. Null when no locality was asked for.",
        "schoolDistrictsAvailable": "Every school district income tax Far Better Off models in this state, as { id, code, name, ratePercent, base } — the accepted values of \"schoolDistrict\", so a client can build the second picker without a second call. \"code\" is the four-digit number box 20 of a W-2 carries, which is the field to match a reader against; \"base\" is \"wages\" or \"state taxable income\", and both appear in Ohio, which is why one rate is two bills. Empty in 50 of the 51 jurisdictions, and that is \"none modelled\", never \"none exists\": Pennsylvania's school districts levy an earned income tax of their own, which rides inside the Act 32 rates in \"localitiesAvailable\" rather than as rows here.",
        "schoolDistrict": "The school district id the answer used, or null when none was asked for.",
        "schoolDistrictName": "What that district is called, with its four-digit code (\"Westerville City School District (2512)\"). Null when none was asked for.",
        "schoolDistrictCode": "The four-digit code alone, so a client can show it against box 20 of the reader's own W-2 without parsing the name. Null when no district was asked for.",
        "schoolDistrictTax": "Ohio school district income tax on the same year of wages, or null when no district was asked for. Null is not zero, exactly as it is for the state and local lines. It is charged on where the reader lives, so it is owed **on top of** localTax, which is charged on where they work — a Westerville resident working in Columbus owes both.",
        "schoolDistrictRatePercent": "The district's rate on its own base, as a percent. Every district modelled charges one flat rate — none publishes a schedule — so unlike localRatePercent this is never null for a district that was asked for.",
        "schoolDistrictBase": "Which of the two bases Ohio Revised Code 5748.01(E) lets a district choose this one is on: \"wages\" for the earned income base, division (E)(2), which is wages with no deduction and no exemption, or \"state taxable income\" for the traditional base, division (E)(1), which is Form SD 100 line 5 — modified adjusted gross income less the Ohio IT 1040 exemption. It is the field that explains why one rate is two bills: 1% is $750 on the earned income base and $729 on the traditional one for a single filer on $75,000, and $708 filing jointly, because the traditional base takes two of Ohio's exemptions and the earned income base has no filing status at all. Null when no district was asked for.",
        "schoolDistrictTaxableIncome": "What the district's rate was applied to, where that is not gross pay — the Ohio taxable income a traditional-base district charges. Ohio's $26,050 zero band and its $332 of flat dollars are **not** in it: they belong to the state's own schedule, which is why $28,400 of wages can owe Ohio nothing and owe a 1% district $260.50. Null for an earned income district, where the answer is \"wages\", and null when none was asked for.",
        "schoolDistrictTaxLabel": "How the district states its own charge, in a phrase you can print (\"Westerville City School District's 0.75% income tax\"). Null when none was asked for.",
        "schoolDistrictTaxesPretaxRetirement": "False for every district modelled, and it is the one local line in Ohio where that is true: a municipal tax here reaches \"qualifying wages\" — box 5 Medicare wages, which an elective deferral is still inside — while both school district bases are built on federal adjusted gross income, which it was never in. So on one Ohio payslip a 5% deferral leaves Columbus at $1,875 and takes Westerville from $562.50 to $534.38. Null when no district was asked for.",
        "schoolDistrictExcludes": "What the district figure leaves out — self-employment earnings on the earned income base, every non-wage dollar of modified adjusted gross income on the traditional one, Ohio's dependency exemptions, and the SD 100's $50 senior citizen credit. Always read it. Null when none was asked for.",
        "schoolDistrictSource": "Where the district's rate and its base were verified: { publisher, url } on the Ohio Department of Taxation's own employer-withholding list. Null when none was asked for.",
        "schoolDistrictTaxYear": "The year the district rates are in force for. Ohio's list is dated by the day employers must use it — 1 January — rather than by a tax year, so it is stated separately from taxYear above. Null when no district was asked for.",
        "stateAndLocalTax": "Every sub-federal income tax line on this salary added up: \"tax\" plus \"localTax\" plus \"schoolDistrictTax\", which is the number a person here actually loses. Null wherever any half asked for is null — an unmodeled state, or no locality and no district asked for — because a sum missing a term is not a total. A term nobody asked for is not missing: with \"locality\" alone this is tax plus localTax, as it always was, and the district only enters it when a district was named.",
        "payrollContributions": "What this state withholds from the employee's own wages for a named state programme in a year — disability insurance, paid family and medical leave, and in New Jersey unemployment insurance too. It is not income tax, so no rate above can show it, and it is often the larger deduction: California's SDI takes 1.3% of every dollar earned, $975 a year on $75,000, where the state income tax on the same salary is under 4%. Charged on gross wages, so pretaxRetirement does not reduce it — a 401(k) deferral escapes the income tax and not this. Null where Far Better Off has verified no such contribution, which is not zero: Delaware's Paid Leave and Maryland's FAMLI both belong here and neither rate has been read off its agency's page yet.",
        "payrollContributionLabel": "The line a pay stub shows, in a phrase you can print (\"California SDI\", \"Washington PFML + WA Cares\"). Null where none is modelled.",
        "payrollContributionDescription": "The same thing in running text, for a sentence rather than a table cell (\"State Disability Insurance\"). Null where none is modelled.",
        "payrollContributionRatePercent": "Every programme's employee rate added up, as a percent. Read it with \"payrollContributionPrograms\": the sum describes a salary under the lowest wage base and no other, because New Jersey's four rates stop at two different ceilings — Unemployment Insurance and workforce development at $44,800 — so above that the real charge is less than this figure states. Null where none is modelled.",
        "payrollContributionMarginalRatePercent": "The rate the next dollar of wages meets in contributions, as a percent — the figure to add to marginalRatePercent when answering what a raise costs. It is 0 once every wage base is passed (a Rhode Islander over $100,000 pays no more Temporary Disability Insurance however big the raise), the whole rate below the lowest base, and in between it is neither: a New Jerseyan over $44,800 meets 0.42% of the 0.845% the rate above sums, because Unemployment Insurance has stopped charging and disability and family leave have not. Null where none is modelled.",
        "payrollContributionPrograms": "The programmes behind the total, in the order a pay stub lists them, as [{ name, short, ratePercent, wageBase, chargedWages, amount }]. \"wageBase\" is null where the programme charges every dollar — California removed SDI's ceiling on 1 January 2024 and WA Cares never had one — and \"chargedWages\" is what the rate actually met, so a base that has bitten is visible rather than inferred. Null where none is modelled.",
        "payrollContributionYear": "The calendar year these rates are in force for. They turn over on 1 January, unlike the income tax rates above, which are stated for a tax year. Null where none is modelled.",
        "payrollContributionExcludes": "What the contribution figure leaves out or assumes, in the state's own terms — an employer that volunteers to pay more of your share, a private plan that withholds instead, a WA Cares exemption, a rate already legislated to move next January. Always read it. Null where none is modelled.",
        "payrollContributionSource": "Where each rate and wage base was verified: { publisher, url } on the labor or paid-leave agency's own page. Null where none is modelled.",
        "stateTaxAndContributions": "Everything the state itself takes out of this salary: \"tax\" plus \"payrollContributions\". Null wherever either half is null — an unmodeled state, or one with no verified contribution — for the same reason \"stateAndLocalTax\" is null without a locality: a sum missing a term is not a total. It excludes any locality; add \"localTax\" for the whole sub-federal bill."
      },
      "notes": [
        "Wage income only, and 29 of the 51 jurisdictions get a number: 9 that levy no individual income tax on wages, 16 that charge one statutory rate (3 of those after a zero band), and California, New Jersey, New York and Virginia, whose own published bracket schedule is applied in full. For the other 22, \"tax\" is null and \"taxability\" is \"unmodeled\". Far Better Off will not guess at a bracket table it has not read off the state's own forms — so treat null as \"no answer\", never as zero.",
        "Where a state's own standard deduction has been verified it is applied, by filingStatus, and returned in \"standardDeduction\" with its citation — Arizona, Colorado, Georgia, Idaho, Illinois, Indiana, Iowa, Kentucky, Louisiana, Massachusetts, Michigan, Mississippi, North Carolina and Ohio so far, and in Iowa and Idaho that deduction is the federal one, because both start from the federal figures rather than from your wages. In Illinois it stops above $250,000 ($500,000 filing jointly), and in Ohio it steps down at $40,000 and again at $80,000 of wages and stops above $500,000, as each state's own rule does — so \"standardDeduction\" is what this filer actually gets, not what the statute's headline figure says. Every other flat-rate state's own rule is settled too rather than left out: Pennsylvania grants none, and Utah gives the federal deduction back as a credit (\"credit\") instead. In the graduated states the figure still leaves out personal exemptions and credits, so those filers owe less. County and municipal income taxes are never included, so in Indiana, Kentucky, Michigan, Ohio and much of Pennsylvania the real total is higher. The per-state \"excludes\" field says which of those apply.",
        "Pennsylvania is the one state here that taxes 401(k) elective deferrals as compensation, so its 3.07% applies to the whole salary. Everywhere else the rate is applied to wages minus pretaxRetirement.",
        "Utah is the one state here that gives back a credit instead of a deduction, so \"standardDeduction\" is null there and \"ratePercent\" times \"taxedWages\" overstates the bill: 4.5% on every dollar, less a taxpayer tax credit of 6% of the federal standard deduction that shrinks by 1.3¢ for each dollar of income above $18,213 single, $36,426 filing jointly and $27,320 head of household (the 2025 schedule, indexed annually). Two things follow that a flat rate hides — a single Utahn owes nothing below about $20,700, and between there and about $92,500 each extra dollar really meets 5.8%, not 4.5%. The dollars are in \"credit\".",
        "Massachusetts is the one state here with a second rate at the top, so \"ratePercent\" alone does not reproduce \"tax\" there for a very high earner: 5% on wage income after the personal exemption, plus 4 points more on taxable income above $1,107,750 in 2026 (\"surtaxPercent\" and \"surtaxThreshold\", with the dollars in \"surtax\"). The threshold is indexed for inflation each year and is the same whatever your filing status. Below it Massachusetts is flat, and \"surtax\" comes back as 0.",
        "2026 rates, each cited to the state's own revenue department, constitution or code. The citation comes back in the \"source\" field of every answer, and the whole table is readable at /state-income-tax-rates. Michigan's rate, for instance, is re-determined each April and stayed at 4.25% for 2026.",
        "Local income tax is answered where it has been verified and nowhere else. Pass \"locality\" for one of the rates modelled — Cincinnati 1.8%, Cleveland 2.5%, Columbus 2.5%, Philadelphia 3.735%, Philadelphia 3.425% for a non-resident who works there, Detroit 2.4%, New York City 3.078%–3.876%, Indianapolis (Marion County) 2.02%, Fort Wayne (Allen County) 1.59%, Gary and Hammond (Lake County) 1.5%, Carmel and Fishers (Hamilton County) 1.1%, South Bend (St. Joseph County) 1.75%, Evansville (Vanderburgh County) 1.25%, Lafayette (Tippecanoe County) 1.28%, Bloomington (Monroe County) 2.14%, Louisville 2.2%, Louisville 1.45% for a non-resident who works there, Lexington 2.75%, Lexington 2.25% for a non-resident who works there, Detroit 1.2% for a non-resident who works there, Grand Rapids 1.5%, Grand Rapids 0.75% for a non-resident who works there, Lansing 1%, Lansing 0.5% for a non-resident who works there, Flint 1%, Flint 0.5% for a non-resident who works there, Pontiac 1%, Pontiac 0.5% for a non-resident who works there, East Lansing 1%, East Lansing 0.5% for a non-resident who works there, Battle Creek 1%, Battle Creek 0.5% for a non-resident who works there, Saginaw 1.5%, Saginaw 0.75% for a non-resident who works there, Highland Park 2%, Highland Park 1% for a non-resident who works there, Muskegon 1%, Muskegon 0.5% for a non-resident who works there, Big Rapids 1%, Big Rapids 0.5% for a non-resident who works there, Walker 1%, Walker 0.5% for a non-resident who works there, Hamtramck 1%, Hamtramck 0.5% for a non-resident who works there, Muskegon Heights 1%, Muskegon Heights 0.5% for a non-resident who works there, Portland 1%, Portland 0.5% for a non-resident who works there, Benton Harbor 1%, Benton Harbor 0.5% for a non-resident who works there, Albion 1%, Albion 0.5% for a non-resident who works there, Ionia 1%, Ionia 0.5% for a non-resident who works there, Lapeer 1%, Lapeer 0.5% for a non-resident who works there, Springfield 1%, Springfield 0.5% for a non-resident who works there, Pittsburgh 3%, Pittsburgh 1% for a non-resident who works there, Allentown 1.975%, Allentown 1.28% for a non-resident who works there, Reading 3.6%, Reading 1% for a non-resident who works there, Erie 1.65%, Erie 1.65% for a non-resident who works there, Scranton 3.4%, Scranton 1% for a non-resident who works there, Bethlehem 1%, Bethlehem 1% for a non-resident who works there, Lancaster 1.6%, Lancaster 1% for a non-resident who works there, Harrisburg 2%, Harrisburg 1% for a non-resident who works there, Altoona 1.7%, Altoona 1.4% for a non-resident who works there, York 1.25%, York 1.25% for a non-resident who works there, Wilkes-Barre 3%, Wilkes-Barre 1% for a non-resident who works there, State College Borough 2.25%, State College Borough 1% for a non-resident who works there, Norristown Borough 2.1%, Norristown Borough 1% for a non-resident who works there, West Chester Borough 1.25%, West Chester Borough 1% for a non-resident who works there, Cheltenham Township 1.5%, Cheltenham Township 1% for a non-resident who works there, Upper Darby Township 1%, Bensalem Township 1%, Abington Township 1%, Millcreek Township 1%, Bristol Township 0.5%, Ross Township 1%, Mount Lebanon Township 1.3%, Toledo 2.5%, Akron 2.5%, Dayton 2.5%, Canton 2.5%, Springfield 2.4%, Kettering 2.25%, Parma 2.5%, Lorain 2.5%, Hamilton 2%, Euclid 2.85%, Cuyahoga Falls 2%, Middletown 2%, Mansfield 2.25%, Lakewood 1.5%, St. Louis 1% and Bowling Green 2% — and the answer comes back in \"localTax\", with \"stateAndLocalTax\" for the two lines together. \"localitiesAvailable\" lists what each state offers. They do not share a base, and the answer says which one it used rather than leaving you to assume: Ohio's cities and Philadelphia charge their rate on gross pay with no deduction and no exemption, so a 401(k) contribution does not reduce them (\"localTaxesPretaxRetirement\" is true), while Michigan's cities charge theirs on a federal wage figure the contribution was never in — the AGI on a Detroit resident's return, W-2 box 1 in every other city there — and each allows an exemption of its own ($600 a head in Detroit, Grand Rapids, Lansing, Flint, Pontiac, East Lansing, Highland Park, Muskegon, Big Rapids, Walker, Hamtramck, Muskegon Heights, Albion and Lapeer, and $700 a head in Ionia, and $750 a head in Battle Creek, Saginaw, Benton Harbor and Springfield, and $1000 a head in Portland), so a contribution does reduce all 40 of those rates and \"localExemptions\" is worth passing. New York City is the third base and the only locality here with a schedule rather than a rate: four resident brackets from 3.078% to 3.876% charged on New York State taxable income, so \"localRatePercent\" is null there and \"localBrackets\", \"localMarginalRatePercent\" and \"localTaxableIncome\" are how the answer is reproduced — and \"status\" changes it, because the state's standard deduction and the city's brackets both follow the filing status. Indiana's counties are the fourth base and the first to reuse one: eight of them charge a single rate on the same Indiana taxable income the state taxes, so \"localRatePercent\" and \"localTaxableIncome\" are both filled in and a 401(k) reduces the county line too. St. Louis is the fifth base and the first in a state this API cannot compute: its 1% earnings tax reaches a published list of compensation items — salaries, wages, bonuses, commissions, tips and severance — with deferred compensation and cafeteria plans on the city's own non-taxable list, so a 401(k) reduces it, there is no deduction or exemption to pass, and Missouri's own schedule is not modelled, which is why \"tax\" is null there and \"stateAndLocalTax\" is null with it. What is still missing is missing for the same reason the rest took this long, and Kansas City is the clearest case of it: its Code of Ordinances imposes the same 1% on residents' earnings and on work done in the city, but the RD-109 instructions that would settle whether a 401(k) deferral is inside that figure are served by a host that refuses every automated read, so the rate is absent rather than copied off a page the city does not publish. It will not be guessed at.",
        "Ohio asks the local question twice, so this endpoint takes two local parameters and adds both. A municipal tax follows the **work** (\"locality\"); the school district income tax follows the **home** (\"schoolDistrict\"), and all 214 districts that levy one for 2026 are answered — so a Westerville resident working in Columbus owes Columbus's 2.5% on the work and Westerville City School District's 0.75% on the residence, and a request naming only one of them is short by the other. Name a district by its id or by the four-digit code on box 20 of the reader's own W-2, which is the only reliable way to match one: a district's boundaries are not a city's, so a bare name is deliberately not a spelling and \"schoolDistrictsAvailable\" carries the code beside every row. Ohio Revised Code 5748.01(E) lets a district choose one of two bases and they are not interchangeable, which is why \"schoolDistrictBase\" is in every answer: 68 charge their rate on wages with no deduction and no exemption, and 146 charge it on Ohio taxable income — Form SD 100 line 5, the state's personal exemption already off — so 1% of $75,000 is $750 in one and $729 in the other, and $708 filing jointly. Two things that follow surprise people: the state's $26,050 zero band and its $332 of flat dollars stay with the **state**, so $28,400 of wages owes Ohio nothing and owes a 1% district $260.50; and a 401(k) deferral reduces a district line and no Ohio city line, because both district bases are built on federal adjusted gross income and a municipal tax reaches box 5 Medicare wages.",
        "Two rates come back, and they answer different questions. \"effectiveRatePercent\" is what this year cost; \"marginalRatePercent\" is what the next dollar costs, with the band it came from in \"marginalBracket\" and the whole schedule in \"brackets\". Do not clamp the marginal rate to \"ratePercent\": it is legitimately higher in Massachusetts above the surtax threshold, and in Utah, where a tapering credit takes 1.3 cents of every dollar between about $20,700 and $92,500 of single income, so the real rate on a raise there is 5.8% against an advertised 4.5%. Where a locality is asked for, \"stateAndLocalMarginalRatePercent\" adds the two.",
        "Income tax is not the only thing a state takes out of a paycheck, and in 10 of them the second line is answered here too: \"payrollContributions\" is the disability, paid-leave and — in New Jersey alone — unemployment contribution withheld from the worker's own wages, with the programmes behind it in \"payrollContributionPrograms\" and the two lines added in \"stateTaxAndContributions\". It behaves like FICA and not like the tax above: charged on gross pay, so a 401(k) deferral does not reduce it, with a per-programme wage base rather than a deduction or a filing status. Washington's two contributions are the clearest case of why this cannot be folded into a rate — the state levies no income tax at all and still takes the most of any state here. Where nothing has been verified the field is null and not zero: Delaware's Paid Leave and Maryland's FAMLI belong in that table and are not in it yet, and New York's disability benefits contribution and Hawaii's TDI are left out because the law lets an employer pay them instead of setting the worker's share.",
        "This is the state line only unless you ask for a locality. For the federal side — brackets, FICA and take-home pay — call /api/v1/paycheck and subtract this number."
      ],
      "dataVintage": [
        "state-wage-tax-rates",
        "local-wage-tax-rates",
        "state-payroll-contribution-rates"
      ]
    },
    {
      "slug": "loan",
      "title": "Loan payment & amortization",
      "summary": "Monthly payment, total interest and the year-by-year schedule for any fixed-rate amortizing loan — mortgage, auto, student or personal.",
      "url": "https://farbetteroff.com/api/v1/loan",
      "example": "https://farbetteroff.com/api/v1/loan?principal=300000&rate=6.5&termMonths=360&extraMonthly=200",
      "calculator": "https://farbetteroff.com/calculators/personal-loan-calculator",
      "params": [
        {
          "name": "principal",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 0,
          "max": 100000000000,
          "description": "Amount borrowed.",
          "accepts": "number, US dollars, between 0 and 100000000000"
        },
        {
          "name": "rate",
          "type": "number",
          "unit": "percent",
          "required": true,
          "min": 0,
          "max": 100,
          "description": "Annual interest rate (APR).",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "termMonths",
          "type": "integer",
          "unit": "months",
          "required": true,
          "min": 1,
          "max": 1200,
          "description": "Length of the loan in months. A 30-year mortgage is 360.",
          "accepts": "integer, whole months, between 1 and 1200"
        },
        {
          "name": "extraMonthly",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000000,
          "description": "Extra principal paid on top of the scheduled payment each month.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        },
        {
          "name": "schedule",
          "type": "boolean",
          "required": false,
          "default": false,
          "description": "Include the year-by-year amortization schedule in the response.",
          "accepts": "boolean"
        }
      ],
      "returns": {
        "payment": "Scheduled monthly payment (principal and interest only).",
        "months": "Months until the loan is paid off, after any extra principal.",
        "termLabel": "That payoff time in words, e.g. \"24 yr 11 mo\".",
        "totalInterest": "Interest paid over the life of the loan.",
        "totalPaid": "Principal plus interest.",
        "extraPayment": "Present only when extraMonthly > 0: months and interest saved against the original schedule.",
        "schedule": "Present only when schedule=true: one row per year with principal paid, interest paid and closing balance."
      }
    },
    {
      "slug": "mortgage",
      "title": "Mortgage payment (PITI)",
      "summary": "The whole monthly payment on a home loan — principal, interest, property tax, insurance, HOA and PMI — not just principal and interest.",
      "url": "https://farbetteroff.com/api/v1/mortgage",
      "example": "https://farbetteroff.com/api/v1/mortgage?homePrice=400000&downPayment=80000&rate=6.5&termYears=30&propertyTaxAnnual=3600&insuranceAnnual=1800",
      "calculator": "https://farbetteroff.com/calculators/mortgage-calculator",
      "params": [
        {
          "name": "homePrice",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 0,
          "max": 10000000000,
          "description": "Purchase price.",
          "accepts": "number, US dollars, between 0 and 10000000000"
        },
        {
          "name": "downPayment",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 10000000000,
          "description": "Down payment in dollars.",
          "accepts": "number, US dollars, between 0 and 10000000000"
        },
        {
          "name": "rate",
          "type": "number",
          "unit": "percent",
          "required": true,
          "min": 0,
          "max": 100,
          "description": "Annual interest rate (APR).",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "termYears",
          "type": "integer",
          "unit": "years",
          "required": false,
          "default": 30,
          "min": 1,
          "max": 50,
          "description": "Loan term in years.",
          "accepts": "integer, years, between 1 and 50"
        },
        {
          "name": "propertyTaxAnnual",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 10000000,
          "description": "Property tax per year.",
          "accepts": "number, US dollars, between 0 and 10000000"
        },
        {
          "name": "insuranceAnnual",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 10000000,
          "description": "Homeowner's insurance per year.",
          "accepts": "number, US dollars, between 0 and 10000000"
        },
        {
          "name": "hoaMonthly",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000,
          "description": "HOA dues per month.",
          "accepts": "number, US dollars, between 0 and 1000000"
        },
        {
          "name": "pmiRate",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 0.5,
          "min": 0,
          "max": 5,
          "description": "Annual PMI premium as a percentage of the loan. Only charged below 20% down. Freddie Mac puts a typical premium at $30–$70 a month per $100,000 borrowed, which is 0.36%–0.84% of the loan a year.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 5"
        },
        {
          "name": "extraMonthly",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 10000000,
          "description": "Extra principal per month.",
          "accepts": "number, US dollars, between 0 and 10000000"
        }
      ],
      "returns": {
        "loanAmount": "Home price minus the down payment.",
        "downPaymentPercent": "Down payment as a percentage of the price.",
        "principalAndInterest": "The loan payment alone.",
        "monthlyTotal": "Everything due each month, including any extra principal.",
        "breakdown": "Each component of the monthly total, in dollars.",
        "totalInterest": "Interest over the life of the loan, after any extra principal.",
        "payoffMonths": "Months to payoff.",
        "payoffTermLabel": "That payoff time in words, e.g. \"30 yr\" or \"24 yr 11 mo\".",
        "pmi": "Null when no PMI is charged. Otherwise the month it drops off automatically, the earlier month you may request cancellation, and what it costs either way."
      },
      "notes": [
        "PMI termination follows the Homeowners Protection Act as summarised by the CFPB: automatic at 78% of the original value, or the amortization midpoint as a backstop; borrower-requested at 80%.",
        "Property tax and insurance are whatever you pass in — Far Better Off does not look up local rates."
      ]
    },
    {
      "slug": "house-affordability",
      "title": "How much house can I afford",
      "summary": "The highest home price whose whole payment fits inside a lender's two debt-to-income ratios — answered at the 28/36 convention and at both of FHA's manual-underwriting thresholds.",
      "url": "https://farbetteroff.com/api/v1/house-affordability",
      "example": "https://farbetteroff.com/api/v1/house-affordability?income=90000&monthlyDebts=500&downPayment=40000&rate=6.5",
      "calculator": "https://farbetteroff.com/calculators/how-much-house-can-i-afford",
      "params": [
        {
          "name": "income",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 1,
          "max": 100000000,
          "description": "Gross household income per year, before tax. Annual, not monthly — the ratios below are applied to a twelfth of it.",
          "accepts": "number, US dollars, between 1 and 100000000"
        },
        {
          "name": "monthlyDebts",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000,
          "description": "Required monthly payments on everything that is not housing — car, student loans, credit-card minimums, alimony and child support. Groceries, utilities and phone bills are not debt and do not belong here.",
          "accepts": "number, US dollars, between 0 and 1000000"
        },
        {
          "name": "downPayment",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 100000000,
          "description": "Cash going in. It raises the price you can reach and is not borrowed.",
          "accepts": "number, US dollars, between 0 and 100000000"
        },
        {
          "name": "rate",
          "type": "number",
          "unit": "percent",
          "required": true,
          "min": 0,
          "max": 100,
          "description": "Mortgage APR you expect to be offered.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "termYears",
          "type": "integer",
          "unit": "years",
          "required": false,
          "default": 30,
          "min": 1,
          "max": 50,
          "description": "Loan term in years.",
          "accepts": "integer, years, between 1 and 50"
        },
        {
          "name": "propertyTaxRatePct",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 0.89,
          "min": 0,
          "max": 10,
          "description": "Annual property tax as a percent of the home's price. Defaults to the US average effective rate; county rates run from about 0.3% to over 2%, so last year's bill divided by the price is the number to send.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 10"
        },
        {
          "name": "insuranceAnnual",
          "type": "number",
          "unit": "usd",
          "required": false,
          "min": 0,
          "max": 1000000,
          "description": "Your own annual homeowners premium, if you have a quote. Leave it out and the premium is read off the measured curve described in the notes, which re-prices at every home price the search tries.",
          "accepts": "number, US dollars, between 0 and 1000000"
        },
        {
          "name": "pmiRatePct",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 0.5,
          "min": 0,
          "max": 5,
          "description": "Annual PMI as a percent of the loan, charged only where the answer lands above 80% loan-to-value. Defaults to 0.5%, mid-range for the $30–$70 a month per $100,000 borrowed Freddie Mac describes. Send `pmiRatePct=0` for a payment with no mortgage insurance in it — the right call for a VA loan, or where you are solving the lender's PITI rather than what underwriting measures.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 5"
        }
      ],
      "returns": {
        "maxPrice": "The highest home price whose full payment fits both ratios, under the 28/36 rule.",
        "loanAmount": "What has to be borrowed at that price.",
        "downPaymentPercent": "The down payment as a percent of that price.",
        "incomeMultiple": "The price as a multiple of gross annual income — the figure the “3 to 4 times income” rule of thumb is about.",
        "monthlyBudget": "The housing budget that binds: the lower of the two below.",
        "frontEndBudget": "Housing alone, under the front-end ratio.",
        "backEndBudget": "What is left for housing under the back-end ratio, after the other debts.",
        "limitedBy": "\"income\" when the front-end ratio is the ceiling, \"debts\" when the other payments are — the one field that says what to do about the answer.",
        "principalAndInterest": "The mortgage payment itself at that price.",
        "monthlyTax": "Estimated property tax per month at that price.",
        "monthlyInsurance": "Estimated homeowners insurance per month at that price.",
        "monthlyPmi": "Mortgage insurance per month at that price, charged above 80% loan-to-value. 0 when `pmiApplies` is false or `pmiRatePct=0` was sent.",
        "totalMonthlyPayment": "Principal, interest, tax, insurance and mortgage insurance — the whole housing payment, which is the figure the ratios are measured against (Fannie Mae's PITIA).",
        "pmiApplies": "True when the down payment lands under 20% of the price, where a conventional loan adds the PMI that is charged in `monthlyPmi` and in the payment above.",
        "byBenchmark": "The same solve at each underwriting benchmark — the 28/36 convention and FHA's two manual-underwriting pairs — each with its ratios, its price, its payment and the authority behind it. Strictest first."
      },
      "notes": [
        "The price is found by bisection, not by a formula: property tax and the insurance premium both move with the price being tested, so the price appears on both sides of the constraint. Forty halvings of the range between the down payment and $5,000,000 settle it to well under a cent.",
        "The 28/36 pair is a lending convention with no regulation behind it. FHA's 31/43 is a real qualifying ratio for manually underwritten loans — above it the lender must justify in writing why the mortgage is an acceptable risk — and 37/47 needs a documented compensating factor and a decision credit score of 580 or better (HUD Handbook 4000.1 II.A.5.d).",
        "**PMI is in this payment, and it is inside the ratios rather than on top of them.** That is where underwriting puts it: Fannie Mae's monthly housing expense — the numerator of the debt-to-income ratio these benchmarks are about — is principal and interest plus \"property, flood, and mortgage insurance premiums (as applicable)\" (Selling Guide B3-6-03). So a loan above 80% LTV buys less house, not the same house plus a premium: on `income=90000&monthlyDebts=500&downPayment=40000&rate=6.5` the premium is about $107 a month and costs about $14,858 of price. `pmiApplies` says whether it was charged, `monthlyPmi` is the figure, `pmiRatePct=0` turns it off, and /api/v1/pmi dates its removal. HOA dues, ground rent and closing costs are still not in it, and FHA's mortgage insurance — charged at any down payment, often for the life of the loan — is not modelled.",
        "The default property tax rate is 0.89% — the national average effective rate, computed from the US Census Bureau's 2024 American Community Survey, https://data.census.gov/table/ACSDT5Y2024.B25103 — and it is an average across counties that range from about 0.3% to over 2%. Send your own `propertyTaxRatePct` if you know it; it moves the answer more than anything here except the rate.",
        "The default insurance premium is measured rather than assumed, and it is not a flat rate: read off the 2024 American Community Survey 1-year PUMS microdata, where the same household reports both its premium (INSP) and its property value (VALP), the premium rises as roughly the 0.31 power of the price — $1,930 a year at a $400,000 home, about $2,400 at $836,000. A premium is priced on what it costs to rebuild the house, and land cannot burn down. Source: https://www.census.gov/programs-surveys/acs/microdata.html",
        "This is what a lender would lend, which is not the same as what is comfortable to spend. The ratios say nothing about childcare, retirement saving or the cost of a roof.",
        "Same math as the calculator page: both call `houseAffordability` in @calcwise/finance, so this answer and https://farbetteroff.com/calculators/how-much-house-can-i-afford cannot disagree."
      ]
    },
    {
      "slug": "rent-affordability",
      "title": "How much rent can I afford",
      "summary": "The rent a household can carry on the 30% rule and on a lender's back-end ratio, plus where the answer falls on HUD's cost-burden scale — which counts utilities, and almost nothing else does.",
      "url": "https://farbetteroff.com/api/v1/rent-affordability",
      "example": "https://farbetteroff.com/api/v1/rent-affordability?income=60000&monthlyDebts=600&monthlyUtilities=180",
      "calculator": "https://farbetteroff.com/calculators/rent-affordability-calculator",
      "params": [
        {
          "name": "income",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 1,
          "max": 100000000,
          "description": "Gross household income per year, before tax. Annual, not monthly. Gross rather than take-home, because every rule here is written on gross — the landlord's 3x test included.",
          "accepts": "number, US dollars, between 1 and 100000000"
        },
        {
          "name": "monthlyDebts",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000,
          "description": "Required monthly payments on everything that is not housing — car, student loans, credit-card minimums, alimony and child support. Groceries, phone and utilities are not debt; utilities have their own parameter below.",
          "accepts": "number, US dollars, between 0 and 1000000"
        },
        {
          "name": "monthlyUtilities",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 100000,
          "description": "Electric, gas, water and trash you pay on top of the rent. HUD counts these inside housing cost, so they move `costBurdenRent` and `burdenAtMaxRent` — send them or those two answers are optimistic.",
          "accepts": "number, US dollars, between 0 and 100000"
        },
        {
          "name": "sharePct",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 30,
          "min": 1,
          "max": 100,
          "description": "Share of gross income to target for rent. Defaults to the 30% convention, which is a rule of thumb nobody set — see the notes.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 1 and 100"
        },
        {
          "name": "backEndPct",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 36,
          "min": 1,
          "max": 100,
          "description": "Back-end debt-to-income ratio used as the second ceiling on rent plus all other debt. Defaults to 36, the back-end half of the 28/36 lending convention. `byBenchmark` answers at every benchmark in the table regardless of what is sent here.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 1 and 100"
        },
        {
          "name": "dependents",
          "type": "integer",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 20,
          "description": "Number of dependents. Used only by `federalFormula`, where each one is a deduction under 24 CFR § 5.611(a)(1). It does not change `maxRent` — no budgeting rule of thumb accounts for household size.",
          "accepts": "integer, between 0 and 20"
        },
        {
          "name": "childcareAnnual",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000,
          "description": "Reasonable childcare per year needed to work or study. Deductible in full under 24 CFR § 5.611(a)(4), so it enters `federalFormula` only.",
          "accepts": "number, US dollars, between 0 and 1000000"
        },
        {
          "name": "elderlyOrDisabled",
          "type": "boolean",
          "required": false,
          "default": false,
          "description": "True for an elderly or disabled family, which unlocks the § 5.611(a)(2) deduction and the medical deduction below. `federalFormula` only.",
          "accepts": "boolean"
        },
        {
          "name": "medicalAnnual",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000,
          "description": "Unreimbursed health, medical and attendant-care costs per year. Deductible only for an elderly or disabled family, and only above 10 percent of annual income. `federalFormula` only.",
          "accepts": "number, US dollars, between 0 and 1000000"
        }
      ],
      "returns": {
        "maxRent": "The answer: the lower of the share rule and the back-end ratio, never negative.",
        "limitedBy": "\"share\" when the percent-of-income rule is the ceiling, \"debts\" when the other payments are — the field that says what to do about the answer.",
        "grossMonthlyIncome": "Gross annual income ÷ 12, which every ratio here divides by.",
        "shareOfIncome": "`sharePct` of gross monthly income — the rule as it is usually applied.",
        "debtAdjusted": "Rent the back-end ratio leaves room for once the other debts are paid, floored at zero.",
        "costBurdenRent": "The rent at which this household crosses HUD's cost-burden line — 30% of gross **less** the utility bill, because utilities sit inside HUD's numerator.",
        "severeCostBurdenRent": "The same at HUD's severe line, 50% of gross less utilities.",
        "burdenAtMaxRent": "\"not-burdened\", \"cost-burdened\" or \"severely-cost-burdened\" — where `maxRent` plus utilities falls under 24 CFR § 91.5.",
        "landlordMaxRent": "Gross monthly income ÷ 3 — the most rent a landlord applying the usual \"income must be at least 3x the rent\" screen would accept.",
        "leftOver": "Gross monthly income less rent, utilities and other debt.",
        "byBenchmark": "The rent left over at each real underwriting back-end ratio — the 28/36 convention's 36 and FHA's 43 and 47 — each with the authority behind it. Strictest first.",
        "federalFormula": "What 24 CFR § 5.628 would charge this household if it were assisted: 30% of monthly **adjusted** income or 10% of monthly gross, whichever is higher, with the § 5.611 deductions applied. A different answer to the same 30%.",
        "thresholds": "HUD's two cost-burden thresholds and what they measure, verbatim from 24 CFR § 91.5."
      },
      "notes": [
        "**The 30% rule is a convention, not a rule anyone set.** No agency caps what an unassisted renter may pay. The number is borrowed from federal housing policy, where it means two other things — the two paragraphs below — and this endpoint returns all three rather than picking one.",
        "**HUD's 30% counts utilities, and that is the correction most rent calculators need.** 24 CFR § 91.5 defines cost burden as the extent to which “gross housing costs, including utility costs, exceed 30 percent of gross income”, and severe cost burden as the same above 50 percent. A household paying exactly 30% of gross in rent is already cost burdened once the electric bill is counted, which is why `monthlyUtilities` exists and why `costBurdenRent` is the threshold **less** that bill. https://www.ecfr.gov/current/title-24/subtitle-A/part-91/section-91.5",
        "**The other federal 30% is of adjusted income, with a 10%-of-gross floor underneath it.** An assisted household's total tenant payment is the highest of “30 percent of the family's monthly adjusted income” and “10 percent of the family's monthly income” (24 CFR § 5.628(a)), among other amounts. Adjusted income is annual income less the deductions in § 5.611 — dependents, elderly or disabled status, medical costs above 10% of income, and childcare — so it is below gross for any household with children or care costs. Send `dependents`, `childcareAnnual`, `elderlyOrDisabled` and `medicalAnnual` and `federalFormula` computes it. https://www.ecfr.gov/current/title-24/subtitle-A/part-5/subpart-F/section-5.628",
        "**The § 5.611 deduction amounts are the regulation's figures, and HUD raises both every year.** $480 per dependent and $525 for an elderly or disabled family are what the CFR prints; each “will be adjusted by HUD annually in accordance with the Consumer Price Index for Urban Wage Earners and Clerical Workers, rounded to the next lowest multiple of $25”. This API does not claim a current-year adjusted amount, so those two are floors — which makes `federalFormula.totalTenantPayment` at or slightly **above** what a housing authority would charge, the safe direction to be wrong in for anyone planning a budget.",
        "The back-end ceiling is a mortgage ratio applied to rent, and it is labelled as one. 36 is the back-end half of the 28/36 convention; 43 and 47 are FHA's manual-underwriting thresholds, where above 31%/43% the lender must justify in writing why the loan is an acceptable risk and 37%/47% additionally needs a documented compensating factor and a decision credit score of 580 (HUD Handbook 4000.1 II.A.5.d). No regulator sets a back-end ratio for a lease.",
        "The 3x-income screen most landlords apply is the same arithmetic as a 33% share, so `landlordMaxRent` will sit slightly above the 30% answer. It is a screening rule private landlords choose, not law, and it varies by market.",
        "Security deposits, first and last month up front, renters insurance, parking and commuting are not in any of these numbers.",
        "Same math as the calculator page: both call `rentAffordability` in @calcwise/finance, so this answer and https://farbetteroff.com/calculators/rent-affordability-calculator cannot disagree."
      ]
    },
    {
      "slug": "car-affordability",
      "title": "How much car can I afford",
      "summary": "The car the 20/4/10 rule leaves room for, with insurance, fuel and upkeep taken out of the ten percent first — from the IRS's own operating allowance for the caller's part of the country, beside what the IRS allows for the payment itself.",
      "url": "https://farbetteroff.com/api/v1/car-affordability",
      "example": "https://farbetteroff.com/api/v1/car-affordability?takeHome=4200&downPayment=4000&rate=7.5&area=tx",
      "calculator": "https://farbetteroff.com/calculators/car-affordability-calculator",
      "params": [
        {
          "name": "takeHome",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 1,
          "max": 10000000,
          "description": "Monthly pay after tax. Take-home rather than gross, because the rule is written on take-home — sending gross overstates every answer here by roughly a quarter.",
          "accepts": "number, US dollars, between 1 and 10000000"
        },
        {
          "name": "downPayment",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 10000000,
          "description": "Down payment plus trade-in. It adds to the price directly and is what the rule's 20% leg is measured against.",
          "accepts": "number, US dollars, between 0 and 10000000"
        },
        {
          "name": "rate",
          "type": "number",
          "unit": "percent",
          "required": true,
          "min": 0,
          "max": 100,
          "description": "Annual percentage rate on the car loan.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "termMonths",
          "type": "integer",
          "unit": "months",
          "required": false,
          "default": 48,
          "min": 1,
          "max": 120,
          "description": "Loan term in months. Defaults to the rule's 48 — `byTerm` prices 36, 48, 60 and 72 at the same monthly payment regardless, which is the cheapest way to see what stretching costs.",
          "accepts": "integer, whole months, between 1 and 120"
        },
        {
          "name": "sharePct",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 10,
          "min": 1,
          "max": 100,
          "description": "Share of take-home pay for **all** car costs, payment and running costs together. Defaults to the rule's 10, which is a convention nobody set — see the notes.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 1 and 100"
        },
        {
          "name": "area",
          "type": "enum",
          "required": false,
          "values": [
            "northeast",
            "boston",
            "new-york",
            "philadelphia",
            "midwest",
            "chicago",
            "cleveland",
            "detroit",
            "minneapolis-st-paul",
            "st-louis",
            "south",
            "atlanta",
            "baltimore",
            "dallas-ft-worth",
            "houston",
            "miami",
            "tampa",
            "washington-dc",
            "west",
            "anchorage",
            "denver",
            "honolulu",
            "los-angeles",
            "phoenix",
            "san-diego",
            "san-francisco",
            "seattle"
          ],
          "description": "Where the car is run, as an IRS area id (\"miami\", \"west\"), the label the IRS itself prints (\"Washington, D.C.\", \"West region\") or a USPS state code (\"tx\" or \"TX\", either case, which resolves to its census region). Picks the IRS operating allowance used for insurance, fuel and upkeep. Omit it and the four regions' mean is used instead, flagged as `national-average`.",
          "accepts": "one of northeast, boston, new-york, philadelphia, midwest, chicago, cleveland, detroit, minneapolis-st-paul, st-louis, south, atlanta, baltimore, dallas-ft-worth, houston, miami, tampa, washington-dc, west, anchorage, denver, honolulu, los-angeles, phoenix, san-diego, san-francisco, seattle"
        },
        {
          "name": "monthlyOperatingCosts",
          "type": "number",
          "required": false,
          "min": 0,
          "max": 100000,
          "description": "What insurance, fuel and upkeep actually cost you each month. Overrides `area` when sent, and it is the number to send if you know it — the IRS allowance is a ceiling on what a taxpayer may claim, not a measurement of your bills.",
          "accepts": "number, between 0 and 100000"
        },
        {
          "name": "cars",
          "type": "integer",
          "required": false,
          "default": 1,
          "min": 1,
          "max": 2,
          "description": "How many cars the household runs. Scales both IRS allowances; the table itself only goes to two.",
          "accepts": "integer, between 1 and 2"
        }
      ],
      "returns": {
        "maxPrice": "The answer: what `maxPayment` finances over the term, plus the down payment.",
        "maxPayment": "What is left of the car budget for the loan payment once running costs are paid — the figure a payment-only calculator would have handed you as the whole ten percent.",
        "totalCarBudget": "`sharePct` of take-home pay: the whole car allowance, payment included.",
        "operatingCosts": "Monthly insurance, fuel and upkeep used in the answer.",
        "operatingCostBasis": "\"provided\" when you sent a figure, \"irs-area\" when it came from the IRS table for `area`, \"national-average\" when it is the unweighted mean of the four census regions — which is this API's arithmetic, not an IRS figure.",
        "operatingCostArea": "The IRS area the allowance came from, or null.",
        "budgetCoversOperatingCosts": "False when running costs alone exhaust the allowance. Not an error: at that income the rule leaves nothing for a payment, however long the loan.",
        "takeHomeForAnyPayment": "The monthly take-home pay at which `sharePct` first covers the running costs — below it, `maxPayment` is zero.",
        "maxLoan": "The loan `maxPayment` supports over `termMonths` at `rate`.",
        "totalInterest": "Interest paid over the full term at that payment.",
        "meetsFourYearTerm": "False past the rule's second leg, four years.",
        "operatingCostAreaLabel": "The area's label as the IRS table prints it (\"Miami\", \"West region\"), or null.",
        "termMonths": "The term the headline answer was solved over, in months.",
        "twentyPctDown": "The rule's first leg, measured rather than enforced: whether the down payment reaches a fifth of `maxPrice`, the priciest car a fifth of it would cover, and the shortfall.",
        "byTerm": "The same monthly payment solved over 36, 48, 60 and 72 months, with the interest each costs and whether it is inside the rule.",
        "irsAllowance": "What the IRS treats as a necessary monthly expense for the same car — the ownership (loan or lease) allowance plus the operating allowance — and what that is as a share of your take-home pay. Usually well above what the rule of thumb allows.",
        "rule": "The 20/4/10 convention's three legs, and the statement that no agency sets it."
      },
      "notes": [
        "**The ten percent is all car costs, not the payment.** The rule caps the payment together with insurance, fuel, maintenance and registration at 10% of take-home, so this endpoint subtracts running costs from the allowance before solving for a loan. Calculators that solve 10% straight into a payment answer a much looser question — on $4,200 of take-home, $420 a month of payment instead of $124.",
        "**Running costs default to the IRS's own allowance.** The Collection Financial Standards split what a car costs exactly the way this calculation needs: ownership costs of $703 a month for the loan or lease, and operating costs by census region and metropolitan area covering “maintenance, repairs, insurance, fuel, registrations, licenses, inspections, parking and tolls” — $248 in Anchorage to $423 in Miami. Send `area` to pick one. https://www.irs.gov/businesses/small-businesses-self-employed/local-standards-transportation",
        "**Those allowances are not advice, and the endpoint does not present them as any.** They are what the IRS treats as a necessary living expense when calculating repayment of delinquent taxes — a ceiling on what a taxpayer may claim, derived from Bureau of Labor Statistics expenditure data. A household spending more than the standard is ordinary. They also exclude personal property taxes and say nothing about depreciation.",
        "**The national average is arithmetic on the table, not a published figure.** The IRS prints no nationwide operating cost, so a caller who names no `area` gets the unweighted mean of the four census-region allowances — $295.75. It is the middle of four government figures, not a population-weighted estimate of what households pay, and `operatingCostBasis` says so on every response that uses it.",
        "**20/4/10 is a convention with no authority behind it.** No agency publishes or enforces it. Worth holding beside `irsAllowance`: the IRS treats about $1,000 a month as necessary for one car, while the rule allows $420 on $4,200 of take-home. Neither is a law; they are two different answers, and this endpoint returns both rather than picking.",
        "The first leg is reported, not applied. Enforcing “20% down” would answer $0 for anyone with nothing saved, which is what the rule literally says and is useless as a ceiling to shop against — so `maxPrice` is the payment answer and `twentyPctDown` tells you where you stand.",
        "`maxPrice` is the car, not the drive-away cost: sales tax, title, registration and dealer fees are on top, and this endpoint does not model them.",
        "Same math as the calculator page: both call `carAffordability` in @calcwise/finance, so this answer and https://farbetteroff.com/calculators/car-affordability-calculator cannot disagree."
      ],
      "dataVintage": [
        "irs-transportation-standards"
      ]
    },
    {
      "slug": "pmi",
      "title": "PMI termination schedule",
      "summary": "When private mortgage insurance comes off a conventional loan — the automatic date, the earlier date you can ask, and what waiting costs.",
      "url": "https://farbetteroff.com/api/v1/pmi",
      "example": "https://farbetteroff.com/api/v1/pmi?principal=190000&rate=6.5&termMonths=360&originalValue=200000&pmiMonthly=79",
      "calculator": "https://farbetteroff.com/calculators/mortgage-calculator",
      "params": [
        {
          "name": "principal",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 1,
          "max": 10000000000,
          "description": "Original loan amount.",
          "accepts": "number, US dollars, between 1 and 10000000000"
        },
        {
          "name": "rate",
          "type": "number",
          "unit": "percent",
          "required": true,
          "min": 0,
          "max": 100,
          "description": "Annual interest rate (APR).",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "termMonths",
          "type": "integer",
          "unit": "months",
          "required": true,
          "min": 1,
          "max": 1200,
          "description": "Loan term in months.",
          "accepts": "integer, whole months, between 1 and 1200"
        },
        {
          "name": "originalValue",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 1,
          "max": 10000000000,
          "description": "The home's original value — the lower of purchase price and original appraised value, which is the figure the rule is measured against.",
          "accepts": "number, US dollars, between 1 and 10000000000"
        },
        {
          "name": "pmiMonthly",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 0,
          "max": 100000,
          "description": "PMI premium per month.",
          "accepts": "number, US dollars, between 0 and 100000"
        },
        {
          "name": "extraMonthly",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 10000000,
          "description": "Extra principal per month, which brings the automatic date forward.",
          "accepts": "number, US dollars, between 0 and 10000000"
        }
      ],
      "returns": {
        "automaticEndMonth": "Month PMI must be dropped without you asking.",
        "automaticEndYear": "That month expressed in years.",
        "automaticEndLabel": "That month in words, e.g. \"11 yr 3 mo\".",
        "requestableFromMonth": "First month you may request cancellation (80% of original value).",
        "endsAtAmortizationMidpoint": "True when the midpoint backstop, not the 78% balance, is what ends it.",
        "totalIfAutomatic": "Total PMI paid if you wait for automatic termination.",
        "totalIfRequested": "Total PMI paid if you request cancellation the first month you can.",
        "savingsFromRequesting": "The difference — what asking is worth.",
        "pmi": "Present, and null, only when no PMI is charged at all — 20% or more down, so there is nothing to cancel. Every other field is then absent.",
        "reason": "Why there is no schedule, on that same no-PMI answer."
      },
      "notes": [
        "Source: CFPB, “When can I remove private mortgage insurance (PMI) from my loan?” — https://www.consumerfinance.gov/ask-cfpb/when-can-i-remove-private-mortgage-insurance-pmi-from-my-loan-en-202/",
        "Conventional loans only. FHA mortgage insurance follows different rules and is not modelled.",
        "Dates are based on the original amortization schedule, which is what the statute uses — not on a new appraisal."
      ]
    },
    {
      "slug": "debt-to-income",
      "title": "Debt-to-income ratio",
      "summary": "Front-end and back-end DTI, residual income, and which of the underwriting benchmarks that actually govern something the result clears.",
      "url": "https://farbetteroff.com/api/v1/debt-to-income",
      "example": "https://farbetteroff.com/api/v1/debt-to-income?monthlyIncome=6000&housing=1600&autoLoans=400&studentLoans=250&creditCardMinimums=150",
      "calculator": "https://farbetteroff.com/calculators/debt-to-income-calculator",
      "params": [
        {
          "name": "monthlyIncome",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 1,
          "max": 10000000,
          "description": "Gross monthly income, before tax and deductions. Monthly, not annual — /api/v1/pay converts a salary if you have the yearly figure.",
          "accepts": "number, US dollars, between 1 and 10000000"
        },
        {
          "name": "housing",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 0,
          "max": 1000000,
          "description": "Rent, or the mortgage payment including property tax, insurance, HOA dues and mortgage insurance. This is the front-end ratio on its own.",
          "accepts": "number, US dollars, between 0 and 1000000"
        },
        {
          "name": "autoLoans",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000,
          "description": "Car and other vehicle payments, per month.",
          "accepts": "number, US dollars, between 0 and 1000000"
        },
        {
          "name": "studentLoans",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000,
          "description": "Student loan payments, per month.",
          "accepts": "number, US dollars, between 0 and 1000000"
        },
        {
          "name": "creditCardMinimums",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000,
          "description": "Minimum payments due, not balances — the ratio is built from payments.",
          "accepts": "number, US dollars, between 0 and 1000000"
        },
        {
          "name": "alimonyChildSupport",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000,
          "description": "Alimony and child support. Counted as debt by 12 CFR 1026.43(c)(7)(i)(A), and the item most often left out.",
          "accepts": "number, US dollars, between 0 and 1000000"
        },
        {
          "name": "otherDebt",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000,
          "description": "Personal loans and any other recurring debt obligation.",
          "accepts": "number, US dollars, between 0 and 1000000"
        }
      ],
      "returns": {
        "backEnd": "All debt as a percent of gross monthly income — \"your DTI\".",
        "frontEnd": "Housing payment alone, as a percent of gross monthly income.",
        "totalMonthlyDebt": "Housing plus every non-housing debt payment.",
        "nonHousingDebt": "The non-housing part on its own.",
        "residualIncome": "Gross monthly income minus total debt. Negative when debt exceeds income, because that is the case worth seeing.",
        "strictestCleared": "The id of the strictest benchmark both ratios clear, or null if none do.",
        "benchmarks": "Each benchmark with `clearsFrontEnd`, `clearsBackEnd` and `clears`, plus the source it comes from. Strictest first.",
        "qualifiedMortgage": "What replaced the 43% limit, as data rather than prose: `thresholdYear`, the six `tiers` in force for it (each with its `lien`, its loan-amount band as numbers and as a sentence, and the `aprSpread` over the average prime offer rate **at or above which** the loan stops being a General QM), the `formerDtiLimit` with the date it stopped applying, and the `citation`. Constant — it is the regulation, not an answer about your inputs."
      },
      "notes": [
        "Gross income, never take-home. DTI is computed on income before tax because that is what a lender uses; comparing debts to net pay overstates the ratio.",
        "What counts as debt is defined, not guessed: 12 CFR 1026.43(c)(7)(i)(A) sums the mortgage payment, simultaneous loans, mortgage-related obligations (property tax, insurance, HOA) and current debt obligations including alimony and child support. Everyday living costs — groceries, utilities, phone — are not in that list and are not in this ratio.",
        "**43% is no longer the CFPB's qualified-mortgage limit, and citing it as one is out of date.** The CFPB's General QM Final Rule removed the General QM definition's 43% DTI limit and replaced it with price-based thresholds, mandatory from 1 October 2022. The current text of 12 CFR 1026.43 contains no occurrence of \"43 percent\". The replacement is a price test, and every tier of it comes back in `result.qualifiedMortgage`: in 2026, a first-lien General QM of $137,958 or more must keep its APR **under** the average prime offer rate plus 2.25 percentage points, and 5 further tiers cover smaller loans, manufactured homes and subordinate liens — 12 CFR 1026.43(e)(2)(vi).",
        "**The $110,260 printed in the regulation is not the amount in force, and quoting it is the second-order version of the same mistake.** The section prints 2021 base figures and marks them \"(indexed for inflation)\", then says in as many words to read the official commentary for the current dollar amounts. The Bureau re-indexes them to the CPI-U reported the preceding June and republishes them each December, effective 1 January: the 2026 amounts in `qualifiedMortgage.tiers` are the ones from 90 FR 57890. `meta.dataVintage` carries the date the next edition is due.",
        "DTI did not stop mattering; it stopped being a bright line. A creditor must still consider and verify the borrower's debt-to-income ratio **or** residual income under 12 CFR 1026.43(c)(2)(vii) and (c)(7), with no numeric ceiling attached — which is why `residualIncome` is returned beside the ratios rather than as a nicety.",
        "Where 43% does still bind: FHA's qualifying ratios for manually underwritten loans are 31%/43%, and above either the lender must justify in writing why the loan is an acceptable risk. 37%/47% is reachable with a documented compensating factor and a credit score of 580 or better (HUD Handbook 4000.1 II.A.5.d).",
        "The 28/36 pair is a lending convention with no regulation behind it, and is labelled `convention` rather than `fha` in the response for exactly that reason.",
        "A benchmark is cleared only when **both** ratios are at or under it, and the boundary is inclusive: a back-end ratio of exactly 43.0% clears FHA's, since it is exceeding the ratio that triggers the write-up."
      ],
      "dataVintage": [
        "qm-price-thresholds"
      ]
    },
    {
      "slug": "credit-card-payoff",
      "title": "Credit card payoff",
      "summary": "How long a card balance takes to clear at a fixed monthly payment, and what it costs — including the minimum-payment trap.",
      "url": "https://farbetteroff.com/api/v1/credit-card-payoff",
      "example": "https://farbetteroff.com/api/v1/credit-card-payoff?balance=5000&apr=22.8&monthlyPayment=150",
      "calculator": "https://farbetteroff.com/calculators/credit-card-payoff-calculator",
      "params": [
        {
          "name": "balance",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 0,
          "max": 1000000000,
          "description": "Current balance.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        },
        {
          "name": "apr",
          "type": "number",
          "unit": "percent",
          "required": true,
          "min": 0,
          "max": 100,
          "description": "Annual percentage rate.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "monthlyPayment",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000000,
          "description": "Fixed amount paid each month. Ignored when minimumOnly=true.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        },
        {
          "name": "minimumOnly",
          "type": "boolean",
          "required": false,
          "default": false,
          "description": "Pay only the card's minimum each month (1% of the balance plus interest, floor $25) instead of a fixed amount.",
          "accepts": "boolean"
        }
      ],
      "returns": {
        "months": "Months to clear the balance. Null when the payment never clears it.",
        "termLabel": "That time in words.",
        "totalInterest": "Interest paid getting there.",
        "totalPaid": "Balance plus interest.",
        "firstPayment": "The first month's payment — the useful number under minimumOnly.",
        "neverPaysOff": "True when the payment is at or below the monthly interest."
      },
      "notes": [
        "The minimum-payment formula (1% of balance plus that month's interest, with a $25 floor) is the common US issuer convention, not a statutory rule. Your card's terms govern.",
        "Assumes no new charges and no fees."
      ]
    },
    {
      "slug": "debt-snowball",
      "title": "Debt snowball vs. avalanche",
      "summary": "Both payoff orders for up to six debts, run side by side: the queue, the month each debt disappears, the debt-free date and what each method costs in interest.",
      "url": "https://farbetteroff.com/api/v1/debt-snowball",
      "example": "https://farbetteroff.com/api/v1/debt-snowball?balance1=6200&apr1=24.99&minimum1=155&balance2=2100&apr2=6.5&minimum2=95&balance3=11500&apr3=18.9&minimum3=260&extra=200",
      "calculator": "https://farbetteroff.com/calculators/debt-snowball-calculator",
      "params": [
        {
          "name": "balance1",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 0,
          "max": 10000000,
          "description": "Balance owed on the first debt. Send them in any order — the payoff queue is worked out for you.",
          "accepts": "number, US dollars, between 0 and 10000000"
        },
        {
          "name": "apr1",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 100,
          "description": "Annual percentage rate on debt 1, e.g. 24.99. This is what the avalanche orders by.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "minimum1",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000,
          "description": "Minimum payment due on debt 1 each month — the payment, not the balance.",
          "accepts": "number, US dollars, between 0 and 1000000"
        },
        {
          "name": "balance2",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 0,
          "max": 10000000,
          "description": "Balance owed on debt 2.",
          "accepts": "number, US dollars, between 0 and 10000000"
        },
        {
          "name": "apr2",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 100,
          "description": "Annual percentage rate on debt 2, e.g. 24.99. This is what the avalanche orders by.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "minimum2",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000,
          "description": "Minimum payment due on debt 2 each month — the payment, not the balance.",
          "accepts": "number, US dollars, between 0 and 1000000"
        },
        {
          "name": "balance3",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 10000000,
          "description": "Balance owed on debt 3. Leave it out or send 0 to skip the slot.",
          "accepts": "number, US dollars, between 0 and 10000000"
        },
        {
          "name": "apr3",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 100,
          "description": "Annual percentage rate on debt 3, e.g. 24.99. This is what the avalanche orders by.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "minimum3",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000,
          "description": "Minimum payment due on debt 3 each month — the payment, not the balance.",
          "accepts": "number, US dollars, between 0 and 1000000"
        },
        {
          "name": "balance4",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 10000000,
          "description": "Balance owed on debt 4. Leave it out or send 0 to skip the slot.",
          "accepts": "number, US dollars, between 0 and 10000000"
        },
        {
          "name": "apr4",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 100,
          "description": "Annual percentage rate on debt 4, e.g. 24.99. This is what the avalanche orders by.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "minimum4",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000,
          "description": "Minimum payment due on debt 4 each month — the payment, not the balance.",
          "accepts": "number, US dollars, between 0 and 1000000"
        },
        {
          "name": "balance5",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 10000000,
          "description": "Balance owed on debt 5. Leave it out or send 0 to skip the slot.",
          "accepts": "number, US dollars, between 0 and 10000000"
        },
        {
          "name": "apr5",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 100,
          "description": "Annual percentage rate on debt 5, e.g. 24.99. This is what the avalanche orders by.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "minimum5",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000,
          "description": "Minimum payment due on debt 5 each month — the payment, not the balance.",
          "accepts": "number, US dollars, between 0 and 1000000"
        },
        {
          "name": "balance6",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 10000000,
          "description": "Balance owed on debt 6. Leave it out or send 0 to skip the slot.",
          "accepts": "number, US dollars, between 0 and 10000000"
        },
        {
          "name": "apr6",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 100,
          "description": "Annual percentage rate on debt 6, e.g. 24.99. This is what the avalanche orders by.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "minimum6",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000,
          "description": "Minimum payment due on debt 6 each month — the payment, not the balance.",
          "accepts": "number, US dollars, between 0 and 1000000"
        },
        {
          "name": "extra",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000,
          "description": "Everything you can pay above the minimums, per month. This single number decides how fast you are free; the method only decides the order.",
          "accepts": "number, US dollars, between 0 and 1000000"
        }
      ],
      "returns": {
        "debtCount": "How many slots carried a balance and were simulated.",
        "startBalance": "Everything owed today.",
        "minimums": "The minimum payments added up.",
        "monthlyBudget": "Minimums plus extra — the same under both methods, which is what makes the comparison fair.",
        "cheaper": "\"avalanche\", or null when both orders come out identical. Never \"snowball\": highest-rate-first is optimal for total interest.",
        "interestSaved": "Interest the cheaper order saves. Zero when the two orders agree.",
        "monthsSaved": "Months the cheaper order saves. Often zero even when the interest differs.",
        "sameOrder": "True when both methods pick the same queue, so the two plans are one plan.",
        "avalanche": "The highest-rate-first plan: months, termLabel, totalInterest, totalPaid, firstDebtGoneMonth, neverPaysOff, and `order` — one row per debt with its rank, payoff month and interest.",
        "snowball": "The smallest-balance-first plan, in the same shape."
      },
      "notes": [
        "Both methods pay every minimum every month and throw everything left at one debt, then roll a cleared debt's minimum onto the next one. The monthly payment is identical; only the order differs. That is why the two plans can be compared at all.",
        "The avalanche (highest rate first) is never slower or more expensive — it kills the costliest interest first. The snowball (smallest balance first) clears a whole debt sooner, which is what `firstDebtGoneMonth` is for. The CFPB describes both and crowns neither, because the plan you actually finish is the one that works: https://www.consumerfinance.gov/about-us/blog/how-reduce-your-debt/",
        "Debts are slots, not a list: `balance1` … `balance6`, each with its own `apr` and `minimum`. A slot with a zero balance is ignored, so you can send a fixed set of six and leave the unused ones empty. Debts are returned named for the slot they came in on.",
        "Interest is charged monthly on the remaining balance at apr/12, which is how a credit-card statement behaves. Minimums are held constant rather than shrinking with the balance, which is how most people actually pay.",
        "Assumes the rates and minimums stay put, no new debt is added, and the whole `monthlyBudget` keeps being paid even as debts disappear. Stop rolling the freed-up minimums forward and the real payoff stretches out by months.",
        "When the payment does not outrun the interest the balances grow forever: `months` is null and `neverPaysOff` is true rather than a 600-month answer being invented. Anything past 50 years is reported the same way.",
        "Ties are broken on the other measure, so the queue never depends on the order the debts were sent in: two debts at the same rate are ordered smallest balance first, two at the same balance highest rate first."
      ]
    },
    {
      "slug": "compound-interest",
      "title": "Compound interest",
      "summary": "What a balance grows to with regular contributions, split into what you put in and what compounding added.",
      "url": "https://farbetteroff.com/api/v1/compound-interest",
      "example": "https://farbetteroff.com/api/v1/compound-interest?principal=10000&contribution=500&rate=7&years=25",
      "calculator": "https://farbetteroff.com/calculators/compound-interest-calculator",
      "params": [
        {
          "name": "principal",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 0,
          "max": 1000000000000,
          "description": "Starting balance.",
          "accepts": "number, US dollars, between 0 and 1000000000000"
        },
        {
          "name": "contribution",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000000,
          "description": "Added at the end of every compounding period.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        },
        {
          "name": "rate",
          "type": "number",
          "unit": "percent",
          "required": true,
          "min": 0,
          "max": 100,
          "description": "Nominal annual return.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "years",
          "type": "integer",
          "unit": "years",
          "required": true,
          "min": 0,
          "max": 100,
          "description": "How long to run it.",
          "accepts": "integer, years, between 0 and 100"
        },
        {
          "name": "periodsPerYear",
          "type": "integer",
          "unit": "count",
          "required": false,
          "default": 12,
          "min": 1,
          "max": 365,
          "description": "Compounding periods per year. 12 is monthly, 1 is annual.",
          "accepts": "integer, a count, between 1 and 365"
        },
        {
          "name": "series",
          "type": "boolean",
          "required": false,
          "default": false,
          "description": "Include the year-by-year balance series.",
          "accepts": "boolean"
        }
      ],
      "returns": {
        "balance": "Final balance.",
        "contributed": "Principal plus every contribution.",
        "growth": "Balance minus contributed — what the compounding did.",
        "series": "Present only when series=true: balance, contributed and growth for each year."
      }
    },
    {
      "slug": "savings-goal",
      "title": "Savings goal",
      "summary": "Both halves of a savings target: how long a monthly deposit takes to get there, and what deposit hits a deadline exactly.",
      "url": "https://farbetteroff.com/api/v1/savings-goal",
      "example": "https://farbetteroff.com/api/v1/savings-goal?goal=30000&current=5000&monthly=400&rate=4&deadlineYears=5",
      "calculator": "https://farbetteroff.com/calculators/savings-goal-calculator",
      "params": [
        {
          "name": "goal",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 0,
          "max": 1000000000000,
          "description": "The amount you are aiming at.",
          "accepts": "number, US dollars, between 0 and 1000000000000"
        },
        {
          "name": "current",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000000000,
          "description": "What you have saved already.",
          "accepts": "number, US dollars, between 0 and 1000000000000"
        },
        {
          "name": "monthly",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000000,
          "description": "What you put in each month. Drives the time-to-goal answer.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        },
        {
          "name": "rate",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 100,
          "description": "Annual return or APY on the savings.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "deadlineYears",
          "type": "number",
          "unit": "years",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 100,
          "description": "Optional deadline. When above 0, the response also says what monthly deposit lands on the goal exactly then.",
          "accepts": "number, years, between 0 and 100"
        }
      ],
      "returns": {
        "reached": "Whether `monthly` gets there within 100 years.",
        "months": "Months to the goal at `monthly`. Null if it never arrives.",
        "termLabel": "That time in words.",
        "balanceAtGoal": "Balance the month the goal is met.",
        "requiredMonthly": "Present only with deadlineYears > 0: the deposit that lands exactly on the goal by the deadline."
      }
    },
    {
      "slug": "emergency-fund",
      "title": "Emergency fund",
      "summary": "How big a cushion is, how much of it is already there, and how many months of expenses today's savings would actually cover.",
      "url": "https://farbetteroff.com/api/v1/emergency-fund",
      "example": "https://farbetteroff.com/api/v1/emergency-fund?monthlyExpenses=3500&months=6&saved=4000&monthlySaving=400&annualIncome=60000&age=35",
      "calculator": "https://farbetteroff.com/calculators/emergency-fund-calculator",
      "params": [
        {
          "name": "monthlyExpenses",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 0,
          "max": 1000000,
          "description": "Essential monthly outgoings: housing, food, utilities, transport, insurance and minimum debt payments. Essentials, not the whole budget — restaurants, holidays and subscriptions pause in an emergency.",
          "accepts": "number, US dollars, between 0 and 1000000"
        },
        {
          "name": "months",
          "type": "number",
          "unit": "months",
          "required": false,
          "default": 6,
          "min": 1,
          "max": 24,
          "description": "Months of cushion to size the target against. Defaults to 6, which is a convention rather than a rule — see the notes. `ladder` answers for 1, 3, 6 and 12 regardless of what you send.",
          "accepts": "number, whole months, between 1 and 24"
        },
        {
          "name": "saved",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000000,
          "description": "What is set aside for emergencies today.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        },
        {
          "name": "monthlySaving",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000,
          "description": "What can be added each month. Drives `monthsToTarget`; leave it out and that answer is null.",
          "accepts": "number, US dollars, between 0 and 1000000"
        },
        {
          "name": "annualIncome",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 100000000,
          "description": "Annual pre-tax family income. Drives `peers.byIncome` only — it changes no arithmetic. Omit it and that cut comes back null.",
          "accepts": "number, US dollars, between 0 and 100000000"
        },
        {
          "name": "age",
          "type": "number",
          "unit": "years",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 120,
          "description": "Age of the adult. Drives `peers.byAge` only — it changes no arithmetic. The survey covers adults, so an age under 18 falls outside every published band and returns null.",
          "accepts": "number, years, between 0 and 120"
        }
      ],
      "returns": {
        "target": "Dollars the chosen cushion comes to — `monthlyExpenses` × `months`.",
        "targetMonths": "Months of cushion the target represents, echoed.",
        "gap": "Dollars still to save. 0 once the target is met.",
        "fundedPct": "Share of the target already saved, 0–100.",
        "funded": "Whether the target is met.",
        "monthsCovered": "**The target-independent answer:** months of essentials current savings would cover. Does not move when `months` changes. Null when `monthlyExpenses` is 0.",
        "monthsToTarget": "Whole months of saving to close the gap, ignoring interest. 0 when already funded; null when nothing is being saved, or when it would take over 100 years.",
        "termLabel": "`monthsToTarget` in words, or null.",
        "coversSmallShock": "Whether savings alone cover the Federal Reserve's $400 emergency-expense question.",
        "atRainyDayBenchmark": "Whether savings reach three months of expenses — the rainy-day cushion the Federal Reserve measures households against.",
        "ladder": "The four cushion conventions (1, 3, 6, 12 months) with `amount`, `reached` and `shortfall` against each, plus who each size is usually suggested for.",
        "benchmarks": "The measured Federal Reserve figures this endpoint reports against — the $400 and three-month shares, and how many adults can cover neither — with their survey year.",
        "peers": "**Is that normal?** — the measured company this household keeps, for whichever cuts were supplied. `byIncome` and `byAge` give the share of adults in that band with three months set aside; `savingsCeiling` places `saved` in the Fed's largest-expense-from-savings distribution with the share below it and at or above it. Each cut is null when its input was not sent, and the full published bands ride along in `bands` so a caller can draw the whole distribution rather than one row."
      },
      "notes": [
        "**Nobody regulates the size of an emergency fund, and this endpoint does not pretend otherwise.** \"Three to six months\" is a widely-repeated convention with no rule behind it. The CFPB's own guide to building an emergency fund gives no month-count target at all — it says to save what you can, and that \"even a small amount can provide some financial security\". So `ladder` is labelled a set of conventions, and the numbers here that do have a measurement behind them are kept separate in `benchmarks`.",
        "`monthsCovered` is the number to quote, not `fundedPct`. A percentage is a ratio against a target somebody chose, so it halves when a caller changes `months` from 6 to 12 while nothing about the household has changed. Months covered is what the Federal Reserve's Survey of Household Economics and Decisionmaking actually asks about: whether a household \"could cover three months of expenses with a rainy day fund\".",
        "The $400 figure in `coversSmallShock` is the Fed's small-emergency question — whether an adult could cover \"a hypothetical $400 emergency expense exclusively using cash, savings, or a credit card paid off at the next statement\". 63% of US adults said they could in the 2025 survey, unchanged from the previous several years and down from a high of 68% in 2021. The three-month cushion in `atRainyDayBenchmark` is the other measured one: 55% of US adults reached it, while 30% could not cover three months by any means at all — borrowing and selling included. Both distributions, by income and by age, are set out at /how-much-should-i-have-in-an-emergency-fund with the table citations.",
        "Interest is deliberately ignored. An emergency fund belongs somewhere liquid, and over the months this projection covers APY moves the finish line by days, so `monthsToTarget` is a slight over-estimate — the safe direction to be wrong in. Use /api/v1/savings-goal if you want the same question answered with a return applied.",
        "`monthsToTarget` distinguishes 0 from null: 0 means the target is already met, null means not on this plan. A caller that conflates them prints \"never\" to someone who has finished.",
        "**The spread is the finding, not the row a caller lands on.** The same \"three to six months\" is advised to a household where **21%** manage it and to one where **75%** do, and across age it runs 37% to 71% — both bracketing the 55% headline that gets quoted on its own. A single national figure describes neither end, which is why every band travels with the one that was selected.",
        "**No figure here is interpolated between bands.** The bands are the Federal Reserve's own and are reproduced as published rather than re-cut, so a household earning $50,000 and one earning $99,000 get the same 55% — that is the resolution the survey publishes, and inventing a curve between the bands would be a figure the Board never reported. Edges are half-open on income ($50,000 belongs to the band above, matching the Board's \"$25,000–$49,999\" labels) and inclusive on age.",
        "`savingsCeiling` places `saved` in table 26 — \"the largest emergency expense you could handle right now using only savings\". `pctBelowBand` is summed from the published bands rather than read off a cumulative column the Board does not print, and the sum is checkable: the at-or-above share of the $500–$999 band comes to **70%**, which is the figure the Board states in its own text. One caveat worth passing on: the survey asks about **every** dollar of savings, while `saved` is what a household has earmarked for emergencies, so a real ceiling may sit a band higher."
      ],
      "dataVintage": [
        "fed-shed"
      ]
    },
    {
      "slug": "net-worth",
      "title": "Net worth",
      "summary": "Everything owned minus everything owed, split into what is liquid and what is not — and where the answer sits against the Federal Reserve's measured distribution for the household's age.",
      "url": "https://farbetteroff.com/api/v1/net-worth",
      "example": "https://farbetteroff.com/api/v1/net-worth?cash=12000&investments=20000&retirement=45000&home=320000&vehicles=18000&mortgage=250000&autoLoans=9000&studentLoans=14000&creditCards=3000&age=40",
      "calculator": "https://farbetteroff.com/calculators/net-worth-calculator",
      "params": [
        {
          "name": "cash",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000000,
          "description": "Cash, checking and savings.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        },
        {
          "name": "investments",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000000,
          "description": "Taxable brokerage holdings. Counted as liquid alongside `cash`.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        },
        {
          "name": "retirement",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000000,
          "description": "401(k), IRA and other retirement accounts. Counted as an asset but **not** as liquid — reaching it early generally costs tax and a penalty.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        },
        {
          "name": "home",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000000,
          "description": "Current market value of the home — what it would sell for today, not its purchase price.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        },
        {
          "name": "vehicles",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000000,
          "description": "Resale value of vehicles. See the notes on why this one normally falls year over year.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        },
        {
          "name": "otherAssets",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000000,
          "description": "Business interests, collectibles, cash value of insurance, anything else owned.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        },
        {
          "name": "mortgage",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000000,
          "description": "Outstanding mortgage principal. Netted against `home` to give `homeEquity`.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        },
        {
          "name": "autoLoans",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000000,
          "description": "Auto loan balances.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        },
        {
          "name": "studentLoans",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000000,
          "description": "Student loan balances.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        },
        {
          "name": "creditCards",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000000,
          "description": "Credit card balances carried. Subtracted from liquid assets to give `liquidNetWorth`.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        },
        {
          "name": "otherDebts",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000000,
          "description": "Personal loans, medical debt, anything else owed. Also treated as short-term debt.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        },
        {
          "name": "age",
          "type": "number",
          "unit": "years",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 120,
          "description": "Age of the household's reference person. Drives `benchmark` only — it changes no arithmetic. Omit it and `benchmark` comes back null.",
          "accepts": "number, years, between 0 and 120"
        }
      ],
      "returns": {
        "netWorth": "Total assets minus total liabilities. Negative is common rather than exceptional — see the notes.",
        "totalAssets": "Everything owned, summed.",
        "totalLiabilities": "Everything owed, summed.",
        "negative": "Whether debts outweigh assets.",
        "liquidAssets": "`cash` + `investments` — what could be reached without selling a house or a car.",
        "liquidNetWorth": "Liquid assets less short-term debt (`creditCards` + `otherDebts`). **The honest emergency figure**: a brokerage balance offset by a card balance is not really available.",
        "homeEquity": "`home` − `mortgage`. Negative when the mortgage exceeds the home's value.",
        "underwater": "Whether the mortgage exceeds the home's value. False when there is no home.",
        "debtToAssetPct": "Liabilities as a percent of assets. Null when there are no assets to divide by.",
        "liquidSharePct": "Share of assets that is liquid, 0–100. Null when there are no assets.",
        "assetMix": "Each non-empty asset category with its `amount`, `sharePct` and whether it is `liquid`, in declared order rather than sorted by size.",
        "benchmark": "Where this net worth sits against the Federal Reserve's 2022 Survey of Consumer Finances for the household's age band: the band's `median` and `mean`, the `meanToMedianRatio` that explains the gap between them, `vsMedianPct` and `atOrAboveMedian`. Null when no `age` was sent.",
        "allFamilies": "Median and mean net worth across all US families in the same survey, with the same ratio — the denominator for \"compared to everyone, not just my age\"."
      },
      "notes": [
        "**Quote the median, not the mean.** Net worth is among the most skewed quantities in household finance, so its average describes almost nobody: across all US families in the 2022 SCF the mean is $1,059,470 against a median of $192,700 — the mean is **5.5×** the median, pulled there by the top of the distribution. Every \"average net worth by age\" figure in circulation is a mean. This endpoint returns both, and `meanToMedianRatio` so the difference is visible rather than implied.",
        "**The benchmark figures are 2022 dollars from a 2022 survey, and this endpoint does not pretend they are today's.** The SCF runs every three years and the Board states that the 2022 survey \"is the most recent survey conducted\". Comparing a present-day balance sheet against a 2022-dollar benchmark flatters the present-day one, so `surveyYear` and `dollarYear` travel with every comparison. Nothing here inflates them to a current year — that would invent figures the Federal Reserve never published.",
        "Every figure was transcribed from the Fed's own published workbook (table 4, \"Family net worth, by selected characteristics of families, 1989–2022 surveys\"), not from a secondary summary: https://www.federalreserve.gov/econres/files/scf2022_tables_public_real_historical.xlsx",
        "The age bands are the Federal Reserve's own and are not evenly sized (`Less than 35`, then 35–44, 45–54, 55–64, 65–74, `75 or more`). They are reproduced as published rather than re-cut, because re-cutting them needs data the summary table does not carry.",
        "A negative net worth is a normal starting point, not a failure state: a new graduate with student loans or a recent buyer with a fresh mortgage will often show one for years. `negative` is reported as a fact about the balance sheet, and nothing in this response treats it as a verdict.",
        "Assets are counted at what they would sell for today, not at what they cost. That is why a car normally pulls this number down year over year, and why nothing here applies appreciation, depreciation or a growth rate — net worth is a snapshot, and projecting it forward would be a forecast wearing a measurement's clothes.",
        "`retirement` counts toward `netWorth` but not toward `liquidAssets`, and `home` counts toward neither `liquidAssets` nor `liquidNetWorth`. A household can be comfortably positive and still unable to cover a $400 emergency — use /api/v1/emergency-fund for that question."
      ],
      "dataVintage": [
        "fed-scf"
      ]
    },
    {
      "slug": "budget",
      "title": "50/30/20 budget",
      "summary": "Take-home pay split into needs, wants and savings on the 50/30/20 rule — with housing measured against the needs slice it has to fit inside, and against the two benchmarks that are actually published.",
      "url": "https://farbetteroff.com/api/v1/budget",
      "example": "https://farbetteroff.com/api/v1/budget?income=4500&housing=1800&grossMonthlyIncome=6000&annualIncome=72000",
      "calculator": "https://farbetteroff.com/calculators/budget-calculator",
      "params": [
        {
          "name": "income",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 0,
          "max": 10000000,
          "description": "Monthly **take-home** pay — after taxes and payroll deductions.",
          "accepts": "number, US dollars, between 0 and 10000000"
        },
        {
          "name": "housing",
          "type": "number",
          "unit": "usd",
          "required": false,
          "min": 0,
          "max": 10000000,
          "description": "Monthly housing cost **including utilities**, HUD's basis. Drives the whole `housing` object; omit it and that comes back null.",
          "accepts": "number, US dollars, between 0 and 10000000"
        },
        {
          "name": "grossMonthlyIncome",
          "type": "number",
          "unit": "usd",
          "required": false,
          "min": 0,
          "max": 10000000,
          "description": "Monthly income **before** taxes. Used for nothing but HUD's cost-burden test, which is defined on gross income. Omit it and `housing.hud` comes back null rather than being estimated from take-home.",
          "accepts": "number, US dollars, between 0 and 10000000"
        },
        {
          "name": "annualIncome",
          "type": "number",
          "unit": "usd",
          "required": false,
          "min": 0,
          "max": 1000000000,
          "description": "Annual **pre-tax family** income. Selects `margin.band` only — it changes no arithmetic. Omit it and the band comes back null.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        }
      ],
      "returns": {
        "income": "Monthly take-home pay, echoed.",
        "plan": "The rule's three slices in dollars a month: `needs` (50%), `wants` (30%) and `savings` (20%).",
        "savingsPerYear": "The savings slice over twelve months, at this pace and ignoring investment returns.",
        "ruleShares": "The three percentages, so a caller never hardcodes 50/30/20 itself.",
        "ruleOrigin": "Where the rule comes from — a 2005 book, named. See the notes.",
        "housing": "Housing against the budget: `sharePct` of take-home, **shareOfNeedsBudgetPct** of the rule's own needs slice, `leavesForOtherNeeds` in dollars, and `fitsNeedsBudget`. Null when no `housing` was sent. Its nested `hud` carries HUD's cost-burden test on HUD's own basis — `grossSharePct`, `costBurdened` (above 30% of gross) and `severelyCostBurdened` (above 50%) — and is itself null unless `grossMonthlyIncome` was supplied, per the notes.",
        "margin": "What the Federal Reserve measures about having anything left over at month end: `alwaysOrOftenPct` across all US adults, the `band` matching `annualIncome`, and every `bands` entry with its full five-point distribution."
      },
      "notes": [
        "**50/30/20 is a rule of thumb from a book, not a standard.** It traces to the 2005 book **All Your Worth: The Ultimate Lifetime Money Plan**, by Elizabeth Warren and Amelia Warren Tyagi. No regulator publishes it, no agency measures against it, and no federal survey reports it as a norm. This endpoint implements it faithfully and returns `ruleOrigin` with every response, so a caller quoting the split can say where it came from instead of implying an authority that does not exist.",
        "**shareOfNeedsBudgetPct is the figure to quote, and nobody else publishes it.** Everyone reports housing as a share of income; the question the rule actually poses is whether housing fits inside the 50% it allows for **all** needs. On $4,500 of take-home the needs slice is $2,250, so $1,800 of rent is **80% of the entire needs budget** and leaves $450 for food, utilities, transport, insurance and minimum debt payments. Above 100 the rule is broken before groceries. That is the arithmetic answer to \"is 50/30/20 realistic?\".",
        "**HUD's 30% is defined on gross income, and this endpoint will not apply it to take-home pay.** HUD defines affordable housing as housing \"on which the occupant is paying no more than 30 percent of gross income for housing costs, including utilities\", above 50 percent being the severe case; its CHAS dataset counts cost-burdened households against exactly that threshold. Take-home pay is a smaller denominator, so the same rent scores higher against it — $1,800 is 40% of $4,500 take-home but 30.0% of $6,000 gross, which is one household and two different verdicts. `housing.hud` therefore stays null until `grossMonthlyIncome` arrives rather than guessing a gross figure. Sources: https://archives.hud.gov/local/nv/goodstories/2006-04-06glos.cfm and https://www.huduser.gov/portal/datasets/cp.html",
        "**Saving 20% is not the norm, and there is a measurement for it.** The Federal Reserve's Survey of Household Economics and Decisionmaking asks how often people have money left over at the end of the month. In 2025, **41 percent** of US adults said always or often — similar to 2024 — and it ranges from 19 percent under $25,000 of family income to 59 percent at $100,000 or more. The rule's savings slice is a target, and `margin` is what the population actually reports. https://www.federalreserve.gov/publications/2026-economic-well-being-of-us-households-in-2025-income-and-expenses.htm",
        "The Board publishes whole percents, so the five-point distributions in `margin.bands` sum to between 99 and 101 rather than exactly 100. That is rounding in the source. `alwaysOrOftenPct` is the Board's own stated figure rather than a sum of two rounded components — which matters in the lowest band, where the prose says 19 and `often + always` sums to 20.",
        "`annualIncome` is pre-tax family income for the whole household, because that is the basis the Fed's bands use. `income` is monthly take-home for one budget. They are deliberately different questions and neither is derived from the other.",
        "Nothing here is advice about what the split **should** be. The rule is returned as the rule, the two benchmarks are returned as measurements, and they are kept in separate objects so nothing borrows the other's authority."
      ],
      "dataVintage": [
        "fed-shed"
      ]
    },
    {
      "slug": "cd",
      "title": "Certificate of deposit",
      "summary": "What a CD is worth at maturity, from the APY the bank quotes.",
      "url": "https://farbetteroff.com/api/v1/cd",
      "example": "https://farbetteroff.com/api/v1/cd?deposit=10000&apy=4.25&termMonths=12",
      "calculator": "https://farbetteroff.com/calculators/cd-calculator",
      "params": [
        {
          "name": "deposit",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 0,
          "max": 10000000000,
          "description": "Amount deposited.",
          "accepts": "number, US dollars, between 0 and 10000000000"
        },
        {
          "name": "apy",
          "type": "number",
          "unit": "percent",
          "required": true,
          "min": 0,
          "max": 50,
          "description": "Annual percentage yield, as quoted.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 50"
        },
        {
          "name": "termMonths",
          "type": "integer",
          "unit": "months",
          "required": true,
          "min": 1,
          "max": 600,
          "description": "Term of the CD in months.",
          "accepts": "integer, whole months, between 1 and 600"
        }
      ],
      "returns": {
        "maturity": "Value when the term ends.",
        "interest": "Maturity minus the deposit."
      },
      "notes": [
        "APY already accounts for the bank's compounding frequency, which is what makes it the comparable number (12 CFR Part 1030 / Regulation DD, Appendix A).",
        "Interest is shown before tax. CD interest is generally taxable as ordinary income."
      ]
    },
    {
      "slug": "inflation",
      "title": "Inflation impact",
      "summary": "What a sum of money will cost, and what it will be worth, after inflation has run for a while.",
      "url": "https://farbetteroff.com/api/v1/inflation",
      "example": "https://farbetteroff.com/api/v1/inflation?amount=10000&years=20&rate=3",
      "calculator": "https://farbetteroff.com/calculators/inflation-calculator",
      "params": [
        {
          "name": "amount",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 0,
          "max": 1000000000000,
          "description": "Today's amount.",
          "accepts": "number, US dollars, between 0 and 1000000000000"
        },
        {
          "name": "years",
          "type": "number",
          "unit": "years",
          "required": true,
          "min": 0,
          "max": 200,
          "description": "How many years forward.",
          "accepts": "number, years, between 0 and 200"
        },
        {
          "name": "rate",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 3,
          "min": 0,
          "max": 100,
          "description": "Average annual inflation rate.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        }
      ],
      "returns": {
        "factor": "Cumulative price multiplier over the period.",
        "futureCost": "What today's basket costs then.",
        "buyingPower": "What today's money is worth then, in today's dollars.",
        "lostPercent": "Share of buying power lost, as a percentage."
      }
    },
    {
      "slug": "401k",
      "title": "401(k) projection",
      "summary": "A 401(k) balance projected to retirement, split into your money, the employer's money and growth.",
      "url": "https://farbetteroff.com/api/v1/401k",
      "example": "https://farbetteroff.com/api/v1/401k?currentBalance=25000&salary=65000&contribPercent=6&years=35",
      "calculator": "https://farbetteroff.com/calculators/401k-calculator",
      "params": [
        {
          "name": "currentBalance",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 10000000000,
          "description": "What is in the account today.",
          "accepts": "number, US dollars, between 0 and 10000000000"
        },
        {
          "name": "salary",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 0,
          "max": 1000000000,
          "description": "Current annual salary.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        },
        {
          "name": "contribPercent",
          "type": "number",
          "unit": "percent",
          "required": true,
          "min": 0,
          "max": 100,
          "description": "Share of salary you defer each year.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "matchRatePercent",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 50,
          "min": 0,
          "max": 200,
          "description": "Cents on the dollar the employer matches — 50 means 50%.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 200"
        },
        {
          "name": "matchLimitPercent",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 6,
          "min": 0,
          "max": 100,
          "description": "Share of salary the match applies up to.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "rate",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 7,
          "min": 0,
          "max": 100,
          "description": "Average annual return.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "annualRaisePercent",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 2,
          "min": 0,
          "max": 50,
          "description": "Average yearly raise.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 50"
        },
        {
          "name": "years",
          "type": "integer",
          "unit": "years",
          "required": true,
          "min": 0,
          "max": 70,
          "description": "Years until you stop contributing.",
          "accepts": "integer, years, between 0 and 70"
        },
        {
          "name": "currentAge",
          "type": "integer",
          "unit": "years",
          "required": false,
          "min": 0,
          "max": 100,
          "description": "The age you reach this year. Given it, each year of the projection uses that year's own § 402(g) limit, including the age-50 and age-60-to-63 catch-ups. Ignored when deferralLimit is sent.",
          "accepts": "integer, years, between 0 and 100"
        },
        {
          "name": "deferralLimit",
          "type": "number",
          "unit": "usd",
          "required": false,
          "min": 0,
          "max": 1000000,
          "description": "Employee deferral cap for every year, overriding currentAge. Omit both for the flat 2026 limit, $24,500.",
          "accepts": "number, US dollars, between 0 and 1000000"
        },
        {
          "name": "series",
          "type": "boolean",
          "required": false,
          "default": false,
          "description": "Include the year-by-year balance series.",
          "accepts": "boolean"
        }
      ],
      "returns": {
        "balance": "Projected balance at the end.",
        "yourContributions": "Everything you put in, excluding the starting balance.",
        "employerContributions": "Everything the employer matched in.",
        "growth": "Investment growth on top.",
        "cappedByDeferralLimit": "True if your contribution percentage would exceed the annual cap.",
        "catchUpContributions": "Of yourContributions, the dollars only a catch-up allowed. 0 unless currentAge was sent and the plain limit would have bitten.",
        "series": "Present only when series=true."
      },
      "notes": [
        "2026 employee deferral limit: $24,500 (IRS Notice 2025-67), $32,500 from the year you turn 50 and $35,750 for the four years you turn 60 to 63 — send currentAge to have each year use its own. The 2026 figures apply to every projected year; they rise with inflation most years.",
        "A projection, not a promise: it assumes a constant return and a constant raise, and markets do neither."
      ],
      "dataVintage": [
        "irs-retirement-limits"
      ]
    },
    {
      "slug": "401k-match",
      "title": "Employer match",
      "summary": "What your employer's match is worth this year — and how much of it you are leaving on the table.",
      "url": "https://farbetteroff.com/api/v1/401k-match",
      "example": "https://farbetteroff.com/api/v1/401k-match?salary=60000&contribPercent=4&matchRatePercent=50&matchLimitPercent=6",
      "calculator": "https://farbetteroff.com/calculators/401k-match-calculator",
      "params": [
        {
          "name": "salary",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 0,
          "max": 1000000000,
          "description": "Annual salary.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        },
        {
          "name": "contribPercent",
          "type": "number",
          "unit": "percent",
          "required": true,
          "min": 0,
          "max": 100,
          "description": "Share of salary you contribute.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "matchRatePercent",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 50,
          "min": 0,
          "max": 200,
          "description": "Cents on the dollar matched — 50 means 50%, 100 means dollar for dollar.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 200"
        },
        {
          "name": "matchLimitPercent",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 6,
          "min": 0,
          "max": 100,
          "description": "Share of salary the match applies up to.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        }
      ],
      "returns": {
        "yourContribution": "Your dollars in this year.",
        "match": "Employer dollars you earn.",
        "maxMatch": "The most the employer would put in at this formula.",
        "missed": "Match you are giving up by contributing less than the limit.",
        "total": "Your contribution plus the match."
      }
    },
    {
      "slug": "safe-withdrawal",
      "title": "Safe withdrawal rate",
      "summary": "The income a nest egg supports — the 4% rule, and the 25× multiple behind it.",
      "url": "https://farbetteroff.com/api/v1/safe-withdrawal",
      "example": "https://farbetteroff.com/api/v1/safe-withdrawal?nestEgg=1000000&withdrawalRate=4",
      "calculator": "https://farbetteroff.com/calculators/retirement-calculator",
      "params": [
        {
          "name": "nestEgg",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 0,
          "max": 1000000000000,
          "description": "Portfolio value at retirement.",
          "accepts": "number, US dollars, between 0 and 1000000000000"
        },
        {
          "name": "withdrawalRate",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 4,
          "min": 0.1,
          "max": 20,
          "description": "First-year withdrawal rate.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0.1 and 20"
        }
      ],
      "returns": {
        "annual": "First-year withdrawal in dollars.",
        "monthly": "That divided by 12.",
        "multiple": "Years of spending the portfolio represents — 25 at 4%."
      },
      "notes": [
        "The 4% rule comes from William Bengen's 1994 study and the 1998 Trinity Study: a 4% inflation-adjusted first-year withdrawal survived every 30-year period in US market history. 30 years is the worst case in that research, not a guarantee."
      ]
    },
    {
      "slug": "fire",
      "title": "FIRE number and date",
      "summary": "The portfolio that covers your spending forever, and how many years of saving it takes to get there.",
      "url": "https://farbetteroff.com/api/v1/fire",
      "example": "https://farbetteroff.com/api/v1/fire?annualSpending=45000&current=30000&annualSavings=25000&rate=7",
      "calculator": "https://farbetteroff.com/calculators/fire-calculator",
      "params": [
        {
          "name": "annualSpending",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 0,
          "max": 1000000000,
          "description": "What you expect to spend per year in retirement.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        },
        {
          "name": "current",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000000000,
          "description": "Invested savings today.",
          "accepts": "number, US dollars, between 0 and 1000000000000"
        },
        {
          "name": "annualSavings",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000000,
          "description": "What you invest per year.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        },
        {
          "name": "rate",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 7,
          "min": 0,
          "max": 100,
          "description": "Real (after-inflation) annual return, so the answer is already in today's dollars.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "withdrawalRate",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 4,
          "min": 0.1,
          "max": 20,
          "description": "Withdrawal rate used to set the target.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0.1 and 20"
        }
      ],
      "returns": {
        "fireNumber": "Annual spending divided by the withdrawal rate.",
        "reached": "Whether saving gets there inside 70 years.",
        "years": "Years until the target is hit. 0 if you are already there.",
        "balances": "Balance at the end of each year, index 0 being today."
      },
      "notes": [
        "Because the rate is a real return, no separate inflation adjustment is applied — every figure is in today's dollars."
      ]
    },
    {
      "slug": "coast-fire",
      "title": "Coast FIRE",
      "summary": "The amount that, invested today, grows into your FIRE number by retirement with no further contributions.",
      "url": "https://farbetteroff.com/api/v1/coast-fire",
      "example": "https://farbetteroff.com/api/v1/coast-fire?annualSpending=45000&current=30000&annualSavings=25000&yearsToRetirement=35",
      "calculator": "https://farbetteroff.com/calculators/fire-calculator",
      "params": [
        {
          "name": "annualSpending",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 0,
          "max": 1000000000,
          "description": "Expected annual spending in retirement.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        },
        {
          "name": "current",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000000000,
          "description": "Invested savings today.",
          "accepts": "number, US dollars, between 0 and 1000000000000"
        },
        {
          "name": "annualSavings",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 1000000000,
          "description": "What you invest per year until you coast.",
          "accepts": "number, US dollars, between 0 and 1000000000"
        },
        {
          "name": "yearsToRetirement",
          "type": "integer",
          "unit": "years",
          "required": true,
          "min": 0,
          "max": 70,
          "description": "Years until you plan to retire.",
          "accepts": "integer, years, between 0 and 70"
        },
        {
          "name": "rate",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 7,
          "min": 0,
          "max": 100,
          "description": "Real (after-inflation) annual return.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "withdrawalRate",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 4,
          "min": 0.1,
          "max": 20,
          "description": "Withdrawal rate used to set the target.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0.1 and 20"
        }
      ],
      "returns": {
        "fireNumber": "The full retirement target.",
        "coastNumberToday": "Invest this much today and you can stop contributing.",
        "reached": "Whether you reach the coast point before retirement.",
        "yearsToCoast": "Years until you can stop contributing. 0 if you already can."
      }
    },
    {
      "slug": "roth-vs-traditional",
      "title": "Roth vs Traditional",
      "summary": "Which account leaves you with more after tax, compared at the same cost to you today — plus the effective federal rate a Traditional withdrawal actually pays, which is neither the bracket everyone quotes nor the 20% a plan withholds.",
      "url": "https://farbetteroff.com/api/v1/roth-vs-traditional",
      "example": "https://farbetteroff.com/api/v1/roth-vs-traditional?taxNow=22&taxRetire=22&withdrawal=60000&years=30&magi=120000",
      "calculator": "https://farbetteroff.com/calculators/roth-vs-traditional-calculator",
      "params": [
        {
          "name": "contribution",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 7500,
          "min": 0,
          "max": 100000,
          "description": "Yearly contribution, measured as **what leaves your pocket after tax**. Defaults to the 2026 IRA limit. See the notes — this is not the same as the figure you type into a brokerage form.",
          "accepts": "number, US dollars, between 0 and 100000"
        },
        {
          "name": "years",
          "type": "integer",
          "unit": "years",
          "required": false,
          "default": 30,
          "min": 1,
          "max": 60,
          "description": "Years of contributions and growth before you start withdrawing.",
          "accepts": "integer, years, between 1 and 60"
        },
        {
          "name": "rate",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 7,
          "min": 0,
          "max": 20,
          "description": "Annual return, the same for both accounts.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 20"
        },
        {
          "name": "taxNow",
          "type": "number",
          "unit": "percent",
          "required": true,
          "min": 0,
          "max": 100,
          "description": "Your marginal tax rate today — the bracket the contribution would otherwise be taxed in.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "taxRetire",
          "type": "number",
          "unit": "percent",
          "required": true,
          "min": 0,
          "max": 100,
          "description": "The rate you expect the Traditional withdrawal to pay. **Send the effective rate, not a bracket** — `withdrawal` below computes it for you.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "withdrawal",
          "type": "number",
          "unit": "usd",
          "required": false,
          "min": 0,
          "max": 10000000,
          "description": "A year's planned withdrawal from the pre-tax account. Drives the whole `retirementRate` object, which is the point of this endpoint; omit it and that comes back null.",
          "accepts": "number, US dollars, between 0 and 10000000"
        },
        {
          "name": "otherTaxableIncome",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 10000000,
          "description": "Other ordinary taxable income in the same retirement year — a pension, a spouse's wages, another account's required distribution. The withdrawal stacks on top of it, so this raises the rate. Social Security is not modelled; see the notes.",
          "accepts": "number, US dollars, between 0 and 10000000"
        },
        {
          "name": "withheldPct",
          "type": "number",
          "unit": "percent",
          "required": false,
          "min": 0,
          "max": 100,
          "description": "What the payer actually withheld, if you have the statement in front of you. Omit it and `withholding` uses the default for `account` — 20% or 10% — and flags it as assumed. Withholding is a deposit, not a rate; it changes no arithmetic above.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "account",
          "type": "enum",
          "required": false,
          "default": "plan",
          "values": [
            "plan",
            "ira"
          ],
          "description": "Where the withdrawal is paid from, which sets the default withholding when `withheldPct` is omitted. A workplace plan withholds 20% and you cannot decline it; an IRA withholds 10% and you can elect out. Selects a default only — it changes no arithmetic.",
          "accepts": "one of plan, ira"
        },
        {
          "name": "age",
          "type": "number",
          "unit": "years",
          "required": false,
          "min": 0,
          "max": 120,
          "description": "Your age **when the withdrawal is taken**, which is a different age from `age50Plus` below — that one is about this year's contribution. Halves count, because the threshold is one: 59.4 is early and 59.5 is not. Selects `ageRules`, which also needs `withdrawal`; omit it and that comes back null.",
          "accepts": "number, years, between 0 and 120"
        },
        {
          "name": "status",
          "type": "enum",
          "required": false,
          "default": "single",
          "values": [
            "single",
            "married",
            "hoh",
            "mfs"
          ],
          "description": "Filing status in retirement, which sets the standard deduction and the brackets the withdrawal fills.",
          "accepts": "one of single, married, hoh, mfs"
        },
        {
          "name": "magi",
          "type": "number",
          "unit": "usd",
          "required": false,
          "min": 0,
          "max": 100000000,
          "description": "Today's modified adjusted gross income. Selects `eligibility` only — it changes no arithmetic above. Omit it and that comes back null.",
          "accepts": "number, US dollars, between 0 and 100000000"
        },
        {
          "name": "age50Plus",
          "type": "boolean",
          "required": false,
          "default": false,
          "description": "Whether the catch-up limit applies, which raises the cap from $7,500 to $8,600. This is your age **today**, in the contribution year — `age` above is your age at the withdrawal, decades later. Affects `limitEdge` and `eligibility`.",
          "accepts": "boolean"
        }
      ],
      "returns": {
        "winner": "`\"roth\"`, `\"traditional\"` or `\"tie\"`.",
        "roth": "After-tax value of the Roth at the end. Withdrawals are tax-free, so this is the balance.",
        "traditional": "After-tax value of the Traditional at the end, net of the exit tax at `taxRetire`.",
        "difference": "`traditional − roth`. Positive means the Traditional came out ahead.",
        "edge": "The absolute difference, which is what a headline wants.",
        "tie": "True when the two land within half a percent — which is what equal tax rates produce.",
        "retirementRate": "**The correction this endpoint exists for.** The federal tax a `withdrawal` actually causes: `effectiveRatePct` against the `marginalRatePct` everyone quotes, `overstatementPct` between them, the `untaxedAmount` the standard deduction shields, and the `bands` the withdrawal itself occupies. `assumesOnlyIncome` flags the best case. Null unless `withdrawal` was sent.",
        "withholding": "**What the payer took, against what is actually owed.** `withheldPct` and the dollars `withheld`, the `tax` due on the same withdrawal, and the `gap` between them — `overwithheld` is true when that gap is positive, which means the excess comes back as a refund the following spring, having earned nothing in between. `breakEvenWithdrawal` is the withdrawal at which that withholding rate would finally be the right one; below it the payer always takes too much. `assumedPct` is true when the rate was the default for `account` rather than one you sent. Null unless `withdrawal` was sent.",
        "ageRules": "**What the two ages cost, priced.** Before 59½ an additional tax applies, and it is charged on the distribution rather than on the tax — so `penalty` can exceed `incomeTax` outright, and `allInRatePct` is simply the effective rate plus `penaltyPct`. `early` says which side of the threshold you are on, `yearsUntilPenaltyFree` how far, and `assumesNoException` flags that none of the 72(t) exceptions are modelled. The other age is reported rather than computed: `rmdAgeReached` and `yearsUntilRmd` against `rmdAge`, the age at which the withdrawal stops being a choice. Null unless both `age` and `withdrawal` were sent.",
        "limitEdge": "What the contribution cap does when you max out: the `traditionalAfterTaxCost` of the same nominal contribution, the `equivalentPreTaxContribution` that would match a full Roth, how far that `exceedsLimitBy`, and the resulting `rothAdvantagePct`. Nothing here depends on future tax rates.",
        "eligibility": "Whether this `magi` may contribute to a Roth IRA at all: the `band`, the reduced `limit` after the IRS's rounding, and the `phaseOut` range. Null unless `magi` was sent.",
        "years": "Whole years used, after rounding the `years` parameter.",
        "status": "Filing status used for the deduction, the brackets and the phase-out range, echoed.",
        "taxYear": "The tax year every bracket, deduction and limit above belongs to."
      },
      "notes": [
        "**The retirement rate people quote is a bracket, and a withdrawal is not taxed at a bracket.** A Traditional withdrawal is ordinary income filling the brackets from the bottom — the standard deduction first at 0%, then 10%, then 12%. On $60,000 withdrawn by a single filer with no other taxable income, the marginal bracket is **12%** and the effective federal rate is **8.37%**. Someone comparing \"22% now against 22% later\" and concluding it is a wash has the later figure wrong by more than the decision is worth. Send `withdrawal` and use the `effectiveRatePct` that comes back as `taxRetire`.",
        "**That rate is a floor, not a forecast, and this endpoint says so in the response.** It assumes the withdrawal is the only ordinary income that year. A pension, a spouse's wages, interest, and required distributions from any other pre-tax account all stack underneath it and push it into higher bands — the same $60,000 on top of $40,000 of other income pays **17.58%**, more than double. That is what `otherTaxableIncome` is for, and why `assumesOnlyIncome` is returned rather than assumed.",
        "**The percentage a plan withheld is not a tax rate at all, and it is usually too much.** A retirement plan distribution paid to you carries mandatory withholding of 20% — the IRS's words are \"even if you intend to roll it over later\" — so it is a deposit against a bill computed months later, identical for everyone and knowing nothing about the filer. On the $60,000 above, the plan sends $12,000 against $5,020 owed: $6,980 lent to the Treasury, earning nothing, until the return is filed. The `withholding` block measures that gap, and `breakEvenWithdrawal` says where it closes — about $239,133 withdrawn in one year by that filer, which is why over-withholding is the normal case rather than an edge case. An IRA is the contrast that proves it is a default and not a rate: 10%, and electable out — send `account=ira` for it. https://www.irs.gov/retirement-plans/plan-participant-employee/rollovers-of-retirement-plan-and-ira-distributions",
        "**The 10% before 59½ is charged on the distribution, not on the tax** — which makes it larger than the surcharge people picture. Send `age` and `ageRules` prices it: the same $60,000 taken at 50 owes $5,020 of income tax and $6,000 of additional tax — the penalty is the **bigger** of the two — for an all-in federal rate of 18.37% against the 8.37% the same withdrawal costs after 59½. Because it lands on the distribution it adds exactly its own 10 points to the rate, whatever the rate was; a withdrawal small enough to owe no income tax at all still owes it. **The 72(t) exceptions are not modelled** — disability, death, substantially equal periodic payments, qualified birth or adoption, certain medical expenses, a domestic-abuse distribution, separation from service at 55 or later for a workplace plan — so `penalty` is what applies if none of them fits, which is what `assumesNoException` says out loud. A rollover is not an early distribution: the additional tax reaches only the taxable part. https://www.irs.gov/taxtopics/tc558",
        "**RMDs are reported, not computed.** `ageRules` answers whether you have reached 73 and how many years are left, because the amount depends on a life-expectancy table and the prior 31 December balance that this endpoint does not ask for. Two timing notes that are this endpoint's own arithmetic applied to a deadline: the first RMD can be deferred to April 1 of the following year, which stacks two distributions into one calendar year and raises the effective rate on both, and a participant still working for the employer sponsoring the plan can generally delay plan RMDs until they retire unless they own 5% or more of the business. Roth IRAs have no RMDs while the owner is alive. https://www.irs.gov/retirement-plans/retirement-plan-and-ira-required-minimum-distributions-faqs",
        "**Social Security benefit taxation is not modelled**, and it is the largest thing missing. A Traditional withdrawal can raise the share of a benefit that becomes taxable, which is a second effect on top of the tax on the withdrawal itself. A retiree drawing Social Security should read `retirementRate` as an understatement.",
        "**At the same tax rate now and later the two accounts are mathematically identical**, and this endpoint returns a tie rather than a winner. `(1 − t)·(1 + r)ⁿ` and `(1 + r)ⁿ·(1 − t)` are the same number. Any calculator that shows the Roth winning at equal rates is comparing equal **contributions** rather than equal cost — which compares a larger sacrifice against a smaller one. See `contribution` above.",
        "**The cap is the one argument for the Roth that does not depend on predicting tax rates.** $7,500 into a Roth shelters $7,500 of after-tax money; the same nominal amount into a Traditional costs only $5,850 after tax at a 22% rate. Matching the Roth would take $9,615 of pre-tax money, which the cap does not allow. `limitEdge` reports that gap. The deferred tax is real and stays in your pocket, but it lands in a taxable account whose drag this endpoint does not model, so it is returned as `taxSavings` and not projected.",
        "**Federal only, and not a tax return.** No state income tax (see `/api/v1/state-tax`), no IRMAA, no Net Investment Income Tax, no credits, no age-65 additional standard deduction, and no RMD schedule. Figures are for tax year 2026: standard deduction and brackets from IRS Rev. Proc. 2025-32, limits from IRS Notice 2025-67.",
        "**The eligibility object is the Roth contribution limit only.** Whether a **Traditional** contribution is **deductible** phases out on different ranges that also depend on whether you or a spouse are covered by a workplace plan, and that is not modelled here — an undeducted Traditional contribution changes the comparison completely, so do not read a `full` band as advice about the other account. Roth phase-out ranges for 2026: $153,000–$168,000 single and head of household, $242,000–$252,000 married filing jointly, and $0–$10,000 filing separately, which never adjusts for inflation. https://www.irs.gov/newsroom/401k-limit-increases-to-24500-for-2026-ira-limit-increases-to-7500",
        "Nothing here is advice about which account to choose. The comparison is arithmetic on the rates you supply, and the rate that matters most is the one this endpoint computes rather than asks you to guess."
      ],
      "dataVintage": [
        "irs-inflation-adjustments",
        "irs-retirement-limits"
      ]
    },
    {
      "slug": "refinance",
      "title": "Mortgage refinance break-even",
      "summary": "The new payment, the monthly saving, how long it takes to earn the closing costs back, and whether resetting the term costs more interest anyway.",
      "url": "https://farbetteroff.com/api/v1/refinance",
      "example": "https://farbetteroff.com/api/v1/refinance?balance=320000&currentRate=7.25&yearsLeft=27&newRate=6&newTermYears=30&closingCosts=6000",
      "calculator": "https://farbetteroff.com/calculators/refinance-calculator",
      "params": [
        {
          "name": "balance",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 0,
          "max": 10000000000,
          "description": "What is still owed on the current mortgage.",
          "accepts": "number, US dollars, between 0 and 10000000000"
        },
        {
          "name": "currentRate",
          "type": "number",
          "unit": "percent",
          "required": true,
          "min": 0,
          "max": 100,
          "description": "The rate on the loan you have today.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "yearsLeft",
          "type": "number",
          "unit": "years",
          "required": true,
          "min": 0,
          "max": 50,
          "description": "Years remaining on the current loan.",
          "accepts": "number, years, between 0 and 50"
        },
        {
          "name": "newRate",
          "type": "number",
          "unit": "percent",
          "required": true,
          "min": 0,
          "max": 100,
          "description": "The rate you are being offered.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "newTermYears",
          "type": "integer",
          "unit": "years",
          "required": false,
          "default": 30,
          "min": 1,
          "max": 50,
          "description": "Term of the new loan, in years.",
          "accepts": "integer, years, between 1 and 50"
        },
        {
          "name": "closingCosts",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 100000000,
          "description": "Closing costs on the new loan, paid up front. Typically 2%–5% of the loan.",
          "accepts": "number, US dollars, between 0 and 100000000"
        }
      ],
      "returns": {
        "currentPayment": "Principal and interest on the loan you have.",
        "newPayment": "Principal and interest on the loan you would take.",
        "monthlySavings": "Current payment minus new payment. Negative when refinancing costs more each month.",
        "breakEvenMonths": "Months of saving needed to cover the closing costs. Null (as \"never\") when the payment goes up.",
        "breakEvenLabel": "The same figure in words, e.g. \"1 yr 6 mo\".",
        "currentInterest": "Interest left on the current loan if you keep it to the end.",
        "newInterest": "Interest on the new loan over its full term.",
        "lifetimeInterestDiff": "Current interest minus new interest. Negative means the refinance costs more interest over its life, even at a lower rate.",
        "resetsTheTerm": "True when the payment falls but the lifetime interest rises — the reset trap."
      },
      "notes": [
        "A rate-and-term refinance: both loans are measured on the same balance, so this does not model cash-out, points bought at closing, or rolling the costs into the loan.",
        "The interest figures cover each loan's own full remaining term, so they are not a like-for-like span when the terms differ. That is what makes `resetsTheTerm` visible instead of hidden.",
        "Break-even ignores what the saved payment could earn if invested, and assumes you keep the loan to payoff."
      ]
    },
    {
      "slug": "rent-vs-buy",
      "title": "Rent vs buy",
      "summary": "Net worth year by year down both paths, counting what the renter earns investing the down payment, and the year buying pulls ahead.",
      "url": "https://farbetteroff.com/api/v1/rent-vs-buy",
      "example": "https://farbetteroff.com/api/v1/rent-vs-buy?years=7&homePrice=400000&monthlyRent=2400&downPaymentPercent=20&rate=6.5",
      "calculator": "https://farbetteroff.com/calculators/rent-vs-buy-calculator",
      "params": [
        {
          "name": "years",
          "type": "integer",
          "unit": "years",
          "required": true,
          "min": 1,
          "max": 50,
          "description": "How long you would stay before selling or moving out.",
          "accepts": "integer, years, between 1 and 50"
        },
        {
          "name": "homePrice",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 0,
          "max": 10000000000,
          "description": "Purchase price.",
          "accepts": "number, US dollars, between 0 and 10000000000"
        },
        {
          "name": "monthlyRent",
          "type": "number",
          "unit": "usd",
          "required": true,
          "min": 0,
          "max": 1000000,
          "description": "Rent for a comparable place, per month, today.",
          "accepts": "number, US dollars, between 0 and 1000000"
        },
        {
          "name": "downPaymentPercent",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 20,
          "min": 0,
          "max": 100,
          "description": "Down payment as a percentage of the price.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "rate",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 6.5,
          "min": 0,
          "max": 100,
          "description": "Mortgage rate (APR).",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        },
        {
          "name": "termYears",
          "type": "integer",
          "unit": "years",
          "required": false,
          "default": 30,
          "min": 1,
          "max": 50,
          "description": "Length of the mortgage.",
          "accepts": "integer, years, between 1 and 50"
        },
        {
          "name": "homeGrowth",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 4,
          "min": -20,
          "max": 30,
          "description": "Annual home appreciation. May be negative.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between -20 and 30"
        },
        {
          "name": "rentGrowth",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 3,
          "min": -20,
          "max": 30,
          "description": "Annual rent increase, applied on each anniversary.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between -20 and 30"
        },
        {
          "name": "investReturn",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 7,
          "min": 0,
          "max": 30,
          "description": "What invested cash earns annually — the down payment's opportunity cost.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 30"
        },
        {
          "name": "propertyTaxPercent",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 1.1,
          "min": 0,
          "max": 10,
          "description": "Property tax per year, as a percentage of the home's current value.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 10"
        },
        {
          "name": "maintenancePercent",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 1,
          "min": 0,
          "max": 10,
          "description": "Maintenance per year, as a percentage of the home's current value.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 10"
        },
        {
          "name": "insuranceAnnual",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 1800,
          "min": 0,
          "max": 1000000,
          "description": "Homeowner's insurance per year.",
          "accepts": "number, US dollars, between 0 and 1000000"
        },
        {
          "name": "hoaMonthly",
          "type": "number",
          "unit": "usd",
          "required": false,
          "default": 0,
          "min": 0,
          "max": 100000,
          "description": "HOA dues per month.",
          "accepts": "number, US dollars, between 0 and 100000"
        },
        {
          "name": "buyClosingPercent",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 2,
          "min": 0,
          "max": 20,
          "description": "Buying costs paid up front, as a percentage of the price.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 20"
        },
        {
          "name": "sellClosingPercent",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 6,
          "min": 0,
          "max": 20,
          "description": "Selling costs, as a percentage of the sale price — agent commission and closing.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 20"
        },
        {
          "name": "pmiRatePct",
          "type": "number",
          "unit": "percent",
          "required": false,
          "default": 0.5,
          "min": 0,
          "max": 5,
          "description": "Annual private mortgage insurance as a percent of the loan, charged only when the down payment leaves the loan above 80% of the price. Defaults to 0.5%, mid-range for the $30–$70 a month per $100,000 borrowed Freddie Mac describes. Send `pmiRatePct=0` for a comparison with no mortgage insurance in it — the right call for a VA loan.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 5"
        }
      ],
      "returns": {
        "verdict": "\"buy\", \"rent\", or \"toss-up\" when the two land within half a percent of the price.",
        "difference": "Buyer's net worth minus renter's at the end of the stay. Positive means buying won.",
        "breakEvenYear": "First year the buyer's net worth catches the renter's. Null when it never happens inside the stay.",
        "buyerNetWorth": "Net worth if you buy: today, then one entry per year. Home equity after selling costs, plus investments.",
        "renterNetWorth": "Net worth if you rent, over the same points — the invested down payment and every month renting was cheaper.",
        "monthlyPayment": "Principal and interest on the mortgage.",
        "loanAmount": "The mortgage itself — home price less the down payment.",
        "remainingBalance": "What is still owed on that mortgage at the end of the stay.",
        "years": "The length of the stay the comparison was run over, echoed back because every other figure is measured at its end.",
        "finalHomeValue": "What the home is worth at the end of the stay.",
        "totals": "What was spent over the whole stay: rent, mortgage interest, property tax, maintenance, insurance, HOA, and PMI.",
        "upfront": "Down payment, buying costs, and the selling costs owed at the end.",
        "pmi": "Null when no mortgage insurance is charged. Otherwise the monthly premium, the month it comes off, and what it costs inside the stay."
      },
      "notes": [
        "Both people start with the same cash. The buyer spends it on the down payment and buying costs; the renter invests it at `investReturn`, and each month the cheaper path invests the difference. That opportunity cost is what most rent-vs-buy comparisons leave out.",
        "The buyer's net worth is equity after selling costs, so it is what they would walk away with — which is why buying normally starts well behind.",
        "Annual rates compound monthly ((1 + r)^(1/12) − 1), so 7% means 7% a year, not 7%/12 a month.",
        "**PMI is charged below 20% down, and it is the cost that moves this answer most.** The premium falls entirely in the early years, which is where the break-even lives: on `years=7&homePrice=400000&monthlyRent=2400&downPaymentPercent=5&rate=6.5` it is $158.33 a month for 135 months — $13,300 inside a 7-year stay — and it moves `breakEvenYear` from 5 to 6 and `difference` from $26,559 to $9,595, which is more than the premium itself because the renter invests every month owning costs more. It stops on the CFPB's automatic termination date — the month the scheduled balance reaches 78% of the price, with the loan's midpoint as a backstop — the same date /api/v1/pmi returns for the same loan. `pmiRatePct=0` turns it off.",
        "Not modelled: the mortgage interest deduction, and capital-gains treatment on the sale. Each needs assumptions about one person's taxes, and each moves the answer."
      ]
    },
    {
      "slug": "rule-of-72",
      "title": "Rule of 72",
      "summary": "Roughly how long money takes to double at a given rate, and the exact answer beside it.",
      "url": "https://farbetteroff.com/api/v1/rule-of-72",
      "example": "https://farbetteroff.com/api/v1/rule-of-72?rate=8",
      "calculator": "https://farbetteroff.com/calculators/compound-interest-calculator",
      "params": [
        {
          "name": "rate",
          "type": "number",
          "unit": "percent",
          "required": true,
          "min": 0,
          "max": 100,
          "description": "Annual rate of return.",
          "accepts": "number, a percentage, so 6.5 means 6.5%, between 0 and 100"
        }
      ],
      "returns": {
        "years": "72 divided by the rate. Null at or below 0%, where money never doubles.",
        "exactYears": "The precise answer, ln(2) / ln(1 + r), for comparison."
      },
      "notes": [
        "The Rule of 72 is a mental-arithmetic approximation. It is accurate to within a few months over the 5%–12% range and drifts outside it — `exactYears` is the number to use when precision matters."
      ]
    }
  ],
  "datasets": [
    {
      "slug": "rates",
      "title": "Today's US consumer interest rates",
      "summary": "The nine national average rates the site runs on, each with its own reading date: 30- and 15-year fixed mortgages, the Fed funds target, the savings and 12-month CD averages, the 10-year Treasury, and the Federal Reserve's credit card, new-car and personal-loan averages. Every row names the body that published it — Freddie Mac, the FDIC or the Federal Reserve Board — rather than the aggregator it was read through. Takes no parameters; refetched every six hours.",
      "url": "https://farbetteroff.com/api/v1/rates",
      "page": "https://farbetteroff.com/rates",
      "sources": [
        {
          "label": "Freddie Mac PMMS",
          "url": "https://www.freddiemac.com/pmms"
        },
        {
          "label": "FDIC national rates",
          "url": "https://www.fdic.gov/national-rates-and-rate-caps"
        },
        {
          "label": "Federal Reserve H.15",
          "url": "https://www.federalreserve.gov/releases/h15/"
        },
        {
          "label": "Federal Reserve G.19",
          "url": "https://www.federalreserve.gov/releases/g19/current/"
        },
        {
          "label": "FOMC target rate",
          "url": "https://www.federalreserve.gov/monetarypolicy/openmarket.htm"
        }
      ],
      "refreshSeconds": 21600
    },
    {
      "slug": "income-needed-to-buy-a-house",
      "title": "Income needed to buy the median new home in the United States",
      "summary": "The gross household income the 28% front-end ratio asks for on the median-priced new home at the current 30-year fixed rate, with the payment broken out, the same answer on 10% down, and the price the median household income actually reaches. Takes no parameters; rebuilt every six hours from three public series.",
      "url": "https://farbetteroff.com/api/v1/income-needed-to-buy-a-house",
      "page": "https://farbetteroff.com/income-needed-to-buy-a-house",
      "sources": [
        {
          "label": "MSPUS",
          "url": "https://fred.stlouisfed.org/series/MSPUS"
        },
        {
          "label": "MORTGAGE30US",
          "url": "https://fred.stlouisfed.org/series/MORTGAGE30US"
        },
        {
          "label": "MEHOINUSA646N",
          "url": "https://fred.stlouisfed.org/series/MEHOINUSA646N"
        }
      ],
      "refreshSeconds": 21600
    },
    {
      "slug": "state-income-tax-rates",
      "title": "State income tax on wages, 2026",
      "summary": "What each of the 50 states and the District of Columbia charges on a paycheck: the 9 that levy no individual income tax on wages, the 16 with one statutory rate, the 4 whose published bracket schedules are modelled in full, and the 22 where the row is an explicit refusal rather than a number. Every verified row carries its revenue department's own page, its standard deduction, its zero band or surtax where it has one, and a top marginal rate. Takes no parameters.",
      "url": "https://farbetteroff.com/api/v1/state-income-tax-rates",
      "page": "https://farbetteroff.com/state-income-tax-rates",
      "sources": [
        {
          "label": "State revenue departments",
          "url": "https://www.taxadmin.org/state-tax-agencies"
        }
      ],
      "refreshSeconds": 21600
    },
    {
      "slug": "money-numbers",
      "title": "The 2026 money numbers",
      "summary": "The 2026 US contribution limits, deductions and rates in one call: 401(k), IRA and HSA limits, the standard deduction and the senior deduction, the gift exclusion, the Social Security COLA, wage base and full retirement age, and I bond and FDIC figures. Every figure carries the notice, revenue procedure or section of the US Code that set it. Takes no parameters.",
      "url": "https://farbetteroff.com/api/v1/money-numbers",
      "page": "https://farbetteroff.com/money-numbers",
      "sources": [
        {
          "label": "IRS Notice 2025-67",
          "url": "https://www.irs.gov/pub/irs-drop/n-25-67.pdf"
        },
        {
          "label": "IRS Rev. Proc. 2025-32",
          "url": "https://www.irs.gov/pub/irs-drop/rp-25-32.pdf"
        },
        {
          "label": "IRS Rev. Proc. 2025-19",
          "url": "https://www.irs.gov/pub/irs-drop/rp-25-19.pdf"
        },
        {
          "label": "90 FR 49047",
          "url": "https://www.federalregister.gov/documents/2025/11/03/2025-19763/cost-of-living-increase-and-other-determinations-for-2026"
        },
        {
          "label": "26 U.S.C. § 151",
          "url": "https://uscode.house.gov/view.xhtml?req=granuleid:USC-prelim-title26-section151&num=0&edition=prelim"
        },
        {
          "label": "TreasuryDirect I bonds",
          "url": "https://www.treasurydirect.gov/savings-bonds/i-bonds/i-bonds-interest-rates/"
        },
        {
          "label": "FDIC deposit insurance",
          "url": "https://www.fdic.gov/resources/deposit-insurance/"
        }
      ],
      "refreshSeconds": 21600
    }
  ],
  "dataVintages": [
    {
      "id": "fed-scf",
      "publisher": "Federal Reserve Board",
      "edition": "Changes in U.S. Family Finances from 2019 to 2022",
      "dataYear": 2022,
      "cycleYears": 3,
      "supersededFrom": "2026-12-01",
      "source": "https://www.federalreserve.gov/econres/scfindex.htm"
    },
    {
      "id": "irs-inflation-adjustments",
      "publisher": "Internal Revenue Service",
      "edition": "Rev. Proc. 2025-32 (tax year 2026)",
      "dataYear": 2026,
      "cycleYears": 1,
      "supersededFrom": "2027-01-01",
      "source": "https://www.irs.gov/newsroom/irs-releases-tax-inflation-adjustments-for-tax-year-2026-including-amendments-from-the-one-big-beautiful-bill"
    },
    {
      "id": "irs-retirement-limits",
      "publisher": "Internal Revenue Service",
      "edition": "Notice 2025-67 (retirement plan limits for 2026)",
      "dataYear": 2026,
      "cycleYears": 1,
      "supersededFrom": "2027-01-01",
      "source": "https://www.irs.gov/retirement-plans/plan-participant-employee/retirement-topics-401k-and-profit-sharing-plan-contribution-limits"
    },
    {
      "id": "social-security-wage-base",
      "publisher": "Social Security Administration (via IRS Topic no. 751)",
      "edition": "2026 wage base, $184,500",
      "dataYear": 2026,
      "cycleYears": 1,
      "supersededFrom": "2027-01-01",
      "source": "https://www.irs.gov/taxtopics/tc751"
    },
    {
      "id": "state-wage-tax-rates",
      "publisher": "State revenue departments",
      "edition": "Rates in force for 2026",
      "dataYear": 2026,
      "cycleYears": 1,
      "supersededFrom": "2027-01-01",
      "source": "https://www.taxadmin.org/state-tax-agencies"
    },
    {
      "id": "state-payroll-contribution-rates",
      "publisher": "State labor and employment agencies",
      "edition": "Employee contribution rates for calendar year 2026",
      "dataYear": 2026,
      "cycleYears": 1,
      "supersededFrom": "2027-01-01",
      "source": "https://edd.ca.gov/en/payroll_taxes/rates_and_withholding/"
    },
    {
      "id": "qm-price-thresholds",
      "publisher": "Consumer Financial Protection Bureau",
      "edition": "90 FR 57890, effective 1 January 2026",
      "dataYear": 2026,
      "cycleYears": 1,
      "supersededFrom": "2027-01-01",
      "source": "https://www.consumerfinance.gov/rules-policy/regulations/1026/43/"
    },
    {
      "id": "fed-shed",
      "publisher": "Federal Reserve Board",
      "edition": "Economic Well-Being of U.S. Households in 2025",
      "dataYear": 2025,
      "cycleYears": 1,
      "supersededFrom": "2027-06-01",
      "source": "https://www.federalreserve.gov/consumerscommunities/shed.htm"
    },
    {
      "id": "local-wage-tax-rates",
      "publisher": "City revenue departments",
      "edition": "City wage tax rates in force from 2026-07-01",
      "dataYear": 2026,
      "cycleYears": 1,
      "supersededFrom": "2027-08-01",
      "source": "https://www.phila.gov/services/payments-assistance-taxes/taxes/business-taxes/business-taxes-by-type/wage-tax-employers/"
    },
    {
      "id": "irs-transportation-standards",
      "publisher": "Internal Revenue Service",
      "edition": "Collection Financial Standards, transportation, effective 2026-06-29",
      "dataYear": 2026,
      "cycleYears": 1,
      "supersededFrom": "2027-09-01",
      "source": "https://www.irs.gov/businesses/small-businesses-self-employed/local-standards-transportation"
    }
  ]
}
