{
  "openapi": "3.1.1",
  "info": {
    "title": "Everyday problem-solving API",
    "version": "1.0.0",
    "summary": "Deterministic tools for people and AI agents.",
    "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://everyday.usefulweb.site"
    }
  ],
  "paths": {
    "/api/v1/tools": {
      "get": {
        "operationId": "listTools",
        "summary": "Catalog of all tools",
        "responses": {
          "200": {
            "description": "Tool list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/{id}": {
      "get": {
        "operationId": "getTool",
        "summary": "Definition of one tool",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "cancellation-navigator",
                "deadline-decoder",
                "decision-simulator",
                "form-translator",
                "how-long-will-it-last",
                "is-it-worth-it",
                "life-admin-generator",
                "repair-or-replace",
                "true-cost-calculator"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tool definition.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/cancellation-navigator/calculate": {
      "post": {
        "operationId": "calculateCancellationNavigator",
        "summary": "Verified steps to cancel Netflix, Spotify, Prime & more, plus a cancellation letter.",
        "description": "Choose a subscription and how you signed up. Cancellation Navigator shows the steps from the official help page (with the date we last checked it), what to do if you are billed through the App Store, Google Play or a carrier, your German online cancellation-button rights (§ 312k BGB), a ready-to-send cancellation letter and a proof-keeping checklist.\n\nMethodology:\n- Service steps were condensed from each service's official help page on the date shown (verifiedAt); nothing is added that the page does not say. If a page could not be read reliably, only the official link is given (steps not verified).\n- App Store and Google Play subscriptions are billed by Apple/Google, so the store's own cancellation steps (Apple Support, Google Play Help) are shown first for those channels.\n- Carrier/partner billing: cancel with the company that bills you (e.g. Spotify's help states partner plans are cancelled with the partner).\n- Germany: § 312k BGB (Kündigungsbutton) summary from gesetze-im-internet.de. Rights for other countries are not asserted because they were not verified.\n- Unknown services get a generic method and letter, clearly marked as unverified.\n\nNot legal advice. Service flows change; the official page linked is authoritative.",
        "tags": [
          "everyday"
        ],
        "x-mcp-tool": "cancellation_navigator",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CancellationNavigatorInput"
              },
              "examples": {
                "example1": {
                  "summary": "Netflix signed up on the web, Germany",
                  "value": {
                    "service": "netflix",
                    "country": "DE",
                    "channel": "web"
                  }
                },
                "example2": {
                  "summary": "ChatGPT Plus bought in the iPhone app, US",
                  "value": {
                    "service": "chatgpt-plus",
                    "country": "US",
                    "channel": "app-store"
                  }
                },
                "example3": {
                  "summary": "Unknown local gym, Germany",
                  "value": {
                    "service": "other",
                    "serviceName": "FitClub Musterstadt",
                    "country": "DE",
                    "channel": "other",
                    "yourName": "Max Mustermann"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CancellationNavigatorResult"
                }
              }
            }
          },
          "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/tools/deadline-decoder/calculate": {
      "post": {
        "operationId": "calculateDeadlineDecoder",
        "summary": "Find every deadline, required action and consequence in a letter or notice.",
        "description": "Paste or upload an official letter, invoice, reminder or notice (English or German). Deadline Decoder extracts absolute dates and relative deadlines such as \"within 14 days\" or \"binnen eines Monats\", resolves them against the letter or receipt date, lists what you must do and what happens otherwise, and exports the deadlines as a calendar (.ics) file.\n\nMethodology:\n- The text is split into sentences (paragraph-, bullet- and abbreviation-aware; German ordinal dates like \"12. Oktober\" are not treated as sentence ends).\n- Absolute dates are matched in the formats 2026-10-12, 12.10.2026, 12/10/2026 (day/month or month/day as selected; an unambiguous day > 12 overrides), \"October 12, 2026\", \"12 Oct 2026\" and \"12. Oktober 2026\". Impossible dates (31.02.) are discarded.\n- A date counts as a deadline when its sentence contains a deadline cue (by, until, no later than, due, bis, spätestens, fällig, Frist …) or a required-action pattern; other dates are listed as \"mentioned\".\n- Relative deadlines (\"within 14 days\", \"no later than 30 days after receipt\", \"innerhalb von 2 Wochen\", \"binnen eines Monats\") are added to the reference date: days and weeks as calendar days, business days skip Saturdays and Sundays (public holidays are not considered), months/years as calendar months (clamped to the month end).\n- Required actions are sentences matching modal or request patterns (must, shall, required, please pay/submit, bitte, müssen, \"ist … zu zahlen\", \"überweisen Sie\" …). Consequences are sentences with otherwise/failure-to/fee/penalty/escalation patterns (andernfalls, sonst, Mahngebühr, Säumniszuschlag, Inkasso, Vollstreckung …).\n- Every finding quotes the exact sentence and names the rule that fired. Confidence is \"pattern-match\": nothing is guessed by an AI model.\n\nNot legal advice. Rule-based extraction can miss deadlines or misread dates, and legal deadline rules (e.g. when a letter counts as received, weekends and public holidays) differ by country and authority. Always check the original document and, if in doubt, ask the sender or an adviser.",
        "tags": [
          "everyday"
        ],
        "x-mcp-tool": "deadline_decoder",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeadlineDecoderInput"
              },
              "examples": {
                "example1": {
                  "summary": "German payment reminder (Mahnung)",
                  "value": {
                    "text": "Zahlungserinnerung\nDatum: 05.10.2026\n\nSehr geehrte Frau Muster,\nleider konnten wir bis heute keinen Zahlungseingang für die Rechnung Nr. 4711 vom 01.09.2026 feststellen. Bitte überweisen Sie den offenen Betrag von 89,90 EUR bis spätestens 20. Oktober 2026 auf das unten genannte Konto. Andernfalls müssen wir eine Mahngebühr von 5,00 EUR berechnen und die Forderung an ein Inkassobüro übergeben. Gegen diesen Bescheid kann innerhalb eines Monats nach Bekanntgabe Widerspruch eingelegt werden.",
                    "referenceDate": "2026-10-07",
                    "referenceType": "received",
                    "dateOrder": "DMY"
                  }
                },
                "example2": {
                  "summary": "US insurance notice",
                  "value": {
                    "text": "Notice date: October 1, 2026\n\nWe need additional information to process your claim. You must submit the enclosed form and a copy of your medical bills within 30 days after receipt of this notice. If we do not receive the documents, your claim will be closed. Your premium payment of $142.50 is due 10/25/2026; failure to pay by the due date may result in a late fee of $15 and cancellation of your policy.",
                    "referenceDate": "2026-10-03",
                    "referenceType": "received",
                    "dateOrder": "MDY"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeadlineDecoderResult"
                }
              }
            }
          },
          "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/tools/decision-simulator/calculate": {
      "post": {
        "operationId": "calculateDecisionSimulator",
        "summary": "Compare 2–6 choices by expected value, worst case, best case and minimax regret.",
        "description": "Give each choice a worst, most likely and best outcome (money, hours, points…). The simulator computes expected values with PERT or triangular weights (or your own probabilities), then applies maximin, maximax, minimax regret and Laplace rules and explains which rule picks which choice.\n\nMethodology:\n- Each choice has three scenario outcomes: worst (W), most likely (M) and best (B).\n- PERT expected value = (W + 4M + B) ÷ 6, standard deviation ≈ (B − W) ÷ 6.\n- Triangular expected value = (W + M + B) ÷ 3, standard deviation = √((W² + M² + B² − WM − WB − MB) ÷ 18).\n- Custom: probabilities are normalised to sum to 1; EV = Σ pᵢ·xᵢ, standard deviation = √(Σ pᵢ·(xᵢ − EV)²).\n- Maximin picks the best worst case; maximax the best best case; Laplace the best unweighted average (W + M + B) ÷ 3.\n- Minimax regret treats worst / likely / best as three shared states of the world: regret = (best outcome of any choice in that state) − (this choice’s outcome); the choice with the smallest maximum regret wins.\n- When lower values are better, “best” means lowest everywhere. Ties go to the choice listed first. The recommendation is the expected-value pick.",
        "tags": [
          "everyday"
        ],
        "x-mcp-tool": "decision_simulator",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DecisionSimulatorInput"
              },
              "examples": {
                "example1": {
                  "summary": "Job offers: first-year net gain",
                  "value": {
                    "goal": "maximize",
                    "method": "pert",
                    "unit": "EUR",
                    "choices": [
                      {
                        "name": "Stay in current job",
                        "worst": 48000,
                        "likely": 50000,
                        "best": 52000
                      },
                      {
                        "name": "Startup offer",
                        "worst": 30000,
                        "likely": 58000,
                        "best": 90000
                      },
                      {
                        "name": "Corporate offer",
                        "worst": 50000,
                        "likely": 55000,
                        "best": 60000
                      }
                    ]
                  }
                },
                "example2": {
                  "summary": "Commute: travel minutes per day",
                  "value": {
                    "goal": "minimize",
                    "method": "custom",
                    "unit": "minutes",
                    "choices": [
                      {
                        "name": "Car",
                        "worst": 90,
                        "likely": 45,
                        "best": 35,
                        "pWorst": 10,
                        "pLikely": 70,
                        "pBest": 20
                      },
                      {
                        "name": "Train",
                        "worst": 70,
                        "likely": 55,
                        "best": 50,
                        "pWorst": 15,
                        "pLikely": 75,
                        "pBest": 10
                      },
                      {
                        "name": "Bike",
                        "worst": 60,
                        "likely": 58,
                        "best": 55,
                        "pWorst": 20,
                        "pLikely": 60,
                        "pBest": 20
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DecisionSimulatorResult"
                }
              }
            }
          },
          "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/tools/form-translator/calculate": {
      "post": {
        "operationId": "calculateFormTranslator",
        "summary": "Plain-language help for confusing forms: field-by-field hints and jargon explained.",
        "description": "Paste or upload (incl. photo/OCR) an official, insurance or tax form in English or German. Form Translator detects the fields, recognises what kind of entry each needs (date, signature, checkbox, IBAN, tax ID …), explains jargon from a curated glossary of 160 terms and lists the documents you will probably need.\n\nMethodology:\n- Lines are scanned for field labels: \"Label:\" followed by blanks, labels next to fill lines (____ or ....), checkbox options (☐, □, [ ], ( )) and short label-only lines that contain a field keyword.\n- Each label is classified with keyword rules into field types (date, signature, checkbox, IBAN/bank, tax ID, ID/reference number, e-mail, phone, address, name, amount, marital status, nationality, place+date), each with a fixed fill-in hint.\n- Jargon is matched against an editorial glossary (160 English and German admin, tax, insurance, benefits, banking and legal terms incl. inflected German forms). Explanations are written by usefulweb.site editors, not generated.\n- Documents are listed when a sentence asks to attach/enclose/provide proof (beifügen, Nachweis, Kopie, Bescheinigung …), quoted verbatim, plus documents commonly requested for recognised glossary terms (marked as such).\n- IBANs found in the text are checked with the ISO 13616 mod-97 checksum (German IBANs must have 22 characters). A valid checksum does not prove the account exists.\n\nNot legal, tax or insurance advice. Explanations are editorial plain-language summaries for orientation and may not match the exact legal meaning in your country, contract or authority. The detection is rule-based and never complete; when in doubt, ask the issuing office.",
        "tags": [
          "everyday"
        ],
        "x-mcp-tool": "form_translator",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FormTranslatorInput"
              },
              "examples": {
                "example1": {
                  "summary": "German Kindergeld-style application",
                  "value": {
                    "text": "Antrag auf Kindergeld\n\n1. Angaben zur antragstellenden Person\nName, Vorname: ______________________\nGeburtsdatum (TT.MM.JJJJ): __________\nSteuer-ID: ___________\nAnschrift (Straße, Hausnummer, PLZ, Ort): ____________________\nFamilienstand:\n☐ ledig ☐ verheiratet ☐ geschieden ☐ verwitwet\n\n2. Angaben zum Ehegatten / eingetragenen Lebenspartner\nName, Vorname: ______________\n\n3. Bankverbindung\nIBAN: DE89 3704 0044 0532 0130 00\nKontoinhaber: ______________\n\nBitte fügen Sie eine Kopie der Geburtsurkunde und ggf. eine Schulbescheinigung bei.\nIch versichere, dass meine Angaben vollständig und richtig sind.\nOrt, Datum: ____________   Unterschrift: ________________"
                  }
                },
                "example2": {
                  "summary": "US health insurance enrollment",
                  "value": {
                    "text": "Health Plan Enrollment Form\n\nPolicyholder name: ____________\nDate of birth (MM/DD/YYYY): ________\nSocial Security Number: ___-__-____\nMarital status: [ ] Single [ ] Married [ ] Divorced\nDependents (name, DOB, relationship): ______________\nPrimary beneficiary: ______________\n\nPlan options: The Silver plan has a $2,000 deductible, 20% coinsurance and a $30 copay for primary care visits.\nDo you have a pre-existing condition? [ ] Yes [ ] No\n\nPlease attach a copy of your ID and proof of address.\nSignature of applicant: ______________ Date: ________"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormTranslatorResult"
                }
              }
            }
          },
          "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/tools/how-long-will-it-last/calculate": {
      "post": {
        "operationId": "calculateHowLongWillItLast",
        "summary": "Estimate remaining life of appliances and home components and plan the replacement.",
        "description": "Pick an appliance or home component, enter its age, how hard it is used and how well it is maintained. The tool uses the life-expectancy ranges published in InterNACHI's Standard Estimated Life Expectancy Chart for Homes to estimate remaining years, the share of life used, and a replacement planning window.\n\nMethodology:\n- Base range: the YEARS value for the item from InterNACHI's Standard Estimated Life Expectancy Chart for Homes (e.g. '9 to 13'). Single values use the same min and max; 'N+' values are open-ended (only a minimum).\n- Adjusted range = base range × usage multiplier (light 1.15, normal 1.0, heavy 0.8) × maintenance multiplier (regular 1.0, occasional 0.9, neglected 0.75). These multipliers are this tool's own assumptions, not published figures; InterNACHI's values already assume regular recommended maintenance and normal wear and tear.\n- Remaining years = max(0, adjusted min − age) to max(0, adjusted max − age).\n- Life used = age ÷ midpoint of the adjusted range × 100 (open-ended: ÷ adjusted minimum).\n- Status: < 50% early life, 50–80% mid-life, ≥ 80% but below adjusted minimum approaching end, between adjusted min and max within end-of-life range, beyond adjusted max beyond expected life.\n- Replacement window = current year + remaining min … current year + remaining max (rounded to whole years).\n\nLife expectancies are guidelines only, not guarantees or warranties (InterNACHI).",
        "tags": [
          "everyday"
        ],
        "x-mcp-tool": "how_long_will_it_last",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HowLongWillItLastInput"
              },
              "examples": {
                "example1": {
                  "summary": "7-year-old refrigerator, normal use",
                  "value": {
                    "item": "refrigerator",
                    "ageYears": 7,
                    "usage": "normal",
                    "maintenance": "good"
                  }
                },
                "example2": {
                  "summary": "10-year-old water heater, heavy use, occasional maintenance",
                  "value": {
                    "item": "water-heater",
                    "ageYears": 10,
                    "usage": "heavy",
                    "maintenance": "average"
                  }
                },
                "example3": {
                  "summary": "4-year-old washing machine, light use",
                  "value": {
                    "item": "washing-machine",
                    "ageYears": 4,
                    "usage": "light",
                    "maintenance": "good"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HowLongWillItLastResult"
                }
              }
            }
          },
          "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/tools/is-it-worth-it/calculate": {
      "post": {
        "operationId": "calculateIsItWorthIt",
        "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/tools/life-admin-generator/calculate": {
      "post": {
        "operationId": "calculateLifeAdminGenerator",
        "summary": "A dated to-do list for moving, marriage, a baby, a new job and other life events.",
        "description": "Choose a life event, your country, the date and your circumstances. You get a personalised before / on-the-day / after checklist with due dates. Legal deadlines are only stated where verified against official sources (e.g. German Anmeldung within two weeks); everything else is clearly marked as a recommendation.\n\nMethodology:\n- A rule catalog maps each life event to tasks with an offset in days relative to the event date (negative = before). Rules can be limited to countries and to circumstances (e.g. lease notice only when renting).\n- Due date = event date + offset (calendar days). Items are grouped into before, on the day and after, sorted by due date then id.\n- Country-specific legal deadlines are only included where verified against an official source (Germany: BMG § 17, PStG §§ 18 and 28; Austria: oesterreich.gv.at; Switzerland: ch.ch; UK: GOV.UK birth and death registration). Only those are marked mandatory and cited.\n- For other countries and topics the item is phrased as \"check local requirements\"; offsets for recommendations are editorial planning suggestions.\n\nOrganisational help, not legal advice. Rules change and have exceptions — confirm deadlines with the responsible authority.",
        "tags": [
          "everyday"
        ],
        "x-mcp-tool": "life_admin_generator",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LifeAdminGeneratorInput"
              },
              "examples": {
                "example1": {
                  "summary": "Moving home in Germany (renting, car)",
                  "value": {
                    "event": "moving",
                    "country": "de",
                    "eventDate": "2026-12-01",
                    "circumstances": [
                      "renting",
                      "has-car",
                      "employed"
                    ]
                  }
                },
                "example2": {
                  "summary": "Having a baby in the UK",
                  "value": {
                    "event": "baby",
                    "country": "uk",
                    "eventDate": "2027-03-20",
                    "circumstances": [
                      "employed",
                      "has-car"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LifeAdminGeneratorResult"
                }
              }
            }
          },
          "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/tools/repair-or-replace/calculate": {
      "post": {
        "operationId": "calculateRepairOrReplace",
        "summary": "Fix it or buy new? The 50% rule plus a cost-per-year check, with a clear verdict.",
        "description": "Enter the age and expected lifespan of a broken item, the repair quote, the replacement price and running costs. The tool applies the common 50% rule of thumb and compares the cost per remaining year of repairing versus replacing, including the risk of another failure, and gives a reasoned verdict.\n\nMethodology:\n- 50% rule of thumb: if the repair quote is more than the threshold (default 50%) of the replacement price, replace; otherwise repair. This is a common heuristic, not a law or standard.\n- Expected extra repair cost = P(another failure) × next repair cost (defaults to the current quote).\n- Repair cost per year = (repair quote + expected extra repair cost) ÷ expected extra life + running cost of the old item per year.\n- Replace cost per year = replacement price ÷ lifespan of the new item + running cost of the new item per year.\n- Break-even repair quote = (replace cost per year − old running cost) × extra life − expected extra repair cost (floored at 0).\n- Final verdict follows the cost-per-year comparison, because it accounts for remaining life, failure risk and running costs; the 50% rule is shown as a cross-check.",
        "tags": [
          "everyday"
        ],
        "x-mcp-tool": "repair_or_replace",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RepairOrReplaceInput"
              },
              "examples": {
                "example1": {
                  "summary": "Washing machine with a failed drum bearing",
                  "value": {
                    "itemName": "Washing machine",
                    "currency": "EUR",
                    "itemAgeYears": 8,
                    "expectedLifespanYears": 11,
                    "replacementPrice": 550,
                    "repairQuote": 320,
                    "lifeAfterRepairYears": 3,
                    "runningCostOldPerYear": 75,
                    "runningCostNewPerYear": 55,
                    "failureProbabilityPercent": 35,
                    "ruleThresholdPercent": 50
                  }
                },
                "example2": {
                  "summary": "Laptop with a dead battery",
                  "value": {
                    "itemName": "Laptop",
                    "currency": "USD",
                    "itemAgeYears": 3,
                    "expectedLifespanYears": 6,
                    "replacementPrice": 1200,
                    "repairQuote": 150,
                    "lifeAfterRepairYears": 3,
                    "runningCostOldPerYear": 0,
                    "runningCostNewPerYear": 0,
                    "failureProbabilityPercent": 15,
                    "ruleThresholdPercent": 50
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RepairOrReplaceResult"
                }
              }
            }
          },
          "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/tools/true-cost-calculator/calculate": {
      "post": {
        "operationId": "calculateTrueCostCalculator",
        "summary": "What a car, pet, appliance, home or gadget really costs per year, month and day.",
        "description": "Add the purchase price, financing, expected resale value, recurring costs, maintenance, insurance and energy use. The calculator returns the true total cost of ownership, the cost per year, month and day, the share of each cost bucket, and how many times the sticker price you really pay.\n\nMethodology:\n- Depreciation = purchase price − expected resale value (the money you will not get back).\n- Loan interest is computed from an exact monthly annuity schedule: payment = L·i ÷ (1 − (1 + i)^−n) with i = APR ÷ 12 and n = term in months; only interest falling within the ownership period (years × 12 months) is counted.\n- Recurring costs are annualised: weekly × 365.25/7, monthly × 12, quarterly × 4, yearly × 1; then multiplied by years owned.\n- Energy per year = consumption ÷ (1 or 100) × usage per year × price per energy unit.\n- True total = depreciation + loan interest + years × (recurring + maintenance + insurance + energy per year).\n- Per year = total ÷ years; per month = total ÷ (12 × years); per day = total ÷ (365.25 × years). Sticker multiplier = total ÷ purchase price.",
        "tags": [
          "everyday"
        ],
        "x-mcp-tool": "true_cost_calculator",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TrueCostCalculatorInput"
              },
              "examples": {
                "example1": {
                  "summary": "Compact car, financed, 6 years",
                  "value": {
                    "itemType": "car",
                    "itemName": "Compact car",
                    "currency": "EUR",
                    "purchasePrice": 24000,
                    "yearsOwned": 6,
                    "resaleValue": 9000,
                    "loanAmount": 15000,
                    "aprPercent": 5.9,
                    "loanTermMonths": 48,
                    "maintenancePerYear": 600,
                    "insurancePerYear": 750,
                    "energyConsumption": 6,
                    "consumptionPer": "per-100",
                    "energyUnitPrice": 1.75,
                    "usagePerYear": 12000,
                    "recurring": [
                      {
                        "name": "Vehicle tax",
                        "amount": 120,
                        "frequency": "yearly"
                      },
                      {
                        "name": "Parking permit",
                        "amount": 30,
                        "frequency": "monthly"
                      }
                    ]
                  }
                },
                "example2": {
                  "summary": "Medium-sized dog, 12 years",
                  "value": {
                    "itemType": "pet",
                    "itemName": "Dog",
                    "currency": "EUR",
                    "purchasePrice": 900,
                    "yearsOwned": 12,
                    "resaleValue": 0,
                    "loanAmount": 0,
                    "aprPercent": 0,
                    "loanTermMonths": 0,
                    "insurancePerYear": 240,
                    "maintenancePerYear": 250,
                    "energyConsumption": 0,
                    "consumptionPer": "per-1",
                    "energyUnitPrice": 0,
                    "usagePerYear": 0,
                    "recurring": [
                      {
                        "name": "Food",
                        "amount": 15,
                        "frequency": "weekly"
                      },
                      {
                        "name": "Dog tax",
                        "amount": 100,
                        "frequency": "yearly"
                      },
                      {
                        "name": "Toys & treats",
                        "amount": 10,
                        "frequency": "monthly"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrueCostCalculatorResult"
                }
              }
            }
          },
          "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/workflows": {
      "get": {
        "operationId": "listWorkflows",
        "summary": "Multi-tool workflows",
        "responses": {
          "200": {
            "description": "Workflow list.",
            "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"
                }
              }
            }
          }
        }
      },
      "CancellationNavigatorInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "service": {
            "title": "Service",
            "type": "string",
            "enum": [
              "netflix",
              "spotify",
              "amazon-prime",
              "kindle-unlimited",
              "disney-plus",
              "hulu",
              "paramount-plus",
              "youtube-premium",
              "google-one",
              "microsoft-365",
              "xbox",
              "playstation-plus",
              "adobe",
              "audible",
              "dazn",
              "linkedin-premium",
              "dropbox",
              "chatgpt-plus",
              "duolingo",
              "other"
            ],
            "default": "netflix"
          },
          "serviceName": {
            "title": "Service name (if Other)",
            "type": "string",
            "maxLength": 120
          },
          "country": {
            "title": "Your country",
            "type": "string",
            "enum": [
              "DE",
              "AT",
              "EU-other",
              "UK",
              "US",
              "other"
            ],
            "default": "DE"
          },
          "channel": {
            "title": "Where did you sign up / who bills you?",
            "type": "string",
            "enum": [
              "web",
              "app-store",
              "google-play",
              "carrier",
              "other"
            ],
            "default": "web"
          },
          "yourName": {
            "title": "Your name (for the letter, optional)",
            "type": "string",
            "maxLength": 120
          },
          "customerNumber": {
            "title": "Customer / account number (optional)",
            "type": "string",
            "maxLength": 80
          }
        },
        "required": []
      },
      "CancellationNavigatorResult": {
        "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": [
              "service",
              "verified",
              "officialUrl",
              "verifiedAt",
              "stepsSource",
              "steps",
              "serviceNotes",
              "channelNotes",
              "rights",
              "letter"
            ],
            "properties": {
              "service": {
                "type": "string"
              },
              "verified": {
                "type": "boolean",
                "description": "True if the steps come from an official help page checked on verifiedAt (false = generic method)."
              },
              "officialUrl": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "uri"
              },
              "verifiedAt": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date"
              },
              "stepsSource": {
                "type": "string",
                "enum": [
                  "service-help-page",
                  "apple-support",
                  "google-play-help",
                  "generic"
                ]
              },
              "steps": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "serviceNotes": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "channelNotes": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "rights": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "title",
                    "url",
                    "text"
                  ],
                  "properties": {
                    "title": {
                      "type": "string"
                    },
                    "url": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "text": {
                      "type": "string"
                    }
                  }
                }
              },
              "letter": {
                "type": "string",
                "description": "Plain-text cancellation letter template."
              }
            }
          },
          "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"
              }
            }
          }
        }
      },
      "DeadlineDecoderInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "text": {
            "title": "Letter or notice text",
            "description": "Paste the text here, or use one of the other options below (exactly one).",
            "type": "string",
            "maxLength": 200000
          },
          "file": {
            "title": "Or upload a file",
            "description": "TXT, PDF, DOCX, HTML or a photo/scan (PNG/JPG, read with OCR). Max 5 MiB. Upload as {filename, contentType?, contentBase64}. Max 5120 KiB. Accepts .txt,.pdf,.docx,.png,.jpg,.jpeg,.html.",
            "type": "object",
            "additionalProperties": false,
            "required": [
              "filename",
              "contentBase64"
            ],
            "properties": {
              "filename": {
                "type": "string"
              },
              "contentType": {
                "type": "string"
              },
              "contentBase64": {
                "type": "string"
              }
            }
          },
          "referenceDate": {
            "title": "Reference date",
            "description": "Date of the letter or the day you received it. Relative deadlines (\"within 14 days\") are counted from here. Defaults to today.",
            "type": "string",
            "format": "date"
          },
          "referenceType": {
            "title": "The reference date is…",
            "type": "string",
            "enum": [
              "received",
              "letter"
            ],
            "default": "received"
          },
          "dateOrder": {
            "title": "Numeric dates like 03/04/2026 are",
            "type": "string",
            "enum": [
              "DMY",
              "MDY"
            ],
            "default": "DMY"
          }
        },
        "required": []
      },
      "DeadlineDecoderResult": {
        "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": [
              "referenceDate",
              "referenceType",
              "today",
              "deadlines",
              "datesMentioned",
              "actions",
              "consequences",
              "nextDeadline",
              "confidence"
            ],
            "properties": {
              "referenceDate": {
                "type": "string",
                "format": "date"
              },
              "referenceType": {
                "type": "string",
                "enum": [
                  "letter",
                  "received"
                ]
              },
              "today": {
                "type": "string",
                "format": "date"
              },
              "confidence": {
                "type": "string",
                "const": "pattern-match",
                "description": "All findings come from fixed text patterns, not from a statistical model."
              },
              "nextDeadline": {
                "type": [
                  "object",
                  "null"
                ],
                "description": "Earliest deadline that is today or upcoming, or null."
              },
              "deadlines": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "date",
                    "daysRemaining",
                    "status",
                    "kind",
                    "rule",
                    "matchedText",
                    "evidence",
                    "action",
                    "calculation"
                  ],
                  "properties": {
                    "date": {
                      "type": "string",
                      "format": "date"
                    },
                    "daysRemaining": {
                      "type": "integer",
                      "description": "Calendar days from today (negative = overdue)."
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "overdue",
                        "today",
                        "upcoming"
                      ]
                    },
                    "kind": {
                      "type": "string",
                      "enum": [
                        "absolute",
                        "relative"
                      ]
                    },
                    "rule": {
                      "type": "string"
                    },
                    "matchedText": {
                      "type": "string"
                    },
                    "evidence": {
                      "type": "string",
                      "description": "Exact sentence the deadline was found in."
                    },
                    "action": {
                      "type": "string"
                    },
                    "calculation": {
                      "type": "string"
                    }
                  }
                }
              },
              "datesMentioned": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "date",
                    "matchedText",
                    "rule",
                    "evidence"
                  ],
                  "properties": {
                    "date": {
                      "type": "string",
                      "format": "date"
                    },
                    "matchedText": {
                      "type": "string"
                    },
                    "rule": {
                      "type": "string"
                    },
                    "evidence": {
                      "type": "string"
                    }
                  }
                }
              },
              "actions": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "action",
                    "rule",
                    "evidence"
                  ],
                  "properties": {
                    "action": {
                      "type": "string"
                    },
                    "rule": {
                      "type": "string"
                    },
                    "evidence": {
                      "type": "string"
                    }
                  }
                }
              },
              "consequences": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "rules",
                    "amounts",
                    "evidence"
                  ],
                  "properties": {
                    "rules": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "amounts": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "evidence": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "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"
              }
            }
          }
        }
      },
      "DecisionSimulatorInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "goal": {
            "title": "Higher values are",
            "type": "string",
            "enum": [
              "maximize",
              "minimize"
            ],
            "default": "maximize"
          },
          "method": {
            "title": "Expected value weights",
            "type": "string",
            "enum": [
              "pert",
              "triangular",
              "custom"
            ],
            "default": "pert"
          },
          "unit": {
            "title": "Unit of the values",
            "type": "string",
            "maxLength": 20,
            "default": "EUR"
          },
          "choices": {
            "title": "Choices",
            "description": "Worst/likely/best outcome per choice. Probabilities (%) are only used with “My own probabilities” and are normalised to sum to 100.",
            "type": "array",
            "minItems": 2,
            "maxItems": 6,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "name": {
                  "title": "Choice",
                  "type": "string"
                },
                "worst": {
                  "title": "Worst",
                  "type": "number"
                },
                "likely": {
                  "title": "Most likely",
                  "type": "number"
                },
                "best": {
                  "title": "Best",
                  "type": "number"
                },
                "pWorst": {
                  "title": "P(worst) %",
                  "type": "number",
                  "minimum": 0,
                  "maximum": 100
                },
                "pLikely": {
                  "title": "P(likely) %",
                  "type": "number",
                  "minimum": 0,
                  "maximum": 100
                },
                "pBest": {
                  "title": "P(best) %",
                  "type": "number",
                  "minimum": 0,
                  "maximum": 100
                }
              },
              "required": [
                "name",
                "worst",
                "likely",
                "best"
              ]
            }
          }
        },
        "required": [
          "choices"
        ]
      },
      "DecisionSimulatorResult": {
        "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": [
              "goal",
              "method",
              "unit",
              "choices",
              "picks",
              "recommendation",
              "rulesInAgreement",
              "explanation"
            ],
            "properties": {
              "goal": {
                "type": "string",
                "enum": [
                  "maximize",
                  "minimize"
                ]
              },
              "method": {
                "type": "string",
                "enum": [
                  "pert",
                  "triangular",
                  "custom"
                ]
              },
              "unit": {
                "type": "string"
              },
              "choices": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "name",
                    "worst",
                    "likely",
                    "best",
                    "expectedValue",
                    "standardDeviation",
                    "average",
                    "maxRegret",
                    "weights",
                    "rankByExpectedValue"
                  ],
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "worst": {
                      "type": "number"
                    },
                    "likely": {
                      "type": "number"
                    },
                    "best": {
                      "type": "number"
                    },
                    "expectedValue": {
                      "type": "number"
                    },
                    "standardDeviation": {
                      "type": "number",
                      "description": "Analytical spread of the chosen distribution (PERT: (best − worst)/6; triangular: √((a²+b²+c²−ab−ac−bc)/18); custom: discrete)."
                    },
                    "average": {
                      "type": "number",
                      "description": "Unweighted mean of worst, likely and best (Laplace rule)."
                    },
                    "maxRegret": {
                      "type": "number",
                      "description": "Largest shortfall versus the best choice in any of the three scenarios."
                    },
                    "weights": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "additionalProperties": false,
                      "required": [
                        "worst",
                        "likely",
                        "best"
                      ],
                      "properties": {
                        "worst": {
                          "type": "number"
                        },
                        "likely": {
                          "type": "number"
                        },
                        "best": {
                          "type": "number"
                        }
                      },
                      "description": "Normalised probabilities used (null when not applicable)."
                    },
                    "rankByExpectedValue": {
                      "type": "integer",
                      "minimum": 1
                    }
                  }
                }
              },
              "picks": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "expectedValue",
                  "maximin",
                  "maximax",
                  "minimaxRegret",
                  "laplace"
                ],
                "properties": {
                  "expectedValue": {
                    "type": "string"
                  },
                  "maximin": {
                    "type": "string",
                    "description": "Best worst case (pessimist)."
                  },
                  "maximax": {
                    "type": "string",
                    "description": "Best best case (optimist)."
                  },
                  "minimaxRegret": {
                    "type": "string"
                  },
                  "laplace": {
                    "type": "string",
                    "description": "Best unweighted average."
                  }
                }
              },
              "recommendation": {
                "type": "string"
              },
              "rulesInAgreement": {
                "type": "integer",
                "minimum": 1,
                "maximum": 5,
                "description": "How many of the 5 rules pick the recommended choice."
              },
              "explanation": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "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"
              }
            }
          }
        }
      },
      "FormTranslatorInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "text": {
            "title": "Form text",
            "description": "Paste the form text (labels and instructions), or upload a PDF/DOCX/photo below.",
            "type": "string",
            "maxLength": 200000
          },
          "file": {
            "title": "Or upload a file",
            "description": "TXT, PDF, DOCX, HTML or a photo/scan (PNG/JPG, read with OCR). Max 5 MiB. Upload as {filename, contentType?, contentBase64}. Max 5120 KiB. Accepts .txt,.pdf,.docx,.png,.jpg,.jpeg,.html.",
            "type": "object",
            "additionalProperties": false,
            "required": [
              "filename",
              "contentBase64"
            ],
            "properties": {
              "filename": {
                "type": "string"
              },
              "contentType": {
                "type": "string"
              },
              "contentBase64": {
                "type": "string"
              }
            }
          }
        },
        "required": []
      },
      "FormTranslatorResult": {
        "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": [
              "disclaimer",
              "editorialNote",
              "confidence",
              "fields",
              "glossaryHits",
              "documentsNeeded",
              "ibanChecks",
              "glossarySize"
            ],
            "properties": {
              "disclaimer": {
                "type": "string"
              },
              "editorialNote": {
                "type": "string"
              },
              "confidence": {
                "type": "string",
                "const": "pattern-match"
              },
              "glossarySize": {
                "type": "integer",
                "minimum": 0
              },
              "fields": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "label",
                    "line",
                    "fieldTypes",
                    "hint",
                    "glossaryTerms"
                  ],
                  "properties": {
                    "label": {
                      "type": "string",
                      "description": "Field label exactly as found in the form text."
                    },
                    "line": {
                      "type": "integer",
                      "minimum": 1
                    },
                    "fieldTypes": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "hint": {
                      "type": "string",
                      "description": "Editorial fill-in hint."
                    },
                    "glossaryTerms": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "glossaryHits": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "term",
                    "matched",
                    "language",
                    "domain",
                    "explanation",
                    "occurrences"
                  ],
                  "properties": {
                    "term": {
                      "type": "string"
                    },
                    "matched": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "language": {
                      "type": "string",
                      "enum": [
                        "en",
                        "de"
                      ]
                    },
                    "domain": {
                      "type": "string"
                    },
                    "explanation": {
                      "type": "string",
                      "description": "Editorial plain-language explanation."
                    },
                    "hint": {
                      "type": "string"
                    },
                    "occurrences": {
                      "type": "integer",
                      "minimum": 1
                    }
                  }
                }
              },
              "documentsNeeded": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "item",
                    "basis",
                    "rule"
                  ],
                  "properties": {
                    "item": {
                      "type": "string"
                    },
                    "basis": {
                      "type": "string",
                      "enum": [
                        "quoted from form",
                        "commonly requested (glossary)"
                      ]
                    },
                    "rule": {
                      "type": "string"
                    }
                  }
                }
              },
              "ibanChecks": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "iban",
                    "checksumValid"
                  ],
                  "properties": {
                    "iban": {
                      "type": "string"
                    },
                    "checksumValid": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "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"
              }
            }
          }
        }
      },
      "HowLongWillItLastInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "item": {
            "title": "Item",
            "type": "string",
            "enum": [
              "air-conditioner-window",
              "trash-compactor",
              "dehumidifier",
              "dishwasher",
              "food-waste-disposal",
              "dryer-vent-plastic",
              "dryer-vent-steel",
              "clothes-dryer",
              "exhaust-fans",
              "freezer",
              "gas-oven",
              "hand-dryer",
              "humidifier-portable",
              "microwave-oven",
              "range-hood",
              "electric-range",
              "gas-range",
              "refrigerator",
              "swamp-cooler",
              "washing-machine",
              "whole-house-vacuum",
              "caulking",
              "paint-exterior",
              "paint-interior",
              "stains",
              "entertainment-center",
              "kitchen-cabinets",
              "countertop-laminate",
              "countertop-cultured-marble",
              "deck-planks",
              "deck-composite",
              "door-vinyl-exterior",
              "door-hollow-core",
              "afci",
              "light-fixtures",
              "propane-backup-generator",
              "service-panel",
              "solar-panels",
              "solar-batteries",
              "electrical-accessories",
              "carpet",
              "laminate-flooring",
              "vinyl-flooring",
              "linoleum",
              "garage-door",
              "garage-door-opener",
              "co-detector",
              "security-system",
              "central-ac",
              "boiler",
              "ceiling-fan",
              "condenser",
              "furnace",
              "gas-fireplace",
              "heat-pump",
              "whole-house-humidifier",
              "thermostat",
              "burner",
              "faucets",
              "fiberglass-tub-shower",
              "tankless-water-heater",
              "shower-doors",
              "sump-pump",
              "toilet-tank-components",
              "water-heater",
              "water-softener",
              "well-pump",
              "roof-asphalt-architectural",
              "roof-asphalt-3-tab",
              "roof-metal",
              "roof-epdm",
              "vinyl-siding",
              "asphalt-driveway",
              "wood-fencing",
              "pool-filter-pump",
              "pool-water-heater",
              "pool-vinyl-liner",
              "windows-double-pane",
              "windows-vinyl",
              "skylights",
              "window-glazing"
            ],
            "default": "refrigerator"
          },
          "ageYears": {
            "title": "Current age",
            "type": "number",
            "minimum": 0,
            "maximum": 200,
            "default": 5,
            "x-unit": "years"
          },
          "usage": {
            "title": "Usage intensity",
            "type": "string",
            "enum": [
              "light",
              "normal",
              "heavy"
            ],
            "default": "normal"
          },
          "maintenance": {
            "title": "Maintenance quality",
            "type": "string",
            "enum": [
              "good",
              "average",
              "poor"
            ],
            "default": "good"
          }
        },
        "required": [
          "ageYears"
        ]
      },
      "HowLongWillItLastResult": {
        "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": [
              "item",
              "category",
              "publishedYears",
              "publishedMin",
              "publishedMax",
              "openEnded",
              "factor",
              "adjustedMin",
              "adjustedMax",
              "ageYears",
              "remainingMin",
              "remainingMax",
              "lifeUsedPercent",
              "status",
              "replacementWindowStart",
              "replacementWindowEnd"
            ],
            "properties": {
              "item": {
                "type": "string"
              },
              "category": {
                "type": "string"
              },
              "publishedYears": {
                "type": "string",
                "description": "Verbatim value from the InterNACHI chart."
              },
              "publishedMin": {
                "type": "number"
              },
              "publishedMax": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "null for open-ended values like \"20+\"."
              },
              "openEnded": {
                "type": "boolean"
              },
              "factor": {
                "type": "number",
                "description": "Usage multiplier × maintenance multiplier (tool assumption)."
              },
              "adjustedMin": {
                "type": "number"
              },
              "adjustedMax": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "ageYears": {
                "type": "number"
              },
              "remainingMin": {
                "type": "number"
              },
              "remainingMax": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "lifeUsedPercent": {
                "type": "number",
                "description": "Age ÷ midpoint of the adjusted range (÷ adjusted minimum if open-ended) × 100."
              },
              "status": {
                "type": "string",
                "enum": [
                  "early-life",
                  "mid-life",
                  "approaching-end",
                  "within-end-of-life-range",
                  "beyond-expected-life"
                ]
              },
              "replacementWindowStart": {
                "type": "integer",
                "description": "Calendar year when the adjusted minimum life is reached (start budgeting)."
              },
              "replacementWindowEnd": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "Calendar year when the adjusted maximum life is reached."
              }
            }
          },
          "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"
              }
            }
          }
        }
      },
      "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"
              }
            }
          }
        }
      },
      "LifeAdminGeneratorInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "event": {
            "title": "Life event",
            "type": "string",
            "enum": [
              "moving",
              "marriage",
              "new-job",
              "baby",
              "university",
              "retiring",
              "death",
              "car",
              "pet",
              "abroad"
            ]
          },
          "country": {
            "title": "Country",
            "type": "string",
            "enum": [
              "de",
              "at",
              "ch",
              "uk",
              "us",
              "other"
            ],
            "default": "de"
          },
          "eventDate": {
            "title": "Date of the event",
            "description": "Moving day, wedding, first working day, due date, date of death…",
            "type": "string",
            "format": "date"
          },
          "circumstances": {
            "title": "Your situation",
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "renting",
                "owning",
                "has-car",
                "has-children",
                "employed",
                "self-employed",
                "has-pets"
              ]
            }
          }
        },
        "required": [
          "event",
          "eventDate"
        ]
      },
      "LifeAdminGeneratorResult": {
        "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": [
              "event",
              "country",
              "eventDate",
              "items",
              "mandatoryCount"
            ],
            "properties": {
              "event": {
                "type": "string"
              },
              "country": {
                "type": "string"
              },
              "eventDate": {
                "type": "string",
                "format": "date"
              },
              "mandatoryCount": {
                "type": "integer",
                "minimum": 0
              },
              "items": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "id",
                    "title",
                    "due",
                    "phase",
                    "daysFromEvent",
                    "category",
                    "mandatory"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "title": {
                      "type": "string"
                    },
                    "due": {
                      "type": "string",
                      "format": "date"
                    },
                    "phase": {
                      "type": "string",
                      "enum": [
                        "before",
                        "on-the-day",
                        "after"
                      ]
                    },
                    "daysFromEvent": {
                      "type": "integer"
                    },
                    "category": {
                      "type": "string"
                    },
                    "mandatory": {
                      "type": "boolean",
                      "description": "True only for legal duties verified against the cited official source."
                    },
                    "source": {
                      "type": "object",
                      "additionalProperties": false,
                      "required": [
                        "title",
                        "url"
                      ],
                      "properties": {
                        "title": {
                          "type": "string"
                        },
                        "url": {
                          "type": "string",
                          "format": "uri"
                        }
                      }
                    },
                    "note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "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"
              }
            }
          }
        }
      },
      "RepairOrReplaceInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "itemName": {
            "title": "Item",
            "type": "string",
            "maxLength": 80,
            "default": "Appliance"
          },
          "currency": {
            "title": "Currency",
            "description": "Shown in results only; no conversion is performed.",
            "type": "string",
            "maxLength": 8,
            "default": "EUR"
          },
          "itemAgeYears": {
            "title": "Age of the item",
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "default": 6,
            "x-unit": "years"
          },
          "expectedLifespanYears": {
            "title": "Typical lifespan",
            "description": "Typical total life of this kind of item; also used for the new one unless set below.",
            "type": "number",
            "minimum": 0.5,
            "maximum": 100,
            "default": 10,
            "x-unit": "years"
          },
          "replacementPrice": {
            "title": "Price of a new replacement",
            "type": "number",
            "minimum": 0.01,
            "default": 600
          },
          "repairQuote": {
            "title": "Repair quote",
            "type": "number",
            "minimum": 0,
            "default": 200
          },
          "lifeAfterRepairYears": {
            "title": "Expected extra life after repair",
            "type": "number",
            "minimum": 0.1,
            "maximum": 100,
            "default": 3,
            "x-unit": "years"
          },
          "newItemLifespanYears": {
            "title": "Lifespan of the new item (optional)",
            "type": "number",
            "minimum": 0.5,
            "maximum": 100,
            "x-unit": "years"
          },
          "runningCostOldPerYear": {
            "title": "Running cost of the old item",
            "description": "Energy, water, consumables.",
            "type": "number",
            "minimum": 0,
            "default": 0,
            "x-unit": "per year"
          },
          "runningCostNewPerYear": {
            "title": "Running cost of the new item",
            "type": "number",
            "minimum": 0,
            "default": 0,
            "x-unit": "per year"
          },
          "failureProbabilityPercent": {
            "title": "Chance of another failure after repair",
            "description": "Your estimate for the extra life period; an assumption, not a statistic.",
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "default": 30,
            "x-unit": "%"
          },
          "nextRepairCost": {
            "title": "Cost of that next repair (optional)",
            "description": "Defaults to the current repair quote.",
            "type": "number",
            "minimum": 0
          },
          "ruleThresholdPercent": {
            "title": "Rule-of-thumb threshold",
            "type": "number",
            "minimum": 1,
            "maximum": 100,
            "default": 50,
            "x-unit": "%"
          }
        },
        "required": [
          "replacementPrice",
          "repairQuote"
        ]
      },
      "RepairOrReplaceResult": {
        "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": [
              "itemName",
              "currency",
              "verdict",
              "rule50",
              "costPerYear",
              "breakEvenRepairQuote",
              "lifespanUsedPercent",
              "rulesAgree",
              "reasoning"
            ],
            "properties": {
              "itemName": {
                "type": "string"
              },
              "currency": {
                "type": "string"
              },
              "verdict": {
                "type": "string",
                "enum": [
                  "repair",
                  "replace"
                ]
              },
              "rule50": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "thresholdPercent",
                  "repairShareOfReplacementPercent",
                  "verdict"
                ],
                "properties": {
                  "thresholdPercent": {
                    "type": "number"
                  },
                  "repairShareOfReplacementPercent": {
                    "type": "number"
                  },
                  "verdict": {
                    "type": "string",
                    "enum": [
                      "repair",
                      "replace"
                    ]
                  }
                }
              },
              "costPerYear": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "repair",
                  "replace",
                  "difference",
                  "verdict",
                  "expectedExtraRepairCost",
                  "newItemLifespanYears"
                ],
                "properties": {
                  "repair": {
                    "type": "number",
                    "description": "(repair quote + P(failure) × next repair cost) ÷ extra life + old running cost per year."
                  },
                  "replace": {
                    "type": "number",
                    "description": "replacement price ÷ new lifespan + new running cost per year."
                  },
                  "difference": {
                    "type": "number",
                    "description": "replace − repair (positive = repairing is cheaper per year)."
                  },
                  "verdict": {
                    "type": "string",
                    "enum": [
                      "repair",
                      "replace"
                    ]
                  },
                  "expectedExtraRepairCost": {
                    "type": "number"
                  },
                  "newItemLifespanYears": {
                    "type": "number"
                  }
                }
              },
              "breakEvenRepairQuote": {
                "type": "number",
                "description": "Highest repair quote at which repairing still costs no more per year than replacing (0 if repairing never pays)."
              },
              "lifespanUsedPercent": {
                "type": "number"
              },
              "rulesAgree": {
                "type": "boolean"
              },
              "reasoning": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "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"
              }
            }
          }
        }
      },
      "TrueCostCalculatorInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "itemType": {
            "title": "What is it?",
            "type": "string",
            "enum": [
              "car",
              "pet",
              "appliance",
              "home",
              "gadget",
              "other"
            ],
            "default": "car"
          },
          "itemName": {
            "title": "Name",
            "type": "string",
            "maxLength": 80,
            "default": "My purchase"
          },
          "currency": {
            "title": "Currency",
            "description": "Shown in results only; no conversion is performed.",
            "type": "string",
            "maxLength": 8,
            "default": "EUR"
          },
          "purchasePrice": {
            "title": "Purchase (sticker) price",
            "type": "number",
            "minimum": 0,
            "default": 0
          },
          "yearsOwned": {
            "title": "Years you will own it",
            "type": "number",
            "minimum": 0.1,
            "maximum": 60,
            "default": 5,
            "x-unit": "years"
          },
          "resaleValue": {
            "title": "Expected resale value at the end",
            "type": "number",
            "minimum": 0,
            "default": 0
          },
          "loanAmount": {
            "title": "Loan amount",
            "description": "Leave 0 if you pay cash.",
            "type": "number",
            "minimum": 0,
            "default": 0
          },
          "aprPercent": {
            "title": "Loan APR",
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "default": 0,
            "x-unit": "%/year"
          },
          "loanTermMonths": {
            "title": "Loan term",
            "type": "integer",
            "minimum": 0,
            "maximum": 600,
            "default": 0,
            "x-unit": "months"
          },
          "maintenancePerYear": {
            "title": "Maintenance / repairs per year",
            "type": "number",
            "minimum": 0,
            "default": 0
          },
          "insurancePerYear": {
            "title": "Insurance per year",
            "type": "number",
            "minimum": 0,
            "default": 0
          },
          "energyConsumption": {
            "title": "Energy / fuel consumption",
            "description": "E.g. 6 (litres per 100 km) or 150 (kWh per year of use = 1 usage unit).",
            "type": "number",
            "minimum": 0,
            "default": 0
          },
          "consumptionPer": {
            "title": "Consumption is per",
            "type": "string",
            "enum": [
              "per-100",
              "per-1"
            ],
            "default": "per-100"
          },
          "energyUnitPrice": {
            "title": "Price per energy unit",
            "description": "E.g. price per litre or per kWh.",
            "type": "number",
            "minimum": 0,
            "default": 0
          },
          "usagePerYear": {
            "title": "Usage per year",
            "description": "E.g. km per year, wash cycles per year.",
            "type": "number",
            "minimum": 0,
            "default": 0
          },
          "recurring": {
            "title": "Other recurring costs",
            "description": "Taxes, parking, food, subscriptions, fees…",
            "type": "array",
            "maxItems": 20,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "name": {
                  "title": "Cost",
                  "type": "string"
                },
                "amount": {
                  "title": "Amount",
                  "type": "number",
                  "minimum": 0
                },
                "frequency": {
                  "title": "Every",
                  "type": "string",
                  "enum": [
                    "weekly",
                    "monthly",
                    "quarterly",
                    "yearly"
                  ],
                  "default": "monthly"
                }
              },
              "required": [
                "name",
                "amount"
              ]
            }
          }
        },
        "required": [
          "purchasePrice"
        ]
      },
      "TrueCostCalculatorResult": {
        "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": [
              "itemName",
              "itemType",
              "currency",
              "yearsOwned",
              "trueTotal",
              "perYear",
              "perMonth",
              "perDay",
              "stickerMultiplier",
              "loan",
              "buckets",
              "recurringItems"
            ],
            "properties": {
              "itemName": {
                "type": "string"
              },
              "itemType": {
                "type": "string",
                "enum": [
                  "car",
                  "pet",
                  "appliance",
                  "home",
                  "gadget",
                  "other"
                ]
              },
              "currency": {
                "type": "string"
              },
              "yearsOwned": {
                "type": "number"
              },
              "trueTotal": {
                "type": "number",
                "description": "Sum of all cost buckets over the ownership period."
              },
              "perYear": {
                "type": "number"
              },
              "perMonth": {
                "type": "number"
              },
              "perDay": {
                "type": "number"
              },
              "stickerMultiplier": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "trueTotal ÷ purchase price; null when the purchase price is 0."
              },
              "loan": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "monthlyPayment",
                  "totalInterestFullTerm",
                  "interestDuringOwnership",
                  "balanceAtEnd"
                ],
                "properties": {
                  "monthlyPayment": {
                    "type": "number"
                  },
                  "totalInterestFullTerm": {
                    "type": "number"
                  },
                  "interestDuringOwnership": {
                    "type": "number"
                  },
                  "balanceAtEnd": {
                    "type": "number",
                    "description": "Outstanding principal when you stop owning the item (to be repaid from the sale)."
                  }
                }
              },
              "buckets": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "bucket",
                    "label",
                    "total",
                    "perYear",
                    "sharePercent"
                  ],
                  "properties": {
                    "bucket": {
                      "type": "string",
                      "enum": [
                        "depreciation",
                        "financing",
                        "recurring",
                        "maintenance",
                        "insurance",
                        "energy"
                      ]
                    },
                    "label": {
                      "type": "string"
                    },
                    "total": {
                      "type": "number"
                    },
                    "perYear": {
                      "type": "number"
                    },
                    "sharePercent": {
                      "type": "number"
                    }
                  }
                }
              },
              "recurringItems": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "name",
                    "perYear",
                    "total"
                  ],
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "perYear": {
                      "type": "number"
                    },
                    "total": {
                      "type": "number"
                    }
                  }
                }
              }
            }
          },
          "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"
              }
            }
          }
        }
      }
    }
  }
}