{
  "schemaVersion": 1,
  "slug": "apr-calculator",
  "category": "finance",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "a206aab3831e4151a0fc0cd2eb6b0b88c552449078c19960121f1082425fe46a",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/apr-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": "PMT × (1 − (1+i)^−n) ÷ i = A − F; i ∈ [0, 1]; APR = 12i × 100",
    "vars": [
      [
        "i",
        "monthly rate solved for (decimal)"
      ],
      [
        "PMT",
        "monthly payment at the note rate"
      ],
      [
        "n",
        "number of payments"
      ],
      [
        "A",
        "loan amount"
      ],
      [
        "F",
        "fees"
      ]
    ],
    "note": "PMT uses r = note rate % ÷ 100 ÷ 12; i is found by bisection on [0,1] over 200 iterations; APR includes fees."
  },
  "externalEvidence": {
    "reviewedAt": "2026-10-12",
    "sources": [
      {
        "name": "CFPB — Interest rate and APR",
        "url": "https://www.consumerfinance.gov/ask-cfpb/what-is-the-difference-between-a-mortgage-interest-rate-and-an-apr-en-135/"
      }
    ],
    "referenceRole": "definition",
    "implementationHash": "a206aab3831e4151a0fc0cd2eb6b0b88c552449078c19960121f1082425fe46a",
    "basis": "PMT × (1 − (1+i)^−n) ÷ i = A − F; i ∈ [0, 1]; APR = 12i × 100",
    "limitations": "The references explain definitions and methods; any extra preset must be checked against the assumptions on this page."
  },
  "contract": {
    "compute": "if (amount <= 0 || fees >= amount) return { apr: null, monthly: null, totalInterest: null, __error: 'apr' }; const n=years*12, r=rate/100/12; const pmt = r ? amount*r*Math.pow(1+r,n)/(Math.pow(1+r,n)-1) : amount/n; const net = amount - fees; const pv = (i)=> i ? pmt*(1-Math.pow(1+i,-n))/i : pmt*n; let lo=0, hi=1; while (pv(hi)>net && hi<1e12) hi*=2; if (pv(hi)>net) return { apr: null, monthly: null, totalInterest: null, __error: 'apr' }; for(let k=0;k<200;k++){ const mid=(lo+hi)/2; if(pv(mid)>net) lo=mid; else hi=mid; } return { apr:((lo+hi)/2)*12*100, monthly:pmt, totalInterest:pmt*n-amount };",
    "inputs": [
      {
        "name": "amount",
        "type": "number",
        "default": 20000,
        "min": 1,
        "max": 100000000,
        "step": 1000
      },
      {
        "name": "rate",
        "type": "number",
        "default": 6,
        "min": 0,
        "max": 100,
        "step": 0.01
      },
      {
        "name": "years",
        "type": "number",
        "default": 5,
        "min": 1,
        "max": 50,
        "step": 1,
        "slider": true
      },
      {
        "name": "fees",
        "type": "number",
        "default": 500,
        "min": 0,
        "max": 100000,
        "step": 50,
        "slider": true
      }
    ],
    "outputs": [
      {
        "name": "apr",
        "precision": 2,
        "unit": "%"
      },
      {
        "name": "monthly",
        "precision": 2,
        "unit": "$"
      },
      {
        "name": "totalInterest",
        "precision": 2,
        "unit": "$"
      }
    ],
    "interpret": null
  }
}
