{
  "schemaVersion": 1,
  "slug": "mortgage-calculator",
  "category": "finance",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "19658b18dba8239ac4579aa13bcd6305094b75033cc032d9d53690e35f59e0ac",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/mortgage-calculator.json",
    "src/engine.js"
  ],
  "runtimeSource": "/sources/engine.txt",
  "runtimeHash": "5c888d8898afbdee36267bb9977829e1e2ac568f6677c8ee87469c139864645c",
  "scope": "The compute function records implemented equations, constants, lookup tables and custom rules. Inputs record defaults and allowed values; outputs record precision and units. Defaults are examples, not recommendations. General background references are not evidence for this specific algorithm.",
  "publishedFormula": {
    "formula": "M = P · r(1+r)^n / ((1+r)^n − 1)",
    "vars": [
      [
        "M",
        "Monthly principal-and-interest payment"
      ],
      [
        "P",
        "Loan principal — home price minus down payment"
      ],
      [
        "r",
        "Monthly interest rate — annual rate divided by 12, as a decimal"
      ],
      [
        "n",
        "Total number of monthly payments — term in years multiplied by 12"
      ]
    ],
    "note": "This is a fixed-rate, equal monthly principal-and-interest model. At a 0% rate, M = P/n. Property tax is entered as a constant percentage of the original home price; annual insurance is divided by 12. The displayed total monthly cost is the first month’s estimate: scheduled principal and interest (plus any extra principal, capped at the payoff amount), tax, insurance, entered HOA, and entered PMI only while the simulated balance exceeds 80% of the entered home price. PMI months are a model estimate, not a lender cancellation date. Total interest and time saved reflect extra principal; closing costs, rate changes, tax/insurance changes, escrow rules and prepayment penalties are excluded. Compare an actual Loan Estimate and loan terms."
  },
  "externalEvidence": {
    "reviewedAt": "2026-09-27",
    "sources": [
      {
        "name": "CFPB — Fixed-rate mortgage payments",
        "url": "https://www.consumerfinance.gov/ask-cfpb/how-do-mortgage-lenders-calculate-monthly-payments-en-1965/"
      },
      {
        "name": "CFPB — Principal, interest and total monthly payment",
        "url": "https://www.consumerfinance.gov/ask-cfpb/on-a-mortgage-whats-the-difference-between-my-principal-and-interest-payment-and-my-total-monthly-payment-en-1941/"
      },
      {
        "name": "CFPB — PMI cancellation rules and exceptions",
        "url": "https://www.consumerfinance.gov/ask-cfpb/when-can-i-remove-private-mortgage-insurance-pmi-from-my-loan-en-202/"
      }
    ]
  },
  "contract": {
    "compute": "if(!Number.isFinite(homePrice)||homePrice<=0||!Number.isFinite(downPayment)||downPayment<0||downPayment>homePrice)return{monthlyPI:null,monthlyTax:null,monthlyInsurance:null,monthlyTotal:null,totalInterest:null,payoffMonths:null,monthsSaved:null,interestSaved:null,pmiMonths:null,__error:'inputError'};const loan = Math.max(homePrice - downPayment, 0);\nconst r = rate / 100 / 12;\nconst n = Math.max(1, Math.round(years * 12));\nconst pi = loan <= 0 ? 0 : r ? loan * r * Math.pow(1 + r, n) / (Math.pow(1 + r, n) - 1) : loan / n;\nconst monthlyTax = Math.max(0, homePrice * taxRate / 100 / 12);\nconst monthlyInsurance = Math.max(0, insurance / 12);\nconst monthlyPMI = loan > homePrice * 0.8 ? Math.max(0, pmiMonthly) : 0;\nconst monthlyHOA = Math.max(0, hoaMonthly);\nconst extra = Math.max(0, extraPayment);\nconst firstPaymentPI = loan > 0 ? Math.min(pi + extra, loan * (1 + r)) : 0;\nlet balance = loan, totalInterest = 0, months = 0, pmiMonths = 0;\nwhile (balance > 0.005 && months < n) {\n  const interest = balance * r;\n  const scheduledPrincipal = Math.max(0, pi - interest);\n  const principalPaid = Math.min(balance, scheduledPrincipal + extra);\n  if (monthlyPMI > 0 && balance > homePrice * 0.8) pmiMonths++;\n  balance -= principalPaid;\n  totalInterest += interest;\n  months++;\n  if (principalPaid <= 0) break;\n}\nconst baseInterest = Math.max(0, pi * n - loan);\nconst savedInterest = Math.max(0, baseInterest - totalInterest);\nreturn {\n  monthlyPI: pi,\n  monthlyTax,\n  monthlyInsurance,\n  monthlyTotal: firstPaymentPI + monthlyTax + monthlyInsurance + monthlyPMI + monthlyHOA,\n  totalInterest,\n  payoffMonths: months,\n  monthsSaved: loan > 0 ? Math.max(0, n - months) : 0,\n  interestSaved: savedInterest > 0.005 ? savedInterest : 0,\n  pmiMonths\n};",
    "inputs": [
      {
        "name": "homePrice",
        "type": "number",
        "default": 400000,
        "min": 0,
        "max": 100000000,
        "step": 1000
      },
      {
        "name": "downPayment",
        "type": "number",
        "default": 80000,
        "min": 0,
        "max": 100000000,
        "step": 1000
      },
      {
        "name": "rate",
        "type": "number",
        "default": 6.5,
        "min": 0,
        "max": 30,
        "step": 0.01,
        "slider": true
      },
      {
        "name": "years",
        "type": "number",
        "default": 30,
        "min": 1,
        "max": 50,
        "step": 1,
        "slider": true
      },
      {
        "name": "taxRate",
        "type": "number",
        "default": 1.2,
        "min": 0,
        "max": 10,
        "step": 0.05,
        "slider": true
      },
      {
        "name": "insurance",
        "type": "number",
        "default": 1400,
        "min": 0,
        "max": 100000,
        "step": 50,
        "slider": true
      },
      {
        "name": "pmiMonthly",
        "type": "number",
        "default": 0,
        "min": 0,
        "max": 100000,
        "step": 10,
        "advanced": true
      },
      {
        "name": "hoaMonthly",
        "type": "number",
        "default": 0,
        "min": 0,
        "max": 100000,
        "step": 10,
        "advanced": true
      },
      {
        "name": "extraPayment",
        "type": "number",
        "default": 0,
        "min": 0,
        "max": 1000000,
        "step": 50,
        "advanced": true
      }
    ],
    "outputs": [
      {
        "name": "monthlyPI",
        "precision": 2,
        "unit": "$"
      },
      {
        "name": "monthlyTax",
        "precision": 2,
        "unit": "$"
      },
      {
        "name": "monthlyInsurance",
        "precision": 2,
        "unit": "$"
      },
      {
        "name": "monthlyTotal",
        "precision": 2,
        "unit": "$"
      },
      {
        "name": "totalInterest",
        "precision": 2,
        "unit": "$"
      },
      {
        "name": "payoffMonths",
        "precision": 0
      },
      {
        "name": "monthsSaved",
        "precision": 0
      },
      {
        "name": "interestSaved",
        "precision": 2,
        "unit": "$"
      },
      {
        "name": "pmiMonths",
        "precision": 0
      }
    ],
    "interpret": null
  }
}
