{
  "openapi": "3.1.0",
  "info": {
    "title": "Economicium calculators",
    "description": "Free finance and trading calculators - position sizing, risk/reward, margin, liquidation price, pivot points, RMD, I bonds, Coast FIRE, inflation and more. Every endpoint is stateless (no accounts, no persisted data) and runs the exact formulas shown on the corresponding page at economicium.com.",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://economicium.com"
    }
  ],
  "paths": {
    "/api/tools/risk-reward": {
      "get": {
        "operationId": "risk_reward",
        "summary": "Risk/reward ratio",
        "description": "Reward:risk ratio, breakeven win rate, and expectancy in R multiples from an entry, stop and target.",
        "parameters": [
          {
            "name": "entry",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "stop",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "target",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "winRatePct",
            "in": "query",
            "required": true,
            "description": "Expected win rate, 0-100",
            "schema": {
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Computed result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/tools/position-size": {
      "get": {
        "operationId": "position_size",
        "summary": "Position size",
        "description": "Lot size, units and per-lot pip value from account risk, a stop distance, and an instrument.",
        "parameters": [
          {
            "name": "symbol",
            "in": "query",
            "required": true,
            "description": "Instrument symbol. One of: EURUSD (EUR/USD), GBPUSD (GBP/USD), USDJPY (USD/JPY), USDCHF (USD/CHF), AUDUSD (AUD/USD), USDCAD (USD/CAD), NZDUSD (NZD/USD), EURGBP (EUR/GBP), EURJPY (EUR/JPY), GBPJPY (GBP/JPY), XAUUSD (Gold (XAU/USD)), XAGUSD (Silver (XAG/USD)), USOIL (WTI Crude (USOIL)), US30 (Dow Jones (US30)), NAS100 (Nasdaq 100 (NAS100)), SPX500 (S&P 500 (SPX500)), GER40 (DAX (GER40)), BTCUSD (Bitcoin (BTC/USD)), ETHUSD (Ethereum (ETH/USD))",
            "schema": {
              "type": "string",
              "enum": [
                "EURUSD",
                "GBPUSD",
                "USDJPY",
                "USDCHF",
                "AUDUSD",
                "USDCAD",
                "NZDUSD",
                "EURGBP",
                "EURJPY",
                "GBPJPY",
                "XAUUSD",
                "XAGUSD",
                "USOIL",
                "US30",
                "NAS100",
                "SPX500",
                "GER40",
                "BTCUSD",
                "ETHUSD"
              ]
            }
          },
          {
            "name": "accountBalance",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "riskPct",
            "in": "query",
            "required": true,
            "description": "Percent of the account to risk, e.g. 1 for 1%",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "stopDistance",
            "in": "query",
            "required": true,
            "description": "Stop distance in price units (pips x pip size, or |entry - stop|)",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "accountCurrency",
            "in": "query",
            "required": false,
            "description": "Account currency, e.g. \"USD\". Defaults to the instrument's own quote currency.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "contractSize",
            "in": "query",
            "required": false,
            "description": "Override the instrument's default contract size",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "conversionRate",
            "in": "query",
            "required": false,
            "description": "Override the quote-to-account conversion rate",
            "schema": {
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Computed result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/tools/pip-value": {
      "get": {
        "operationId": "pip_value",
        "summary": "Pip value",
        "description": "Cash value of one pip/point for a given instrument, lot size and account currency.",
        "parameters": [
          {
            "name": "symbol",
            "in": "query",
            "required": true,
            "description": "Instrument symbol. One of: EURUSD (EUR/USD), GBPUSD (GBP/USD), USDJPY (USD/JPY), USDCHF (USD/CHF), AUDUSD (AUD/USD), USDCAD (USD/CAD), NZDUSD (NZD/USD), EURGBP (EUR/GBP), EURJPY (EUR/JPY), GBPJPY (GBP/JPY), XAUUSD (Gold (XAU/USD)), XAGUSD (Silver (XAG/USD)), USOIL (WTI Crude (USOIL)), US30 (Dow Jones (US30)), NAS100 (Nasdaq 100 (NAS100)), SPX500 (S&P 500 (SPX500)), GER40 (DAX (GER40)), BTCUSD (Bitcoin (BTC/USD)), ETHUSD (Ethereum (ETH/USD))",
            "schema": {
              "type": "string",
              "enum": [
                "EURUSD",
                "GBPUSD",
                "USDJPY",
                "USDCHF",
                "AUDUSD",
                "USDCAD",
                "NZDUSD",
                "EURGBP",
                "EURJPY",
                "GBPJPY",
                "XAUUSD",
                "XAGUSD",
                "USOIL",
                "US30",
                "NAS100",
                "SPX500",
                "GER40",
                "BTCUSD",
                "ETHUSD"
              ]
            }
          },
          {
            "name": "lots",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "accountCurrency",
            "in": "query",
            "required": false,
            "description": "Account currency, e.g. \"USD\". Defaults to the instrument's own quote currency.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "contractSize",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "pipSize",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Computed result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/tools/margin": {
      "get": {
        "operationId": "margin",
        "summary": "Required margin",
        "description": "Notional value, required margin, and effective leverage for a leveraged position.",
        "parameters": [
          {
            "name": "symbol",
            "in": "query",
            "required": true,
            "description": "Instrument symbol. One of: EURUSD (EUR/USD), GBPUSD (GBP/USD), USDJPY (USD/JPY), USDCHF (USD/CHF), AUDUSD (AUD/USD), USDCAD (USD/CAD), NZDUSD (NZD/USD), EURGBP (EUR/GBP), EURJPY (EUR/JPY), GBPJPY (GBP/JPY), XAUUSD (Gold (XAU/USD)), XAGUSD (Silver (XAG/USD)), USOIL (WTI Crude (USOIL)), US30 (Dow Jones (US30)), NAS100 (Nasdaq 100 (NAS100)), SPX500 (S&P 500 (SPX500)), GER40 (DAX (GER40)), BTCUSD (Bitcoin (BTC/USD)), ETHUSD (Ethereum (ETH/USD))",
            "schema": {
              "type": "string",
              "enum": [
                "EURUSD",
                "GBPUSD",
                "USDJPY",
                "USDCHF",
                "AUDUSD",
                "USDCAD",
                "NZDUSD",
                "EURGBP",
                "EURJPY",
                "GBPJPY",
                "XAUUSD",
                "XAGUSD",
                "USOIL",
                "US30",
                "NAS100",
                "SPX500",
                "GER40",
                "BTCUSD",
                "ETHUSD"
              ]
            }
          },
          {
            "name": "lots",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "price",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "leverage",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "accountCurrency",
            "in": "query",
            "required": false,
            "description": "Account currency, e.g. \"USD\". Defaults to the instrument's own quote currency.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "accountEquity",
            "in": "query",
            "required": false,
            "description": "Used to compute effective leverage and % of equity used",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "contractSize",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Computed result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/tools/profit-loss": {
      "get": {
        "operationId": "profit_loss",
        "summary": "Trade profit/loss",
        "description": "Cash result, pips, and return-on-margin for a closed or hypothetical trade.",
        "parameters": [
          {
            "name": "symbol",
            "in": "query",
            "required": true,
            "description": "Instrument symbol. One of: EURUSD (EUR/USD), GBPUSD (GBP/USD), USDJPY (USD/JPY), USDCHF (USD/CHF), AUDUSD (AUD/USD), USDCAD (USD/CAD), NZDUSD (NZD/USD), EURGBP (EUR/GBP), EURJPY (EUR/JPY), GBPJPY (GBP/JPY), XAUUSD (Gold (XAU/USD)), XAGUSD (Silver (XAG/USD)), USOIL (WTI Crude (USOIL)), US30 (Dow Jones (US30)), NAS100 (Nasdaq 100 (NAS100)), SPX500 (S&P 500 (SPX500)), GER40 (DAX (GER40)), BTCUSD (Bitcoin (BTC/USD)), ETHUSD (Ethereum (ETH/USD))",
            "schema": {
              "type": "string",
              "enum": [
                "EURUSD",
                "GBPUSD",
                "USDJPY",
                "USDCHF",
                "AUDUSD",
                "USDCAD",
                "NZDUSD",
                "EURGBP",
                "EURJPY",
                "GBPJPY",
                "XAUUSD",
                "XAGUSD",
                "USOIL",
                "US30",
                "NAS100",
                "SPX500",
                "GER40",
                "BTCUSD",
                "ETHUSD"
              ]
            }
          },
          {
            "name": "direction",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "buy",
                "sell"
              ]
            }
          },
          {
            "name": "lots",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "entry",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "exit",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "accountCurrency",
            "in": "query",
            "required": false,
            "description": "Account currency, e.g. \"USD\". Defaults to the instrument's own quote currency.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "leverage",
            "in": "query",
            "required": false,
            "description": "Used to compute return-on-margin; omit to skip that figure",
            "schema": {
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Computed result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/tools/compounding": {
      "get": {
        "operationId": "compounding",
        "summary": "Compounding growth",
        "description": "Account growth curve, total return and the gain from compounding vs. simple interest.",
        "parameters": [
          {
            "name": "start",
            "in": "query",
            "required": true,
            "description": "Starting balance",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "ratePct",
            "in": "query",
            "required": true,
            "description": "Return per period, as a percent, e.g. 1 for 1%",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "periods",
            "in": "query",
            "required": true,
            "description": "Number of periods to compound over (max 600)",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "contribution",
            "in": "query",
            "required": false,
            "description": "Recurring contribution added each period",
            "schema": {
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Computed result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/tools/pivot-points": {
      "get": {
        "operationId": "pivot_points",
        "summary": "Pivot points",
        "description": "Classic, Fibonacci, Camarilla and Woodie support/resistance levels from a prior high, low and close.",
        "parameters": [
          {
            "name": "high",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "low",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "close",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Computed result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/tools/fibonacci": {
      "get": {
        "operationId": "fibonacci_levels",
        "summary": "Fibonacci retracement/extension levels",
        "description": "Retracement (0-100%) and extension (127.2-261.8%) price levels for a swing high/low.",
        "parameters": [
          {
            "name": "high",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "low",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "required": true,
            "description": "The swing's own direction",
            "schema": {
              "type": "string",
              "enum": [
                "up",
                "down"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Computed result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/tools/liquidation": {
      "get": {
        "operationId": "liquidation_price",
        "summary": "Liquidation price",
        "description": "Estimated liquidation price and distance from entry for a leveraged crypto position.",
        "parameters": [
          {
            "name": "side",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "long",
                "short"
              ]
            }
          },
          {
            "name": "mode",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "cross",
                "isolated"
              ]
            }
          },
          {
            "name": "entry",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "leverage",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "maintenanceMarginRatePct",
            "in": "query",
            "required": true,
            "description": "Exchange maintenance margin rate, as a percent",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "qty",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "crossBalance",
            "in": "query",
            "required": false,
            "description": "Wallet balance backing the position, cross mode only",
            "schema": {
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Computed result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/tools/rmd": {
      "get": {
        "operationId": "rmd",
        "summary": "Required minimum distribution",
        "description": "This year's RMD from a prior-year-end IRA/employer-plan balance and age, per the IRS Uniform Lifetime Table.",
        "parameters": [
          {
            "name": "priorYearBalance",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "age",
            "in": "query",
            "required": true,
            "description": "Age at the end of this year",
            "schema": {
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Computed result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/tools/ibond": {
      "get": {
        "operationId": "ibond_value",
        "summary": "Series I savings bond value",
        "description": "Accrued and redeemable value of a Series I savings bond, from its issue month, face value and an as-of month.",
        "parameters": [
          {
            "name": "issueMonth",
            "in": "query",
            "required": true,
            "description": "YYYY-MM",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "asOfMonth",
            "in": "query",
            "required": true,
            "description": "YYYY-MM",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "faceValue",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Computed result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/tools/financial-health-score": {
      "get": {
        "operationId": "financial_health_score",
        "summary": "Financial health score",
        "description": "A 0-100 score from savings rate, emergency fund coverage and debt-to-income, each against a named benchmark.",
        "parameters": [
          {
            "name": "monthlyIncome",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "monthlyExpenses",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "emergencyFund",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "monthlyDebtPayments",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Computed result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/tools/real-wage": {
      "get": {
        "operationId": "real_wage",
        "summary": "Real wage / did my raise beat inflation",
        "description": "Whether a pay change kept pace with inflation, in real (inflation-adjusted) terms, using annual US CPI.",
        "parameters": [
          {
            "name": "oldPay",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "oldYear",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "newPay",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "newYear",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Computed result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/tools/emergency-fund": {
      "get": {
        "operationId": "emergency_fund",
        "summary": "Emergency fund / job-loss runway",
        "description": "How many months of runway a set of resources covers against monthly expenses, net of unemployment benefits and COBRA.",
        "parameters": [
          {
            "name": "monthlyExpenses",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "fund",
            "in": "query",
            "required": false,
            "description": "Emergency fund savings",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "severance",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "otherResources",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "unemploymentBenefit",
            "in": "query",
            "required": false,
            "description": "Monthly unemployment benefit",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "cobra",
            "in": "query",
            "required": false,
            "description": "Monthly COBRA health insurance cost",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "targetMonths",
            "in": "query",
            "required": false,
            "description": "Target runway in months, default 6",
            "schema": {
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Computed result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/tools/coast-fire": {
      "get": {
        "operationId": "coast_fire",
        "summary": "Coast FIRE number",
        "description": "The amount invested today that, growing alone with no further contributions, reaches a full FIRE number by retirement age.",
        "parameters": [
          {
            "name": "age",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "retireAge",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "invested",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "annualSpend",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "nominalReturnPct",
            "in": "query",
            "required": true,
            "description": "Expected annual nominal investment return, as a percent",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "inflationPct",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "safeWithdrawalRatePct",
            "in": "query",
            "required": true,
            "description": "e.g. 4 for the 4% rule",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "contribMonthly",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "otherAnnualIncome",
            "in": "query",
            "required": false,
            "description": "e.g. Social Security, pension",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "feesPct",
            "in": "query",
            "required": false,
            "description": "Annual investment fee drag, as a percent",
            "schema": {
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Computed result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/tools/inflation": {
      "get": {
        "operationId": "inflation_adjust",
        "summary": "US inflation calculator",
        "description": "What a dollar amount in one year is worth in another year's dollars, based on annual US CPI-U.",
        "parameters": [
          {
            "name": "amount",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "fromYear",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "toYear",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Computed result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/tools/fx-rate": {
      "get": {
        "operationId": "fx_rate",
        "summary": "Currency exchange rate",
        "description": "Daily ECB reference cross rate between two currencies.",
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": true,
            "description": "Currency code, e.g. EUR",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "description": "Currency code, e.g. USD",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Computed result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/tools/cpi": {
      "get": {
        "operationId": "cpi_index",
        "summary": "US CPI-U annual index",
        "description": "The annual (yearly-average) US CPI-U index value for a given year.",
        "parameters": [
          {
            "name": "year",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Computed result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}