{
  "openapi": "3.1.1",
  "info": {
    "title": "Internet, AI & productivity 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://internet.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": [
                "ai-answer-verifier",
                "error-message-translator",
                "file-format-doctor",
                "privacy-policy-decoder",
                "prompt-to-tool-router",
                "scam-signal-checker",
                "screenshot-to-steps",
                "website-change-explainer"
              ]
            }
          }
        ],
        "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/ai-answer-verifier/calculate": {
      "post": {
        "operationId": "calculateAiAnswerVerifier",
        "summary": "Split an AI answer into claims and see which ones your sources actually support.",
        "description": "Paste an AI-generated answer and the sources it should be based on (text or public URLs). Each sentence becomes a claim; check-worthy claims (numbers, dates, names, superlatives, causes) are flagged, and every claim is matched to the best-supporting source sentence with BM25 scoring and number checks.\n\nMethodology:\n- Claims = sentences of the answer with at least 15 characters.\n- Check-worthy if the claim contains numbers, years, multi-word proper names, superlatives/absolutes or causal wording.\n- Each source is split into sentences; the best match for a claim is the source sentence with the highest BM25 score (k1 = 1.2, b = 0.75) over content words.\n- Coverage = share of the claim's distinct content words found in that sentence. supported: coverage ≥ 0.7 and every number in the claim appears in it; partially-supported: coverage ≥ 0.4; contradicted-number: coverage ≥ 0.5, a number from the claim is missing from the evidence and the evidence contains a different number; otherwise not-found.\n\nThis is lexical evidence matching, not truth verification: \"supported\" means similar wording exists in your sources, not that the sources are right. Paraphrases can be missed.",
        "tags": [
          "internet"
        ],
        "x-mcp-tool": "ai_answer_verifier",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiAnswerVerifierInput"
              },
              "examples": {
                "example1": {
                  "summary": "Eiffel Tower facts",
                  "value": {
                    "answer": "The Eiffel Tower was completed in 1889 for the World's Fair in Paris. It is 330 metres tall. It was designed by Gustave Eiffel alone. It is the most visited paid monument in the world.",
                    "sources": "The Eiffel Tower was built for the 1889 World's Fair in Paris and completed in March 1889.\nIt is 330 metres (1,083 ft) tall, including antennas.\n---\nThe tower was designed by the engineers Maurice Koechlin and Émile Nouguier of Gustave Eiffel's company."
                  }
                },
                "example2": {
                  "summary": "Wrong number",
                  "value": {
                    "answer": "The company reported revenue of 12 billion euros in 2025.",
                    "sources": "In 2025 the company reported revenue of 9.4 billion euros, up 3% from the previous year."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiAnswerVerifierResult"
                }
              }
            }
          },
          "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/error-message-translator/calculate": {
      "post": {
        "operationId": "calculateErrorMessageTranslator",
        "summary": "Paste a technical error and get the plain-English cause and troubleshooting steps.",
        "description": "Matches your error message against a database of over 120 known errors (HTTP status codes, TLS/certificate, DNS, network, filesystem, Node.js, Python, Java, npm, pip, git, Docker, SQL and Windows codes), explains the cause in plain English and fills the concrete file, host, port or package from your message into the steps.\n\nMethodology:\n- Every pattern is a regular expression with a specificity score from 1 (generic, e.g. \"permission denied\") to 10 (one exact error code).\n- All matching patterns are ranked by specificity, then by how early in the message they match; the top one is explained, the rest are listed.\n- If you pick a context, patterns from matching categories get +2 specificity when ranking.\n- Concrete values (URL, host, port, path, module, package, status/error code) are extracted from the message and inserted into the steps.\n- No match → generic triage steps; nothing is guessed.",
        "tags": [
          "internet"
        ],
        "x-mcp-tool": "error_message_translator",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ErrorMessageTranslatorInput"
              },
              "examples": {
                "example1": {
                  "summary": "Database refused connection",
                  "value": {
                    "message": "Error: connect ECONNREFUSED 127.0.0.1:5432\n    at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1555:16)",
                    "context": "code"
                  }
                },
                "example2": {
                  "summary": "Python missing module",
                  "value": {
                    "message": "Traceback (most recent call last):\n  File \"app.py\", line 1, in <module>\n    import requests\nModuleNotFoundError: No module named 'requests'",
                    "context": "terminal"
                  }
                },
                "example3": {
                  "summary": "Browser 502",
                  "value": {
                    "message": "502 Bad Gateway nginx/1.24.0",
                    "context": "browser"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessageTranslatorResult"
                }
              }
            }
          },
          "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/file-format-doctor/calculate": {
      "post": {
        "operationId": "calculateFileFormatDoctor",
        "summary": "Find out what a file really is from its bytes, why it will not open and how to convert it.",
        "description": "Upload a file (or paste its first bytes as hex) and the doctor reads its magic number against a table of 74 formats, looks inside ZIP containers (DOCX, XLSX, ODT, EPUB, JAR, APK), and diagnoses wrong extensions, truncated or encrypted files, text encoding problems and disguised executables — with offline conversion commands.\n\nMethodology:\n- Magic numbers are matched at their documented offsets for 74 formats (e.g. \"%PDF-\" at 0, \"ustar\" at 257, \"CD001\" at 0x8001, \"ftyp\" brands at 4).\n- ISO-BMFF files are told apart by their ftyp brands (heic/heix → HEIC, mif1 → HEIF, avif → AVIF, qt → QuickTime, M4A → audio, isom/mp42 → MP4).\n- ZIP files are opened by reading the central directory (or local file headers in a sample): [Content_Types].xml + word/ → DOCX, xl/ → XLSX, ppt/ → PPTX, the stored \"mimetype\" entry → ODT/ODS/ODP/EPUB, AndroidManifest.xml → APK, META-INF/MANIFEST.MF → JAR. General-purpose bit 0 marks encrypted entries.\n- Without a binary signature the bytes are checked for BOMs, UTF-16 patterns, strict UTF-8 validity and typical mojibake sequences (e.g. \"Ã©\", \"â€™\"), then for SVG/HTML/XML/JSON/CSV structure.\n- Truncation checks (uploads only): PDF must end with %%EOF, PNG with IEND, JPEG with FF D9, GIF with 3B, ZIP must have an end-of-central-directory record, RIFF/BMP declared sizes must fit.\n- Conversion suggestions use free, offline tools (LibreOffice, ImageMagick, FFmpeg, 7-Zip, iconv) with the exact command for your file name.\n\nDetection reads bytes only; it does not scan for malware. Never run an executable you did not expect to receive.",
        "tags": [
          "internet"
        ],
        "x-mcp-tool": "file_format_doctor",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FileFormatDoctorInput"
              },
              "examples": {
                "example1": {
                  "summary": "iPhone photo renamed to .jpg (HEIC inside)",
                  "value": {
                    "filename": "IMG_0420.jpg",
                    "hexBytes": "00 00 00 18 66 74 79 70 68 65 69 63 00 00 00 00 6d 69 66 31 68 65 69 63"
                  }
                },
                "example2": {
                  "summary": "Invoice that is really a Windows program",
                  "value": {
                    "filename": "invoice_2026.pdf.exe",
                    "hexBytes": "4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00"
                  }
                },
                "example3": {
                  "summary": "Word document (ZIP local header with word/ entry)",
                  "value": {
                    "filename": "contract.zip",
                    "hexBytes": "50 4B 03 04 14 00 00 00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 11 00 00 00 77 6F 72 64 2F 64 6F 63 75 6D 65 6E 74 2E 78 6D 6C"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileFormatDoctorResult"
                }
              }
            }
          },
          "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/privacy-policy-decoder/calculate": {
      "post": {
        "operationId": "calculatePrivacyPolicyDecoder",
        "summary": "What a privacy policy says it collects, shares, sells and keeps — with quoted evidence.",
        "description": "Give the URL of a privacy policy or paste/upload its text (English or German). The decoder lists which data categories, purposes, sharing and sale practices, retention periods, user rights, laws (GDPR, CCPA/CPRA …), international transfer mechanisms and contacts the policy mentions, quotes the sentences, and points out topics it does not mention.\n\nMethodology:\n- The policy is split into sentences; every sentence is tested against fixed English and German keyword patterns for 7 sections: data collected, purposes, sharing & selling, rights, laws, international transfers and contact.\n- An item is \"mentioned\" when at least one sentence matches; up to 3 matching sentences are quoted. If every matching sentence contains a negation (\"we do not\", \"nicht\", \"keine\"), the item is marked as negated.\n- Sale of data is classified from sentences with sell/sale/verkaufen: negated sentences count as \"does not sell\", others as \"sells or may sell\"; both present = \"mixed statements\".\n- Retention periods are durations (e.g. \"7 years\", \"nach 7 Tagen\") found in sentences about retaining, storing or deleting data; open-ended phrases like \"as long as necessary\" are flagged as vague.\n- Children's age thresholds are numbers in phrases like \"under the age of 13\" / \"unter 16 Jahren\". \"Not mentioned\" means no pattern matched — not that the practice does not happen.\n\nRule-based keyword analysis of the policy text, not legal advice and not a compliance audit. A policy can describe practices in wording these patterns miss, and what a company does may differ from what its policy says.",
        "tags": [
          "internet"
        ],
        "x-mcp-tool": "privacy_policy_decoder",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PrivacyPolicyDecoderInput"
              },
              "examples": {
                "example1": {
                  "summary": "App privacy policy (English)",
                  "value": {
                    "text": "Privacy Policy\nWe collect your name, email address and phone number when you register. We also collect your precise location, IP address and advertising ID, and we use cookies and tracking pixels.\nWe use your information to provide our services, for analytics and for personalized advertising. We may share your information with advertising partners and data brokers. We may sell your personal information; California residents can opt out via the \"Do Not Sell or Share My Personal Information\" link (CCPA/CPRA).\nWe retain your data for as long as necessary to provide our services. Payment records are kept for 7 years.\nYou have the right to access, delete and correct your personal information. Our services are not directed to children under the age of 13.\nYour data may be transferred to the United States under Standard Contractual Clauses.\nContact: privacy@example-app.com"
                  }
                },
                "example2": {
                  "summary": "Datenschutzerklärung (Deutsch)",
                  "value": {
                    "text": "Datenschutzerklärung\nVerantwortlicher im Sinne der DSGVO ist die Beispiel GmbH. Unseren Datenschutzbeauftragten erreichen Sie unter datenschutz@beispiel.de.\nWir verarbeiten Ihre E-Mail-Adresse, Ihre Anschrift und Zahlungsdaten zur Vertragserfüllung. Beim Besuch unserer Website wird Ihre IP-Adresse gespeichert und nach 7 Tagen gelöscht.\nWir setzen Cookies nur mit Ihrer Einwilligung ein. Eine Weitergabe an Dritte erfolgt nur an Dienstleister im Rahmen der Auftragsverarbeitung. Wir verkaufen Ihre Daten nicht.\nRechnungsdaten bewahren wir aufgrund gesetzlicher Pflichten 10 Jahre auf.\nSie haben das Recht auf Auskunft, Berichtigung, Löschung, Einschränkung der Verarbeitung, Datenübertragbarkeit und Widerspruch. Sie können Ihre Einwilligung jederzeit widerrufen und sich bei einer Aufsichtsbehörde beschweren."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PrivacyPolicyDecoderResult"
                }
              }
            }
          },
          "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/prompt-to-tool-router/calculate": {
      "post": {
        "operationId": "calculatePromptToToolRouter",
        "summary": "Describe your problem in plain words and get the right tools and order to use them.",
        "description": "Takes a natural-language request (English or German) and ranks the usefulweb.site tools and workflows that can solve it, using transparent keyword matching (TF-IDF with synonyms), and proposes a sequence of tool calls.\n\nMethodology:\n- The request is lower-cased, split into words, stop words (EN/DE) removed, lightly stemmed and expanded with a published synonym table.\n- Each tool is indexed by name (weight 3), keywords (2.5), id (2) and tagline (1.5); score = Σ weight × ln(1 + N/df) over matched terms, +4 per exact keyword phrase.\n- If a workflow scores at least 60% of the best tool score, its steps become the plan; otherwise the top tools are planned in score order.",
        "tags": [
          "internet"
        ],
        "x-mcp-tool": "prompt_to_tool_router",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PromptToToolRouterInput"
              },
              "examples": {
                "example1": {
                  "summary": "Moving into a new apartment",
                  "value": {
                    "request": "I'm moving into a new apartment. Can you help me plan everything and avoid unnecessary expenses? Will my sofa fit through the door?"
                  }
                },
                "example2": {
                  "summary": "Suspicious SMS",
                  "value": {
                    "request": "I got an SMS saying my parcel is held and I must pay a customs fee via a link. Is this a scam?"
                  }
                },
                "example3": {
                  "summary": "Kündigung",
                  "value": {
                    "request": "Ich möchte mein Fitnessstudio-Abo kündigen und verstehen welche Fristen gelten"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PromptToToolRouterResult"
                }
              }
            }
          },
          "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/scam-signal-checker/calculate": {
      "post": {
        "operationId": "calculateScamSignalChecker",
        "summary": "Check a message or link for common scam and phishing warning signs — without clicking.",
        "description": "Paste a suspicious e-mail, SMS or chat message and/or links (English or German). The checker looks for documented warning signs — urgency, threats, gift-card or crypto payment, requests for passwords or codes, lookalike and punycode domains, brand/domain mismatches, URL shorteners, risky attachments — and gives a weighted, explained score. Links are analysed statically and never opened. It never declares a message safe.\n\nMethodology:\n- Nothing is fetched or clicked: links are parsed as text (WHATWG URL parser) and compared with rules.\n- Each signal has a fixed weight; the score is the sum of the weights of the distinct signals found, capped at 100. Weights: urgency 15, threat 20, gift-card 30, crypto 25, wire 20, advance-fee 15, credentials 30, remote-access 25, prize 20, parcel-lure 10, generic-greeting 5, family-new-number 25, secrecy 10, investment 15, brand-domain-mismatch 30, lookalike-domain 35, punycode 25, shortener 10, ip-literal 25, at-in-url 25, display-mismatch 30, suspicious-tld 10, many-subdomains 10, no-https 10, sender-brand-mismatch 25, risky-attachment 30, double-extension 10.\n- Verdict: ≥ 50 \"high-risk signals\", 20–49 \"some warning signs\", 1–19 \"minor signals only\", 0 \"no common warning signs found\". No level means \"safe\" — scams without these patterns exist.\n- Brand checks use an editorial list of 67 frequently impersonated brands and their main official domains: lookalikes are detected by homoglyph normalisation (0→o, 1→l, rn→m, Cyrillic letters …) and edit distance (1 for names ≥ 5 letters, 2 for ≥ 9); brand names inside other domains or paths count as brand/domain mismatch.\n- The suspicious-TLD list is a heuristic (.zip .mov .top .xyz .click .link .work .support .rest .fit .cfd .sbs .icu .buzz .cam .gq .ml .cf .ga .tk .monster .quest .lol .cyou .bond .shop .online .site .live .info .ru .su); plenty of legitimate sites use these endings, so the weight is low.\n- Language rules cover English and German phrasing (e.g. \"Ihr Konto wurde gesperrt\", \"Zollgebühr\", \"Paket\", \"Hallo Mama, das ist meine neue Nummer\"). Each signal quotes the sentence, URL or file name that triggered it.\n\nA low score never means a message is safe. This is a static pattern check, not a malware scan or a verdict on the sender. When in doubt, contact the company through its official app, website or phone number — never via links or numbers in the message.",
        "tags": [
          "internet"
        ],
        "x-mcp-tool": "scam_signal_checker",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScamSignalCheckerInput"
              },
              "examples": {
                "example1": {
                  "summary": "German bank phishing e-mail",
                  "value": {
                    "message": "Sehr geehrter Kunde,\nIhr Konto wurde vorübergehend gesperrt. Bitte bestätigen Sie Ihre Zugangsdaten innerhalb von 24 Stunden, sonst wird Ihr Online-Banking dauerhaft deaktiviert.\nJetzt entsperren: http://sparkasse-sicherheit.konto-verifizierung.top/login\nIhre Sparkasse",
                    "senderAddress": "service@sparkasse-kundenservice.info"
                  }
                },
                "example2": {
                  "summary": "Parcel SMS with lookalike link",
                  "value": {
                    "message": "DHL: Your parcel could not be delivered. A redelivery fee of 1.99 EUR is due. Pay now: https://dhI-redelivery.com/track?id=8812",
                    "urls": [
                      "https://xn--pypal-4ve.com/signin",
                      "bit.ly/3xYzAbc"
                    ],
                    "attachments": [
                      "Sendungsdetails.pdf.exe"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScamSignalCheckerResult"
                }
              }
            }
          },
          "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/screenshot-to-steps/calculate": {
      "post": {
        "operationId": "calculateScreenshotToSteps",
        "summary": "Turn a screenshot of an app or website into numbered steps for what you want to do.",
        "description": "Upload a screenshot (or paste the visible labels) and say what you want to achieve. The text on screen is read with OCR, each label is classified as button, input field, navigation, link, checkbox or heading with its position, and the elements relevant to your goal are turned into numbered instructions.\n\nMethodology:\n- OCR: tesseract (English) with word positions; words with confidence below 30 are dropped; words on one line are split into separate elements at gaps wider than 1.8× the text height.\n- Roles are assigned by rules: known action words → button; trailing colon or known field names → input field; short labels in the top 12% or known section names → navigation; URLs/\"forgot…\" → link; ☐/[ ] → checkbox; text 1.5× taller than median → heading.\n- Your goal is split into keywords and expanded with synonyms (e.g. password → security, login). Steps: open the best-matching navigation item (if no matching field is visible), fill visible input fields, tick relevant checkboxes, then click the primary button (Save/Continue/OK…).\n- Position is reported as a 3×3 grid region (top/middle/bottom × left/center/right).\n\nSteps are derived only from text visible in the screenshot; icons without labels and hidden menus cannot be seen. Never upload screenshots that show passwords or card numbers.",
        "tags": [
          "internet"
        ],
        "x-mcp-tool": "screenshot_to_steps",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScreenshotToStepsInput"
              },
              "examples": {
                "example1": {
                  "summary": "Change password (labels pasted)",
                  "value": {
                    "goal": "Change my password",
                    "uiText": "Account settings\nProfile\nSecurity\nNotifications\nCurrent password:\nNew password:\nConfirm password:\n[ ] Sign out of all other devices\nCancel\nSave"
                  }
                },
                "example2": {
                  "summary": "Find the settings",
                  "value": {
                    "goal": "turn off notifications",
                    "uiText": "Home\nSearch\nNotifications\nMessages\nSettings\nWhat is happening?\nPost"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScreenshotToStepsResult"
                }
              }
            }
          },
          "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/website-change-explainer/calculate": {
      "post": {
        "operationId": "calculateWebsiteChangeExplainer",
        "summary": "Compare two versions of a page and see which changes matter: prices, terms, dates, links.",
        "description": "Give a \"before\" and an \"after\" version of a web page (fetch a URL now or paste saved HTML/text). The tool extracts readable blocks, title, meta description, headings, links, prices and dates, diffs them block by block and word by word, and ranks meaningful changes above noise like whitespace, tracking parameters, timestamps or copyright years.\n\nMethodology:\n- Each side is parsed (tolerant HTML tree builder; plain text is split into lines). Text is collected per block-level element (p, li, h1–h6, td, …); scripts, styles and navigation-less noise like <svg> are skipped.\n- Blocks are aligned with a longest-common-subsequence diff over whitespace-normalised text; adjacent removed/added blocks with ≥ 40 % word overlap (Dice) are paired as \"modified\" and diffed word by word.\n- A change is trivial when it disappears after masking whitespace/case, clock times, \"N minutes ago\", copyright years and long hex/random tokens; links differing only in tracking parameters (utm_*, gclid, fbclid, …) are trivial.\n- Meaningful categories and scores: price 100, legal/terms keyword 90, contact (email/phone) 75, link target 70, title 65, date 60, heading 55, other number 45, meta description 40, link removed/added 35/30, other text 20 (+ up to 15 for size). Changes are ranked by score, then document order.\n- Every change lists the rule ids and matched tokens that produced its category.\n\nRule-based comparison of static HTML. Pages that build content with JavaScript may show fewer blocks than a browser; always read the actual wording of legal changes.",
        "tags": [
          "internet"
        ],
        "x-mcp-tool": "website_change_explainer",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebsiteChangeExplainerInput"
              },
              "examples": {
                "example1": {
                  "summary": "Pricing page: price rise, new auto-renewal clause, tracking link",
                  "value": {
                    "beforeContent": "<html><head><title>Pricing – Acme Cloud</title><meta name=\"description\" content=\"Simple pricing for teams.\"></head><body>\n<h1>Pricing</h1><h2>Pro plan</h2><p>Pro costs $12 per month per user.</p><p>Cancel anytime from your dashboard.</p>\n<p>Questions? Email sales@acme.example or call +1 555 010 2000.</p>\n<a href=\"https://acme.example/terms?utm_source=footer\">Terms</a> <a href=\"https://acme.example/signup\">Start trial</a>\n<footer><p>© 2025 Acme Inc. Page generated at 10:15</p></footer></body></html>",
                    "afterContent": "<html><head><title>Pricing – Acme Cloud</title><meta name=\"description\" content=\"Simple pricing for teams.\"></head><body>\n<h1>Pricing</h1><h2>Pro plan</h2><p>Pro costs $15 per month per user.</p><p>Plans renew automatically each year; cancellation requires 30 days notice.</p>\n<p>Questions? Email sales@acme.example or call +1 555 010 2000.</p>\n<a href=\"https://acme.example/terms?utm_source=header\">Terms</a> <a href=\"https://acme.example/signup-2026\">Start trial</a>\n<h2>Enterprise</h2><p>Contact us for volume pricing.</p>\n<footer><p>© 2026 Acme Inc. Page generated at 09:02</p></footer></body></html>",
                    "includeTrivial": true,
                    "maxChanges": 50
                  }
                },
                "example2": {
                  "summary": "Plain-text policy: changed deadline",
                  "value": {
                    "beforeContent": "Returns policy\nYou can return items within 30 days of delivery.\nRefunds are issued within 14 days.\nLast reviewed: 2026-01-10",
                    "afterContent": "Returns policy\nYou can return items within 14 days of delivery.\nRefunds are issued within 14 days.\nLast reviewed: 2026-09-01",
                    "includeTrivial": false,
                    "maxChanges": 20
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebsiteChangeExplainerResult"
                }
              }
            }
          },
          "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"
                }
              }
            }
          }
        }
      },
      "AiAnswerVerifierInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "answer": {
            "title": "AI answer",
            "type": "string",
            "maxLength": 50000
          },
          "sources": {
            "title": "Source texts",
            "description": "Paste one or more sources. Separate sources with a line containing only ---",
            "type": "string",
            "maxLength": 400000
          },
          "sourceUrls": {
            "title": "Source URLs (one per line)",
            "description": "Public pages fetched once (max 5).",
            "type": "array",
            "items": {
              "type": "string"
            },
            "maxItems": 5
          }
        },
        "required": [
          "answer"
        ]
      },
      "AiAnswerVerifierResult": {
        "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": [
              "counts",
              "claims",
              "sources"
            ],
            "properties": {
              "counts": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "claims",
                  "supported",
                  "partiallySupported",
                  "contradictedNumber",
                  "notFound",
                  "checkWorthy"
                ],
                "properties": {
                  "claims": {
                    "type": "integer"
                  },
                  "supported": {
                    "type": "integer"
                  },
                  "partiallySupported": {
                    "type": "integer"
                  },
                  "contradictedNumber": {
                    "type": "integer"
                  },
                  "notFound": {
                    "type": "integer"
                  },
                  "checkWorthy": {
                    "type": "integer"
                  }
                }
              },
              "sources": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "label",
                    "characters"
                  ],
                  "properties": {
                    "label": {
                      "type": "string"
                    },
                    "characters": {
                      "type": "integer"
                    }
                  }
                }
              },
              "claims": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "index",
                    "claim",
                    "checkWorthy",
                    "verdict",
                    "coverage",
                    "score",
                    "evidence",
                    "numbersNotInEvidence"
                  ],
                  "properties": {
                    "index": {
                      "type": "integer"
                    },
                    "claim": {
                      "type": "string"
                    },
                    "checkWorthy": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "verdict": {
                      "type": "string",
                      "enum": [
                        "supported",
                        "partially-supported",
                        "contradicted-number",
                        "not-found"
                      ]
                    },
                    "coverage": {
                      "type": "number",
                      "minimum": 0,
                      "maximum": 1
                    },
                    "score": {
                      "type": "number"
                    },
                    "evidence": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "additionalProperties": false,
                      "required": [
                        "source",
                        "sentence"
                      ],
                      "properties": {
                        "source": {
                          "type": "string"
                        },
                        "sentence": {
                          "type": "string"
                        }
                      }
                    },
                    "numbersNotInEvidence": {
                      "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"
              }
            }
          }
        }
      },
      "ErrorMessageTranslatorInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "message": {
            "title": "Error message",
            "type": "string",
            "maxLength": 20000
          },
          "context": {
            "title": "Where did you see it?",
            "type": "string",
            "enum": [
              "any",
              "browser",
              "terminal",
              "windows",
              "code"
            ],
            "default": "any"
          }
        },
        "required": [
          "message"
        ]
      },
      "ErrorMessageTranslatorResult": {
        "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": [
              "matched",
              "primary",
              "otherMatches",
              "variables",
              "patternCount"
            ],
            "properties": {
              "matched": {
                "type": "boolean"
              },
              "patternCount": {
                "type": "integer"
              },
              "variables": {
                "type": "object",
                "additionalProperties": {
                  "type": "string"
                }
              },
              "primary": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": false,
                "required": [
                  "id",
                  "title",
                  "category",
                  "severity",
                  "specificity",
                  "matchedText",
                  "cause",
                  "likelyCauses",
                  "steps"
                ],
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "title": {
                    "type": "string"
                  },
                  "category": {
                    "type": "string"
                  },
                  "severity": {
                    "type": "string",
                    "enum": [
                      "low",
                      "medium",
                      "high",
                      "critical"
                    ]
                  },
                  "specificity": {
                    "type": "integer"
                  },
                  "matchedText": {
                    "type": "string"
                  },
                  "cause": {
                    "type": "string"
                  },
                  "likelyCauses": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "steps": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              },
              "otherMatches": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "id",
                    "title",
                    "category",
                    "specificity",
                    "matchedText"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "title": {
                      "type": "string"
                    },
                    "category": {
                      "type": "string"
                    },
                    "specificity": {
                      "type": "integer"
                    },
                    "matchedText": {
                      "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"
              }
            }
          }
        }
      },
      "FileFormatDoctorInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "file": {
            "title": "File",
            "description": "Analysed in memory and not stored. Max 10 MiB. Upload as {filename, contentType?, contentBase64}. Max 10240 KiB. Accepts */*.",
            "type": "object",
            "additionalProperties": false,
            "required": [
              "filename",
              "contentBase64"
            ],
            "properties": {
              "filename": {
                "type": "string"
              },
              "contentType": {
                "type": "string"
              },
              "contentBase64": {
                "type": "string"
              }
            }
          },
          "filename": {
            "title": "File name (for hex input)",
            "description": "Used to compare the extension with the detected format. Ignored when a file is uploaded.",
            "type": "string",
            "maxLength": 255
          },
          "hexBytes": {
            "title": "Or: first bytes as hex",
            "description": "E.g. from `xxd -l 512 file` or `Format-Hex`. At least 16 bytes recommended; 512+ for ZIP-based formats.",
            "type": "string",
            "maxLength": 140000
          }
        },
        "required": []
      },
      "FileFormatDoctorResult": {
        "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": [
              "input",
              "detected",
              "alternatives",
              "extensionMatches",
              "encrypted",
              "executable",
              "container",
              "text",
              "diagnoses",
              "conversions"
            ],
            "properties": {
              "input": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "mode",
                  "filename",
                  "extension",
                  "bytesAnalyzed",
                  "completeFile"
                ],
                "properties": {
                  "mode": {
                    "type": "string",
                    "enum": [
                      "upload",
                      "hex"
                    ]
                  },
                  "filename": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "extension": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "bytesAnalyzed": {
                    "type": "integer",
                    "minimum": 0
                  },
                  "completeFile": {
                    "type": "boolean",
                    "description": "True for uploads (truncation checks possible); false for hex samples."
                  }
                }
              },
              "detected": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "id",
                  "name",
                  "mime",
                  "category",
                  "extensions",
                  "confidence",
                  "evidence"
                ],
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  },
                  "mime": {
                    "type": "string"
                  },
                  "category": {
                    "type": "string"
                  },
                  "extensions": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "confidence": {
                    "type": "string",
                    "enum": [
                      "high",
                      "medium",
                      "low"
                    ]
                  },
                  "evidence": {
                    "type": "string"
                  }
                }
              },
              "alternatives": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "id",
                    "name",
                    "evidence"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "evidence": {
                      "type": "string"
                    }
                  }
                }
              },
              "extensionMatches": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "encrypted": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "null = cannot be determined from the bytes provided."
              },
              "executable": {
                "type": "boolean"
              },
              "container": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": false,
                "required": [
                  "entries",
                  "sampleEntries",
                  "encryptedEntries",
                  "hasEndRecord",
                  "mimetype"
                ],
                "properties": {
                  "entries": {
                    "type": "integer"
                  },
                  "sampleEntries": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "maxItems": 20
                  },
                  "encryptedEntries": {
                    "type": "integer"
                  },
                  "hasEndRecord": {
                    "type": "boolean"
                  },
                  "mimetype": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                }
              },
              "text": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": false,
                "required": [
                  "encoding",
                  "bom",
                  "mojibake"
                ],
                "properties": {
                  "encoding": {
                    "type": "string"
                  },
                  "bom": {
                    "type": "boolean"
                  },
                  "mojibake": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              },
              "diagnoses": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "code",
                    "severity",
                    "message",
                    "evidence"
                  ],
                  "properties": {
                    "code": {
                      "type": "string"
                    },
                    "severity": {
                      "type": "string",
                      "enum": [
                        "critical",
                        "warning",
                        "info",
                        "ok"
                      ]
                    },
                    "message": {
                      "type": "string"
                    },
                    "evidence": {
                      "type": "string"
                    }
                  }
                }
              },
              "conversions": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "goal",
                    "tool",
                    "command",
                    "note"
                  ],
                  "properties": {
                    "goal": {
                      "type": "string"
                    },
                    "tool": {
                      "type": "string"
                    },
                    "command": {
                      "type": "string"
                    },
                    "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"
              }
            }
          }
        }
      },
      "PrivacyPolicyDecoderInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "text": {
            "title": "Privacy policy 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"
              }
            }
          },
          "url": {
            "title": "Or the privacy policy URL",
            "description": "A public http(s) address. The page text is fetched once and analysed.",
            "type": "string",
            "format": "uri"
          }
        },
        "required": []
      },
      "PrivacyPolicyDecoderResult": {
        "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": [
              "confidence",
              "sections",
              "sale",
              "retention",
              "childrenAgeThresholds",
              "contactEmails",
              "flags",
              "gaps",
              "sentences"
            ],
            "properties": {
              "confidence": {
                "type": "string",
                "const": "pattern-match"
              },
              "sentences": {
                "type": "integer",
                "minimum": 0
              },
              "sections": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "id",
                    "title",
                    "items"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "title": {
                      "type": "string"
                    },
                    "items": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": false,
                        "required": [
                          "id",
                          "label",
                          "status",
                          "negated",
                          "evidence"
                        ],
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "label": {
                            "type": "string"
                          },
                          "status": {
                            "type": "string",
                            "enum": [
                              "mentioned",
                              "not mentioned"
                            ]
                          },
                          "negated": {
                            "type": "boolean",
                            "description": "All evidence sentences contain a negation (e.g. \"we do not …\")."
                          },
                          "evidence": {
                            "type": "array",
                            "maxItems": 3,
                            "items": {
                              "type": "object",
                              "additionalProperties": false,
                              "required": [
                                "quote",
                                "rule"
                              ],
                              "properties": {
                                "quote": {
                                  "type": "string"
                                },
                                "rule": {
                                  "type": "string"
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              },
              "sale": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "status",
                  "evidence"
                ],
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "says it sells or may sell",
                      "says it does not sell",
                      "mixed statements",
                      "not mentioned"
                    ]
                  },
                  "evidence": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              },
              "retention": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "periods",
                  "vague",
                  "evidence"
                ],
                "properties": {
                  "periods": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "additionalProperties": false,
                      "required": [
                        "duration",
                        "approxDays",
                        "evidence"
                      ],
                      "properties": {
                        "duration": {
                          "type": "string"
                        },
                        "approxDays": {
                          "type": "number"
                        },
                        "evidence": {
                          "type": "string"
                        }
                      }
                    }
                  },
                  "vague": {
                    "type": "boolean",
                    "description": "Uses open-ended wording such as \"as long as necessary\"."
                  },
                  "evidence": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              },
              "childrenAgeThresholds": {
                "type": "array",
                "items": {
                  "type": "integer"
                }
              },
              "contactEmails": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "flags": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "flag",
                    "rule"
                  ],
                  "properties": {
                    "flag": {
                      "type": "string"
                    },
                    "rule": {
                      "type": "string"
                    }
                  }
                }
              },
              "gaps": {
                "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"
              }
            }
          }
        }
      },
      "PromptToToolRouterInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "request": {
            "title": "What do you want to do?",
            "type": "string",
            "maxLength": 4000
          },
          "maxResults": {
            "title": "Max tools",
            "type": "integer",
            "minimum": 1,
            "maximum": 15,
            "default": 5
          }
        },
        "required": [
          "request"
        ]
      },
      "PromptToToolRouterResult": {
        "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": [
              "queryTerms",
              "tools",
              "workflows",
              "plan"
            ],
            "properties": {
              "queryTerms": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "tools": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "id",
                    "name",
                    "score",
                    "matchedTerms",
                    "matchedPhrases",
                    "url"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "score": {
                      "type": "number"
                    },
                    "matchedTerms": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "matchedPhrases": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "url": {
                      "type": "string"
                    }
                  }
                }
              },
              "workflows": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "id",
                    "name",
                    "score",
                    "steps"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "score": {
                      "type": "number"
                    },
                    "steps": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "plan": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "step",
                    "toolId",
                    "reason"
                  ],
                  "properties": {
                    "step": {
                      "type": "integer"
                    },
                    "toolId": {
                      "type": "string"
                    },
                    "reason": {
                      "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"
              }
            }
          }
        }
      },
      "ScamSignalCheckerInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "message": {
            "title": "Message text",
            "description": "Paste the full e-mail, SMS or chat message. HTML source is fine (links inside <a href> are compared with their text).",
            "type": "string",
            "maxLength": 50000
          },
          "urls": {
            "title": "Links to check (one per line)",
            "description": "Optional. Copy links via right-click → \"Copy link address\". They are not opened.",
            "type": "array",
            "items": {
              "type": "string"
            },
            "maxItems": 20
          },
          "senderAddress": {
            "title": "Sender address or number",
            "description": "Optional, e.g. the full e-mail address after \"From:\".",
            "type": "string",
            "maxLength": 320
          },
          "attachments": {
            "title": "Attachment file names (one per line)",
            "description": "Optional. Only the names are checked; do not upload the files.",
            "type": "array",
            "items": {
              "type": "string"
            },
            "maxItems": 20
          }
        },
        "required": []
      },
      "ScamSignalCheckerResult": {
        "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": [
              "score",
              "maxScore",
              "verdict",
              "verdictLabel",
              "confidence",
              "signals",
              "urls",
              "claimedBrands",
              "advice",
              "reportingResources"
            ],
            "properties": {
              "score": {
                "type": "integer",
                "minimum": 0,
                "maximum": 100
              },
              "maxScore": {
                "type": "integer",
                "const": 100
              },
              "verdict": {
                "type": "string",
                "enum": [
                  "high-risk-signals",
                  "some-warning-signs",
                  "minor-signals",
                  "no-common-signals"
                ]
              },
              "verdictLabel": {
                "type": "string"
              },
              "confidence": {
                "type": "string",
                "const": "pattern-match"
              },
              "signals": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "id",
                    "label",
                    "weight",
                    "category",
                    "evidence",
                    "detail"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "label": {
                      "type": "string"
                    },
                    "weight": {
                      "type": "integer",
                      "minimum": 0
                    },
                    "category": {
                      "type": "string",
                      "enum": [
                        "language",
                        "payment",
                        "credentials",
                        "link",
                        "sender",
                        "attachment"
                      ]
                    },
                    "evidence": {
                      "type": "string",
                      "description": "Exact sentence, URL or file name that triggered the rule."
                    },
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              },
              "urls": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "url",
                    "host",
                    "displayHost",
                    "registrableDomain",
                    "officialBrand",
                    "flags"
                  ],
                  "properties": {
                    "url": {
                      "type": "string"
                    },
                    "host": {
                      "type": "string"
                    },
                    "displayHost": {
                      "type": "string"
                    },
                    "registrableDomain": {
                      "type": "string"
                    },
                    "officialBrand": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "flags": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "claimedBrands": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "advice": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "reportingResources": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "name",
                    "url",
                    "note"
                  ],
                  "properties": {
                    "name": {
                      "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"
              }
            }
          }
        }
      },
      "ScreenshotToStepsInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "goal": {
            "title": "What do you want to do?",
            "type": "string",
            "maxLength": 300
          },
          "file": {
            "title": "Screenshot",
            "description": "PNG or JPG, max 5 MiB. Read with OCR on our server; not stored. Upload as {filename, contentType?, contentBase64}. Max 5120 KiB. Accepts .png,.jpg,.jpeg.",
            "type": "object",
            "additionalProperties": false,
            "required": [
              "filename",
              "contentBase64"
            ],
            "properties": {
              "filename": {
                "type": "string"
              },
              "contentType": {
                "type": "string"
              },
              "contentBase64": {
                "type": "string"
              }
            }
          },
          "uiText": {
            "title": "Or: visible labels, one per line (top to bottom)",
            "type": "string",
            "maxLength": 20000
          }
        },
        "required": [
          "goal"
        ]
      },
      "ScreenshotToStepsResult": {
        "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",
              "matchedGoal",
              "goalTerms",
              "steps",
              "elements"
            ],
            "properties": {
              "goal": {
                "type": "string"
              },
              "method": {
                "type": "string",
                "enum": [
                  "tesseract-ocr",
                  "pasted-labels"
                ]
              },
              "matchedGoal": {
                "type": "boolean"
              },
              "goalTerms": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "steps": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "n",
                    "action",
                    "elementId"
                  ],
                  "properties": {
                    "n": {
                      "type": "integer"
                    },
                    "action": {
                      "type": "string"
                    },
                    "elementId": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              },
              "elements": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "id",
                    "text",
                    "role",
                    "region",
                    "box",
                    "confidence"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "text": {
                      "type": "string"
                    },
                    "role": {
                      "type": "string",
                      "enum": [
                        "button",
                        "field",
                        "navigation",
                        "heading",
                        "link",
                        "checkbox",
                        "text"
                      ]
                    },
                    "region": {
                      "type": "string"
                    },
                    "box": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "additionalProperties": false,
                      "required": [
                        "left",
                        "top",
                        "width",
                        "height"
                      ],
                      "properties": {
                        "left": {
                          "type": "number"
                        },
                        "top": {
                          "type": "number"
                        },
                        "width": {
                          "type": "number"
                        },
                        "height": {
                          "type": "number"
                        }
                      }
                    },
                    "confidence": {
                      "type": [
                        "number",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          },
          "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"
              }
            }
          }
        }
      },
      "WebsiteChangeExplainerInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "beforeUrl": {
            "title": "Before: URL",
            "description": "Fetched now. Usually you paste the old version below (e.g. from a saved copy or web archive).",
            "type": "string",
            "format": "uri"
          },
          "beforeContent": {
            "title": "Before: pasted HTML or text",
            "type": "string",
            "maxLength": 400000
          },
          "afterUrl": {
            "title": "After: URL",
            "description": "Fetched now (the live page).",
            "type": "string",
            "format": "uri"
          },
          "afterContent": {
            "title": "After: pasted HTML or text",
            "type": "string",
            "maxLength": 400000
          },
          "includeTrivial": {
            "title": "List trivial changes too",
            "type": "boolean",
            "default": false
          },
          "maxChanges": {
            "title": "Max changes listed",
            "type": "integer",
            "minimum": 5,
            "maximum": 500,
            "default": 50
          }
        },
        "required": []
      },
      "WebsiteChangeExplainerResult": {
        "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": [
              "before",
              "after",
              "counts",
              "changes",
              "truncated",
              "unifiedDiff"
            ],
            "properties": {
              "before": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "origin",
                  "title",
                  "metaDescription",
                  "blockCount",
                  "headings",
                  "linkCount",
                  "prices",
                  "dates"
                ],
                "properties": {
                  "origin": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "kind",
                      "truncated"
                    ],
                    "properties": {
                      "kind": {
                        "type": "string",
                        "enum": [
                          "url",
                          "pasted"
                        ]
                      },
                      "requestedUrl": {
                        "type": "string"
                      },
                      "finalUrl": {
                        "type": "string"
                      },
                      "status": {
                        "type": "integer"
                      },
                      "contentType": {
                        "type": "string"
                      },
                      "fetchedAt": {
                        "type": "string"
                      },
                      "truncated": {
                        "type": "boolean"
                      }
                    }
                  },
                  "title": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "metaDescription": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "blockCount": {
                    "type": "integer"
                  },
                  "headings": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "maxItems": 50
                  },
                  "linkCount": {
                    "type": "integer"
                  },
                  "prices": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "maxItems": 50
                  },
                  "dates": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "maxItems": 50
                  }
                }
              },
              "after": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "origin",
                  "title",
                  "metaDescription",
                  "blockCount",
                  "headings",
                  "linkCount",
                  "prices",
                  "dates"
                ],
                "properties": {
                  "origin": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "kind",
                      "truncated"
                    ],
                    "properties": {
                      "kind": {
                        "type": "string",
                        "enum": [
                          "url",
                          "pasted"
                        ]
                      },
                      "requestedUrl": {
                        "type": "string"
                      },
                      "finalUrl": {
                        "type": "string"
                      },
                      "status": {
                        "type": "integer"
                      },
                      "contentType": {
                        "type": "string"
                      },
                      "fetchedAt": {
                        "type": "string"
                      },
                      "truncated": {
                        "type": "boolean"
                      }
                    }
                  },
                  "title": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "metaDescription": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "blockCount": {
                    "type": "integer"
                  },
                  "headings": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "maxItems": 50
                  },
                  "linkCount": {
                    "type": "integer"
                  },
                  "prices": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "maxItems": 50
                  },
                  "dates": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "maxItems": 50
                  }
                }
              },
              "counts": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "meaningful",
                  "trivial",
                  "high",
                  "medium",
                  "low",
                  "blocksBefore",
                  "blocksAfter",
                  "unchangedBlocks"
                ],
                "properties": {
                  "meaningful": {
                    "type": "integer"
                  },
                  "trivial": {
                    "type": "integer"
                  },
                  "high": {
                    "type": "integer"
                  },
                  "medium": {
                    "type": "integer"
                  },
                  "low": {
                    "type": "integer"
                  },
                  "blocksBefore": {
                    "type": "integer"
                  },
                  "blocksAfter": {
                    "type": "integer"
                  },
                  "unchangedBlocks": {
                    "type": "integer"
                  }
                }
              },
              "changes": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "rank",
                    "kind",
                    "category",
                    "categories",
                    "significance",
                    "level",
                    "element",
                    "before",
                    "after",
                    "wordDiff",
                    "evidence"
                  ],
                  "properties": {
                    "rank": {
                      "type": "integer",
                      "minimum": 1
                    },
                    "kind": {
                      "type": "string",
                      "enum": [
                        "modified",
                        "added",
                        "removed",
                        "title",
                        "meta-description",
                        "link"
                      ]
                    },
                    "category": {
                      "type": "string",
                      "enum": [
                        "price",
                        "legal-terms",
                        "contact",
                        "link-target",
                        "title",
                        "date",
                        "heading",
                        "number",
                        "meta-description",
                        "link-removed",
                        "link-added",
                        "text",
                        "trivial"
                      ]
                    },
                    "categories": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "enum": [
                          "price",
                          "legal-terms",
                          "contact",
                          "link-target",
                          "title",
                          "date",
                          "heading",
                          "number",
                          "meta-description",
                          "link-removed",
                          "link-added",
                          "text",
                          "trivial"
                        ]
                      }
                    },
                    "significance": {
                      "type": "integer",
                      "minimum": 0,
                      "maximum": 100
                    },
                    "level": {
                      "type": "string",
                      "enum": [
                        "high",
                        "medium",
                        "low",
                        "trivial"
                      ]
                    },
                    "element": {
                      "type": "string"
                    },
                    "before": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "after": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "wordDiff": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Inline word diff: [-removed-] {+added+}."
                    },
                    "evidence": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "truncated": {
                "type": "boolean"
              },
              "unifiedDiff": {
                "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"
              }
            }
          }
        }
      }
    }
  }
}