{
  "openapi": "3.1.1",
  "info": {
    "title": "AI Website Readiness Explorer API",
    "version": "1.0.0",
    "summary": "Can ChatGPT, Claude, Perplexity and AI agents read your website? Explainable score.",
    "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://aiwebsitereadinessexplorer.usefulweb.site"
    }
  ],
  "paths": {
    "/api/v1/calculate": {
      "post": {
        "operationId": "calculate",
        "summary": "Can ChatGPT, Claude, Perplexity and AI agents read your website? Explainable score.",
        "description": "Checks a page the way AI crawlers and agents see it: robots.txt rules for 16 AI and search bots (training vs. search vs. user-triggered, RFC 9309 matching, Content-Signal), meta robots, whether the content exists without JavaScript, semantic structure, JSON-LD types, llms.txt, sitemap, OpenAPI/API catalog and machine-readable alternates. Every check is listed with its points, so the score is fully explainable.\n\nMethodology:\n- robots.txt is evaluated per RFC 9309 for the page path: the group naming the bot exactly is used, otherwise the * group; the longest matching rule wins (Allow on ties). Content-Signal lines are reported.\n- Access score: search and user-request bots allowed earns the access points; blocking training-only bots (GPTBot, CCBot, Google-Extended, …) is a legitimate choice and is NOT penalised.\n- Content: visible text without JavaScript (scripts/styles removed); ≥ 500 characters = server-rendered.\n- Score = earned points / possible points × 100 over all checks (each check lists its points). Grade: A ≥ 90, B ≥ 75, C ≥ 60, D ≥ 40, else F.\n- Online mode fetches the page, /robots.txt, /llms.txt, /sitemap.xml, /openapi.json and /.well-known/api-catalog (RFC 9727) once each.",
        "tags": [
          "ai-infra"
        ],
        "x-mcp-tool": "ai_website_readiness_explorer",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiWebsiteReadinessExplorerInput"
              },
              "examples": {
                "example1": {
                  "summary": "Blog that blocks AI training but allows search (offline)",
                  "value": {
                    "html": "<!doctype html><html lang=\"en\"><head><title>Bread baking basics</title><meta name=\"description\" content=\"Step-by-step sourdough guide.\"><link rel=\"canonical\" href=\"https://bakery.example/bread\"><meta property=\"og:title\" content=\"Bread\"><meta property=\"og:type\" content=\"article\"><meta property=\"og:url\" content=\"https://bakery.example/bread\"><script type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"Article\",\"headline\":\"Bread baking basics\"}</script></head><body><header><nav><a href=\"/\">Home</a></nav></header><main><article><h1>Bread baking basics</h1><p>Sourdough needs flour, water, salt and a lively starter. Mix, rest, fold and bake in a hot oven. Sourdough needs flour, water, salt and a lively starter. Mix, rest, fold and bake in a hot oven. Sourdough needs flour, water, salt and a lively starter. Mix, rest, fold and bake in a hot oven. Sourdough needs flour, water, salt and a lively starter. Mix, rest, fold and bake in a hot oven. Sourdough needs flour, water, salt and a lively starter. Mix, rest, fold and bake in a hot oven. Sourdough needs flour, water, salt and a lively starter. Mix, rest, fold and bake in a hot oven. Sourdough needs flour, water, salt and a lively starter. Mix, rest, fold and bake in a hot oven. Sourdough needs flour, water, salt and a lively starter. Mix, rest, fold and bake in a hot oven. </p><img src=\"loaf.jpg\" alt=\"A baked loaf\"></article></main></body></html>",
                    "robotsTxt": "User-agent: GPTBot\nDisallow: /\n\nUser-agent: CCBot\nDisallow: /\n\nUser-agent: Google-Extended\nDisallow: /\n\nUser-agent: *\nAllow: /\nContent-Signal: search=yes, ai-train=no\n\nSitemap: https://bakery.example/sitemap.xml",
                    "llmsTxt": "# Bakery\n\n> Bread guides.\n\n- [Bread basics](https://bakery.example/bread)"
                  }
                },
                "example2": {
                  "summary": "JavaScript-only app shell (offline)",
                  "value": {
                    "html": "<!doctype html><html><head><title>App</title></head><body><div id=\"root\"></div><script src=\"/bundle.js\"></script></body></html>",
                    "robotsTxt": "User-agent: *\nDisallow: /admin"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiWebsiteReadinessExplorerResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tool": {
      "get": {
        "operationId": "getToolDefinition",
        "summary": "Inputs, output schema and examples for this tool",
        "responses": {
          "200": {
            "description": "Tool definition.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details. 422 responses include per-field `errors`.",
        "required": [
          "type",
          "title",
          "status",
          "detail"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "message"
              ],
              "properties": {
                "field": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "AiWebsiteReadinessExplorerInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "url": {
            "title": "Page URL",
            "type": "string",
            "format": "uri"
          },
          "html": {
            "title": "Or paste the page HTML (offline)",
            "type": "string",
            "maxLength": 3000000
          },
          "robotsTxt": {
            "title": "robots.txt content (offline mode)",
            "type": "string",
            "maxLength": 500000
          },
          "llmsTxt": {
            "title": "llms.txt content (offline mode, optional)",
            "type": "string",
            "maxLength": 500000
          }
        },
        "required": []
      },
      "AiWebsiteReadinessExplorerResult": {
        "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": [
              "url",
              "score",
              "grade",
              "title",
              "bots",
              "jsonLdTypes",
              "checks",
              "topFixes"
            ],
            "properties": {
              "url": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "score": {
                "type": "integer",
                "minimum": 0,
                "maximum": 100
              },
              "grade": {
                "type": "string",
                "enum": [
                  "A",
                  "B",
                  "C",
                  "D",
                  "F"
                ]
              },
              "title": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "bots": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "agent",
                    "operator",
                    "purpose",
                    "allowed",
                    "matchedGroup",
                    "rule"
                  ],
                  "properties": {
                    "agent": {
                      "type": "string"
                    },
                    "operator": {
                      "type": "string"
                    },
                    "purpose": {
                      "type": "string",
                      "enum": [
                        "training",
                        "search",
                        "user-request"
                      ]
                    },
                    "allowed": {
                      "type": "boolean"
                    },
                    "matchedGroup": {
                      "type": "string"
                    },
                    "rule": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              },
              "jsonLdTypes": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "checks": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "id",
                    "area",
                    "status",
                    "points",
                    "max",
                    "detail"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "area": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "pass",
                        "warn",
                        "fail",
                        "info"
                      ]
                    },
                    "points": {
                      "type": "integer"
                    },
                    "max": {
                      "type": "integer"
                    },
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              },
              "topFixes": {
                "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"
              }
            }
          }
        }
      }
    }
  }
}