{
  "openapi": "3.1.1",
  "info": {
    "title": "Is It Worth It? API",
    "version": "1.0.0",
    "summary": "Buy, rent, repair or subscribe? Compare total cost and NPV over the years you need it.",
    "description": "Every endpoint performs the same calculation as the human page and returns inputs, result, units, assumptions, sources, warnings and computedAt. MCP endpoint: /mcp."
  },
  "servers": [
    {
      "url": "https://isitworthit.usefulweb.site"
    }
  ],
  "paths": {
    "/api/v1/calculate": {
      "post": {
        "operationId": "calculate",
        "summary": "Buy, rent, repair or subscribe? Compare total cost and NPV over the years you need it.",
        "description": "Enter the options you are considering (buy new, rent, repair what you have, subscribe) with upfront, monthly and one-off costs, resale value and a repair allowance. The tool computes total cost of ownership, net present value of costs, cost per month, a ranking and when the best option overtakes the runner-up.\n\nMethodology:\n- Annual running cost = recurring per month × 12 + repair allowance per year.\n- Total cost (nominal) = upfront + one-off costs + years × annual running cost − resale value.\n- NPV cost = upfront + one-off ÷ (1 + r)^y + Σ(t = 1..N) annual running cost ÷ (1 + r)^t − resale ÷ (1 + r)^N, where r = discount rate and y = the one-off year (running costs are discounted at each year end).\n- Cost per month = total cost ÷ (12 × years); NPV cost per month = NPV cost ÷ (12 × years).\n- Options are ranked by NPV cost (lowest first); ties keep input order.\n- Break-even: nominal cumulative costs of the best and runner-up options are compared at each year end (resale counted only at the end, one-off costs from their year) and the crossing point is interpolated linearly.",
        "tags": [
          "everyday"
        ],
        "x-mcp-tool": "is_it_worth_it",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IsItWorthItInput"
              },
              "examples": {
                "example1": {
                  "summary": "Washing machine: buy, rent or repair the old one (5 years)",
                  "value": {
                    "years": 5,
                    "discountRatePercent": 3,
                    "currency": "EUR",
                    "options": [
                      {
                        "name": "Buy new",
                        "kind": "buy",
                        "upfront": 650,
                        "resale": 100,
                        "repairPerYear": 20
                      },
                      {
                        "name": "Rent",
                        "kind": "rent",
                        "monthly": 15,
                        "oneOff": 30
                      },
                      {
                        "name": "Repair old",
                        "kind": "repair",
                        "upfront": 220,
                        "repairPerYear": 60,
                        "oneOff": 650,
                        "oneOffYear": 3
                      }
                    ]
                  }
                },
                "example2": {
                  "summary": "Design software: perpetual licence vs subscription (4 years)",
                  "value": {
                    "years": 4,
                    "discountRatePercent": 4,
                    "currency": "USD",
                    "options": [
                      {
                        "name": "Perpetual licence + 1 upgrade",
                        "kind": "buy",
                        "upfront": 399,
                        "oneOff": 149,
                        "oneOffYear": 2
                      },
                      {
                        "name": "Monthly subscription",
                        "kind": "subscribe",
                        "monthly": 12.99
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IsItWorthItResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tool": {
      "get": {
        "operationId": "getToolDefinition",
        "summary": "Inputs, output schema and examples for this tool",
        "responses": {
          "200": {
            "description": "Tool definition.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details. 422 responses include per-field `errors`.",
        "required": [
          "type",
          "title",
          "status",
          "detail"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "message"
              ],
              "properties": {
                "field": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "IsItWorthItInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "years": {
            "title": "How long you need it",
            "type": "integer",
            "minimum": 1,
            "maximum": 50,
            "default": 5,
            "x-unit": "years"
          },
          "discountRatePercent": {
            "title": "Discount rate",
            "description": "What money is worth to you per year (e.g. savings interest). Used for NPV only.",
            "type": "number",
            "minimum": 0,
            "maximum": 50,
            "default": 3,
            "x-unit": "%/year"
          },
          "currency": {
            "title": "Currency",
            "description": "Shown in results only; no conversion is performed.",
            "type": "string",
            "maxLength": 8,
            "default": "EUR"
          },
          "options": {
            "title": "Options",
            "description": "Costs are positive numbers. Resale is what you expect to get back at the end. One-off year 0 = at the start.",
            "type": "array",
            "minItems": 2,
            "maxItems": 10,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "name": {
                  "title": "Option",
                  "type": "string"
                },
                "kind": {
                  "title": "Type",
                  "type": "string",
                  "enum": [
                    "buy",
                    "rent",
                    "repair",
                    "subscribe",
                    "other"
                  ],
                  "default": "other"
                },
                "upfront": {
                  "title": "Upfront cost",
                  "type": "number",
                  "minimum": 0,
                  "default": 0
                },
                "monthly": {
                  "title": "Recurring / month",
                  "type": "number",
                  "minimum": 0,
                  "default": 0
                },
                "oneOff": {
                  "title": "One-off costs",
                  "type": "number",
                  "minimum": 0,
                  "default": 0
                },
                "oneOffYear": {
                  "title": "One-off in year",
                  "type": "integer",
                  "minimum": 0,
                  "maximum": 50,
                  "default": 0
                },
                "resale": {
                  "title": "Resale at end",
                  "type": "number",
                  "minimum": 0,
                  "default": 0
                },
                "repairPerYear": {
                  "title": "Repair allowance / year",
                  "type": "number",
                  "minimum": 0,
                  "default": 0
                }
              },
              "required": [
                "name"
              ]
            }
          }
        },
        "required": [
          "options"
        ]
      },
      "IsItWorthItResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "currency",
              "years",
              "discountRatePercent",
              "best",
              "runnerUp",
              "breakEvenYear",
              "savingVsRunnerUpNpv",
              "ranking"
            ],
            "properties": {
              "currency": {
                "type": "string"
              },
              "years": {
                "type": "integer"
              },
              "discountRatePercent": {
                "type": "number"
              },
              "best": {
                "type": "string"
              },
              "runnerUp": {
                "type": "string"
              },
              "breakEvenYear": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Years from start after which the best option (by NPV) is cumulatively cheaper than the runner-up in nominal terms; 0 = cheaper from day one; null = never within the period."
              },
              "savingVsRunnerUpNpv": {
                "type": "number",
                "description": "NPV cost of the runner-up minus NPV cost of the best option."
              },
              "ranking": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "rank",
                    "name",
                    "kind",
                    "totalCost",
                    "npvCost",
                    "costPerMonth",
                    "npvCostPerMonth",
                    "annualRunningCost",
                    "differenceToBest"
                  ],
                  "properties": {
                    "rank": {
                      "type": "integer",
                      "minimum": 1
                    },
                    "name": {
                      "type": "string"
                    },
                    "kind": {
                      "type": "string",
                      "enum": [
                        "buy",
                        "rent",
                        "repair",
                        "subscribe",
                        "other"
                      ]
                    },
                    "totalCost": {
                      "type": "number",
                      "description": "Nominal total cost of ownership over the period, net of resale."
                    },
                    "npvCost": {
                      "type": "number",
                      "description": "Present value of all costs minus present value of resale."
                    },
                    "costPerMonth": {
                      "type": "number"
                    },
                    "npvCostPerMonth": {
                      "type": "number"
                    },
                    "annualRunningCost": {
                      "type": "number"
                    },
                    "differenceToBest": {
                      "type": "number",
                      "description": "npvCost minus the best option’s npvCost."
                    }
                  }
                }
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    }
  }
}