{
 "openapi": "3.1.0",
 "info": {
  "title": "Agent Ready HTML API",
  "version": "1.0.0",
  "summary": "Read-only API, MCP server and NLWeb endpoint over the datasets of agentreadyhtml.com.",
  "description": "what agents read when they fetch a page without JavaScript: the llms.txt Index (every plain-text llms.txt found in a crawl of the Tranco top 10,000, parsed and graded against the llmstxt.org structure), the crawl measures of the read layer by category and platform, and 23 platforms scored on nine read-layer keys from dated documentation.\n\nAccess: every endpoint is public and read-only; there is no API key, no OAuth and no scope, because nothing here can be written or belongs to a user. Rate limit: 120 requests a minute per client address, announced in RateLimit and RateLimit-Policy headers; a 429 carries Retry-After. Errors are JSON ({\"error\":{\"code\",\"message\",\"hint\",\"status\",\"docs\"}}), never HTML. Versioning: the path prefix /api/v1 is the contract; a breaking change ships under /api/v2 with the old prefix kept for at least 180 days and announced on https://agentreadyhtml.netlify.app/developers/ and in this document's info.version. Additive changes (new fields, new tools) do not change the prefix. Idempotency: every operation is a read, so retries are safe and no idempotency key exists. Long-running operations: none; every call answers in one response. Data edition: 2026-11-04; the same rows are downloadable whole from /data/.",
  "license": {
   "name": "CC BY 4.0",
   "url": "https://creativecommons.org/licenses/by/4.0/"
  },
  "x-authentication": "none",
  "x-rate-limit": {
   "requests": 120,
   "window_seconds": 60,
   "headers": [
    "RateLimit",
    "RateLimit-Policy",
    "Retry-After"
   ]
  },
  "x-versioning-policy": {
   "current": "v1",
   "breaking_changes": "new path prefix, old prefix kept for 180 days",
   "announcements": "https://agentreadyhtml.netlify.app/developers/"
  },
  "x-idempotency": "all operations are reads; retries are safe",
  "x-dataset-edition": "2026-11-04"
 },
 "externalDocs": {
  "description": "API and MCP server documentation",
  "url": "https://agentreadyhtml.netlify.app/developers/"
 },
 "servers": [
  {
   "url": "https://agentreadyhtml.netlify.app",
   "description": "The host that serves this surface today; page and dataset URLs in the answers stay on https://agentreadyhtml.com"
  }
 ],
 "tags": [
  {
   "name": "tools",
   "description": "One GET endpoint per MCP tool."
  },
  {
   "name": "nlweb",
   "description": "NLWeb 0.55 ask endpoint."
  },
  {
   "name": "downloads",
   "description": "Whole-dataset files."
  },
  {
   "name": "index"
  }
 ],
 "security": [],
 "paths": {
  "/api": {
   "get": {
    "operationId": "getApiIndex",
    "tags": [
     "index"
    ],
    "summary": "API index",
    "description": "Links to every endpoint, dataset download, the OpenAPI document, the MCP server and the NLWeb endpoint, plus the rate limit and the versioning policy.",
    "responses": {
     "200": {
      "description": "The index.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ApiIndex"
        }
       }
      }
     },
     "429": {
      "description": "More than the published rate limit; Retry-After says when to try again.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/v1/search_llms_index": {
   "get": {
    "operationId": "search_llms_index",
    "tags": [
     "tools"
    ],
    "summary": "Search the llms.txt Index",
    "description": "Lists llms.txt files from the index (domain, Tranco rank, category, platform, grade A to F, size, H1, link counts, whether the home page links it, page URL). Filter by words in the domain or H1, grade, category, platform, minimum links or linked_from_home. Call it to find which sites serve an llms.txt and how it grades; use get_llms_entry for one domain in full. Paginated: pass limit (1 to 100) and the next_cursor of the previous page as cursor. The same tool is callable over MCP at /mcp.",
    "parameters": [
     {
      "name": "q",
      "in": "query",
      "required": false,
      "description": "Words to look for in the domain or the H1 of the file; every word must appear, for example \"stripe\" or \"developer docs\".",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "grade",
      "in": "query",
      "required": false,
      "description": "Structure grade: A passes all six checks of the llmstxt.org structure, F two or fewer.",
      "schema": {
       "type": "string",
       "enum": [
        "A",
        "B",
        "C",
        "D",
        "F"
       ]
      },
      "example": "A"
     },
     {
      "name": "category",
      "in": "query",
      "required": false,
      "description": "Category of the domain as the index lists it, for example \"Developer Tools\". grade_distribution with group_by category lists them all.",
      "schema": {
       "type": "string"
      },
      "example": "Developer Tools"
     },
     {
      "name": "platform",
      "in": "query",
      "required": false,
      "description": "Platform the home page declares in its generator tag, for example WordPress, Framer or Astro.",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "min_links",
      "in": "query",
      "required": false,
      "description": "Keep files that list at least this many links.",
      "schema": {
       "type": "integer",
       "minimum": 0
      }
     },
     {
      "name": "linked_from_home",
      "in": "query",
      "required": false,
      "description": "true keeps files the home page links; false keeps files it does not link. Files whose home page was not read are left out of both.",
      "schema": {
       "type": "boolean"
      }
     },
     {
      "name": "limit",
      "in": "query",
      "required": false,
      "description": "Page size, 1 to 100 (default 20).",
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 100,
       "default": 20
      }
     },
     {
      "name": "cursor",
      "in": "query",
      "required": false,
      "description": "Opaque cursor from next_cursor of the previous page.",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "The result, the same object the MCP tool returns as structuredContent.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "items": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "domain": {
              "type": "string"
             },
             "rank": {
              "type": [
               "integer",
               "null"
              ],
              "description": "Tranco rank, null when the domain is not in the list."
             },
             "category": {
              "type": [
               "string",
               "null"
              ]
             },
             "platform": {
              "type": [
               "string",
               "null"
              ],
              "description": "Generator the home page declares."
             },
             "grade": {
              "type": "string",
              "enum": [
               "A",
               "B",
               "C",
               "D",
               "F"
              ]
             },
             "checks_passed": {
              "type": "integer",
              "description": "Structure checks passed, of six."
             },
             "bytes": {
              "type": "integer"
             },
             "links": {
              "type": "integer"
             },
             "sections": {
              "type": "integer"
             },
             "same_site_links": {
              "type": "integer"
             },
             "h1": {
              "type": "string"
             },
             "linked_from_home": {
              "type": [
               "boolean",
               "null"
              ],
              "description": "null when the home page was not read."
             },
             "llms_full": {
              "type": "boolean",
              "description": "Whether an llms-full.txt is served at the same root."
             },
             "copy_cut": {
              "type": "boolean",
              "description": "Whether the crawl kept only the first 60 KB of the file; size and link counts still describe the whole file."
             },
             "has_entry_page": {
              "type": "boolean"
             },
             "url": {
              "type": "string",
              "format": "uri",
              "description": "The entry page when there is one, otherwise the edition page."
             },
             "dataset_url": {
              "type": "string",
              "format": "uri"
             }
            }
           }
          },
          "total": {
           "type": "integer"
          },
          "limit": {
           "type": "integer"
          },
          "next_cursor": {
           "type": [
            "string",
            "null"
           ]
          },
          "edition": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "A parameter is missing or has the wrong type; error.hint lists the parameters.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "No such endpoint or record.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "More than the published rate limit; Retry-After says when to try again.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "500": {
      "description": "Internal error; the datasets could not be read.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/v1/get_llms_entry": {
   "get": {
    "operationId": "get_llms_entry",
    "tags": [
     "tools"
    ],
    "summary": "One domain in the llms.txt Index",
    "description": "Returns one domain from the index: its row (grade, checks passed, size, H1, links, whether the home page links the file), what the grade means, and, when the domain has an entry page, the parsed summary, H2 sections, link hosts and the six structure checks with their detail. Call it after search_llms_index, or with any domain you are checking. The same tool is callable over MCP at /mcp.",
    "parameters": [
     {
      "name": "domain",
      "in": "query",
      "required": true,
      "description": "A domain such as stripe.com, or a URL on it; a leading www. is ignored if the domain is not listed with it.",
      "schema": {
       "type": "string"
      },
      "example": "supabase.com"
     }
    ],
    "responses": {
     "200": {
      "description": "The result, the same object the MCP tool returns as structuredContent.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "domain": {
           "type": "string"
          },
          "rank": {
           "type": [
            "integer",
            "null"
           ],
           "description": "Tranco rank, null when the domain is not in the list."
          },
          "category": {
           "type": [
            "string",
            "null"
           ]
          },
          "platform": {
           "type": [
            "string",
            "null"
           ],
           "description": "Generator the home page declares."
          },
          "grade": {
           "type": "string",
           "enum": [
            "A",
            "B",
            "C",
            "D",
            "F"
           ]
          },
          "checks_passed": {
           "type": "integer",
           "description": "Structure checks passed, of six."
          },
          "bytes": {
           "type": "integer"
          },
          "links": {
           "type": "integer"
          },
          "sections": {
           "type": "integer"
          },
          "same_site_links": {
           "type": "integer"
          },
          "h1": {
           "type": "string"
          },
          "linked_from_home": {
           "type": [
            "boolean",
            "null"
           ],
           "description": "null when the home page was not read."
          },
          "llms_full": {
           "type": "boolean",
           "description": "Whether an llms-full.txt is served at the same root."
          },
          "copy_cut": {
           "type": "boolean",
           "description": "Whether the crawl kept only the first 60 KB of the file; size and link counts still describe the whole file."
          },
          "has_entry_page": {
           "type": "boolean"
          },
          "url": {
           "type": "string",
           "format": "uri",
           "description": "The entry page when there is one, otherwise the edition page."
          },
          "dataset_url": {
           "type": "string",
           "format": "uri"
          },
          "grade_meaning": {
           "type": "string"
          },
          "grade_scale": {
           "type": "object",
           "additionalProperties": {
            "type": "string"
           }
          },
          "checks_defined": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "id": {
              "type": "string"
             },
             "label": {
              "type": "string"
             }
            }
           }
          },
          "entry": {
           "type": [
            "object",
            "null"
           ],
           "description": "The parsed entry; null when the domain has no entry page."
          },
          "other_entries": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "path": {
              "type": "string"
             },
             "grade": {
              "type": "string"
             },
             "page": {
              "type": "string",
              "format": "uri"
             }
            }
           }
          },
          "cite": {
           "type": "string"
          },
          "edition": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "A parameter is missing or has the wrong type; error.hint lists the parameters.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "No such endpoint or record.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "More than the published rate limit; Retry-After says when to try again.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "500": {
      "description": "Internal error; the datasets could not be read.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/v1/grade_distribution": {
   "get": {
    "operationId": "grade_distribution",
    "tags": [
     "tools"
    ],
    "summary": "Grades across the llms.txt Index",
    "description": "Returns how many llms.txt files earned each grade (A to F), overall and grouped by category or by platform, with the share that earned an A. Call it for adoption and quality questions across the index, or to list the category and platform names that search_llms_index accepts. The same tool is callable over MCP at /mcp.",
    "parameters": [
     {
      "name": "group_by",
      "in": "query",
      "required": false,
      "description": "category (default), platform, or none for the overall counts only.",
      "schema": {
       "type": "string",
       "enum": [
        "category",
        "platform",
        "none"
       ],
       "default": "category"
      },
      "example": "category"
     },
     {
      "name": "min_files",
      "in": "query",
      "required": false,
      "description": "Leave out groups with fewer files than this; platform names read from generator tags are many and small, so 5 is a useful floor.",
      "schema": {
       "type": "integer",
       "minimum": 1,
       "default": 1
      },
      "example": 20
     }
    ],
    "responses": {
     "200": {
      "description": "The result, the same object the MCP tool returns as structuredContent.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "total_files": {
           "type": "integer"
          },
          "grades": {
           "type": "object",
           "additionalProperties": {
            "type": "integer"
           }
          },
          "group_by": {
           "type": "string"
          },
          "groups": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "key": {
              "type": "string"
             },
             "files": {
              "type": "integer"
             },
             "grades": {
              "type": "object",
              "additionalProperties": {
               "type": "integer"
              }
             },
             "share_a_percent": {
              "type": "number"
             }
            }
           }
          },
          "grade_meaning": {
           "type": "object",
           "additionalProperties": {
            "type": "string"
           }
          },
          "url": {
           "type": "string",
           "format": "uri"
          },
          "dataset_url": {
           "type": "string",
           "format": "uri"
          },
          "edition": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "A parameter is missing or has the wrong type; error.hint lists the parameters.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "No such endpoint or record.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "More than the published rate limit; Retry-After says when to try again.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "500": {
      "description": "Internal error; the datasets could not be read.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/v1/get_crawl_measure": {
   "get": {
    "operationId": "get_crawl_measure",
    "tags": [
     "tools"
    ],
    "summary": "Crawl measures of the read layer",
    "description": "Lists the crawl measures (count, denominator and percent) for home pages that answered 200: headline figures, by category and by platform, for example the share that serve llms.txt, answer Accept: text/markdown with markdown or return 200 for a made-up path. Filter by group_type, group and words of the measure. Call it for how common a practice is. Paginated: pass limit (1 to 100) and the next_cursor of the previous page as cursor. The same tool is callable over MCP at /mcp.",
    "parameters": [
     {
      "name": "group_type",
      "in": "query",
      "required": false,
      "description": "headline is the whole crawl; category and platform split it.",
      "schema": {
       "type": "string",
       "enum": [
        "headline",
        "category",
        "platform"
       ]
      },
      "example": "headline"
     },
     {
      "name": "group",
      "in": "query",
      "required": false,
      "description": "The group name, for example \"Developer Tools\" (a category) or \"WordPress\" (a platform); case-insensitive. Omit group_type to match the name in any type.",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "measure",
      "in": "query",
      "required": false,
      "description": "Words from the measure name; every word must appear, for example \"llms.txt\" or \"markdown\" or \"soft 404\".",
      "schema": {
       "type": "string"
      },
      "example": "llms.txt"
     },
     {
      "name": "limit",
      "in": "query",
      "required": false,
      "description": "Page size, 1 to 100 (default 20).",
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 100,
       "default": 20
      }
     },
     {
      "name": "cursor",
      "in": "query",
      "required": false,
      "description": "Opaque cursor from next_cursor of the previous page.",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "The result, the same object the MCP tool returns as structuredContent.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "items": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "group_type": {
              "type": "string"
             },
             "group": {
              "type": "string"
             },
             "measure": {
              "type": "string"
             },
             "n": {
              "type": "integer"
             },
             "of": {
              "type": "integer"
             },
             "percent": {
              "type": "number"
             }
            }
           }
          },
          "total": {
           "type": "integer"
          },
          "limit": {
           "type": "integer"
          },
          "next_cursor": {
           "type": [
            "string",
            "null"
           ]
          },
          "edition": {
           "type": "string"
          },
          "crawl": {
           "type": "object",
           "properties": {
            "rows_read": {
             "type": "integer"
            },
            "home_pages_answered_200": {
             "type": "integer"
            },
            "universe": {
             "type": "string"
            }
           }
          },
          "url": {
           "type": "string",
           "format": "uri"
          },
          "dataset_url": {
           "type": "string",
           "format": "uri"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "A parameter is missing or has the wrong type; error.hint lists the parameters.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "No such endpoint or record.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "More than the published rate limit; Retry-After says when to try again.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "500": {
      "description": "Internal error; the datasets could not be read.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/v1/list_platforms": {
   "get": {
    "operationId": "list_platforms",
    "tags": [
     "tools"
    ],
    "summary": "Platforms scored on the read layer",
    "description": "Lists the 23 platforms (docs platforms, site builders, frameworks, edge products) with their total on the nine-key rubric and each key score (2 on by default, 1 with setup, 0 not offered, n/a). With id, returns one platform with the evidence, source URL and read date for every key; with key, adds that key's evidence to each platform. Call it to compare platforms or to cite one score. Paginated: pass limit (1 to 100) and the next_cursor of the previous page as cursor. The same tool is callable over MCP at /mcp.",
    "parameters": [
     {
      "name": "id",
      "in": "query",
      "required": false,
      "description": "Platform id for one platform in full, for example astro, nextjs-app-router or mintlify.",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "type",
      "in": "query",
      "required": false,
      "description": "Keep one kind of platform.",
      "schema": {
       "type": "string",
       "enum": [
        "docs-platform",
        "site-builder",
        "framework",
        "edge-product"
       ]
      },
      "example": "framework"
     },
     {
      "name": "key",
      "in": "query",
      "required": false,
      "description": "A rubric key to rank by and to show the evidence for, for example markdown_negotiation.",
      "schema": {
       "type": "string",
       "enum": [
        "initial_html_by_default",
        "real_status_codes",
        "llms_txt_generation",
        "llms_txt_linking",
        "markdown_negotiation",
        "jsonld_output",
        "openapi_exposure",
        "fenced_code",
        "manual_work_needed"
       ]
      }
     },
     {
      "name": "limit",
      "in": "query",
      "required": false,
      "description": "Page size, 1 to 100 (default 20).",
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 100,
       "default": 20
      }
     },
     {
      "name": "cursor",
      "in": "query",
      "required": false,
      "description": "Opaque cursor from next_cursor of the previous page.",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "The result, the same object the MCP tool returns as structuredContent.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "items": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "id": {
              "type": "string"
             },
             "name": {
              "type": "string"
             },
             "type": {
              "type": "string"
             },
             "operator": {
              "type": "string"
             },
             "one_line": {
              "type": "string"
             },
             "total": {
              "type": "object",
              "properties": {
               "score": {
                "type": "integer"
               },
               "of": {
                "type": "integer"
               }
              }
             },
             "test_built": {
              "type": "boolean"
             },
             "scores": {
              "type": "object",
              "additionalProperties": true
             },
             "url": {
              "type": "string",
              "format": "uri"
             }
            }
           }
          },
          "total": {
           "type": "integer"
          },
          "limit": {
           "type": "integer"
          },
          "next_cursor": {
           "type": [
            "string",
            "null"
           ]
          },
          "edition": {
           "type": "string"
          },
          "rubric": {
           "type": "object",
           "additionalProperties": true
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "A parameter is missing or has the wrong type; error.hint lists the parameters.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "No such endpoint or record.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "More than the published rate limit; Retry-After says when to try again.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "500": {
      "description": "Internal error; the datasets could not be read.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/ask": {
   "get": {
    "operationId": "askGet",
    "tags": [
     "nlweb"
    ],
    "summary": "Ask (NLWeb, GET)",
    "description": "NLWeb 0.55. Searches the site's records and pages for the question and returns schema.org objects, each with a source URL. Add streaming=true (or Accept: text/event-stream) for server-sent events start, result, error and complete.",
    "parameters": [
     {
      "name": "query",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string",
       "maxLength": 500
      },
      "description": "The question or search text."
     },
     {
      "name": "site",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "Ignored unless it names this site; present for NLWeb compatibility."
     },
     {
      "name": "mode",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "enum": [
        "list",
        "summarize"
       ]
      },
      "description": "list (default) or summarize, which adds a SearchSummary item."
     },
     {
      "name": "streaming",
      "in": "query",
      "required": false,
      "schema": {
       "type": "boolean"
      },
      "description": "true for text/event-stream."
     },
     {
      "name": "response_format",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "enum": [
        "conversational_search",
        "chatgpt_app"
       ]
      }
     }
    ],
    "responses": {
     "200": {
      "description": "An NLWeb answer, or a failure with code NO_RESULTS.",
      "content": {
       "application/json": {
        "schema": {
         "oneOf": [
          {
           "$ref": "#/components/schemas/AskAnswer"
          },
          {
           "$ref": "#/components/schemas/AskFailure"
          }
         ]
        }
       },
       "text/event-stream": {
        "schema": {
         "type": "string",
         "description": "Events start, result (one per item), error, complete; each data line is JSON."
        }
       }
      }
     },
     "400": {
      "description": "INVALID_QUERY, UNSUPPORTED_MODE or UNSUPPORTED_FORMAT.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/AskFailure"
        }
       }
      }
     },
     "429": {
      "description": "More than the published rate limit; Retry-After says when to try again.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   },
   "post": {
    "operationId": "askPost",
    "tags": [
     "nlweb"
    ],
    "summary": "Ask (NLWeb, POST)",
    "description": "NLWeb 0.55 request object: query.text (required), query.site, prefer.streaming, prefer.mode, prefer.response_format, meta.version. The context object is accepted and ignored: answers come from the site's data, not from a model.",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/AskRequest"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "An NLWeb answer, or a failure with code NO_RESULTS.",
      "content": {
       "application/json": {
        "schema": {
         "oneOf": [
          {
           "$ref": "#/components/schemas/AskAnswer"
          },
          {
           "$ref": "#/components/schemas/AskFailure"
          }
         ]
        }
       },
       "text/event-stream": {
        "schema": {
         "type": "string"
        }
       }
      }
     },
     "400": {
      "description": "INVALID_QUERY, UNSUPPORTED_MODE or UNSUPPORTED_FORMAT.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/AskFailure"
        }
       }
      }
     },
     "429": {
      "description": "More than the published rate limit; Retry-After says when to try again.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/data/llms-txt-index-2026-11-04.json": {
   "get": {
    "operationId": "download_llms_txt_index_2026_11_04_json",
    "tags": [
     "downloads"
    ],
    "summary": "llms.txt Index rows (json)",
    "description": "One row per plain-text llms.txt found in the crawl: domain, rank, category, platform, size, H1, sections, links, same-site links, whether the home page links it, whether llms-full.txt exists, grade and checks passed. Whole-file download; the tools above answer questions over the same rows.",
    "responses": {
     "200": {
      "description": "The file.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "additionalProperties": true
        }
       }
      }
     }
    }
   }
  },
  "/data/llms-txt-index-2026-11-04.csv": {
   "get": {
    "operationId": "download_llms_txt_index_2026_11_04_csv",
    "tags": [
     "downloads"
    ],
    "summary": "llms.txt Index rows (csv)",
    "description": "One row per plain-text llms.txt found in the crawl: domain, rank, category, platform, size, H1, sections, links, same-site links, whether the home page links it, whether llms-full.txt exists, grade and checks passed. Whole-file download; the tools above answer questions over the same rows.",
    "responses": {
     "200": {
      "description": "The file.",
      "content": {
       "text/csv": {
        "schema": {
         "type": "string"
        }
       }
      }
     }
    }
   }
  },
  "/data/llms-txt-entries-2026-11-04.json": {
   "get": {
    "operationId": "download_llms_txt_entries_2026_11_04_json",
    "tags": [
     "downloads"
    ],
    "summary": "llms.txt Index entries (json)",
    "description": "The parsed entries behind the entry pages: summary, H2 sections, link hosts and the six structure checks with their detail. Whole-file download; the tools above answer questions over the same rows.",
    "responses": {
     "200": {
      "description": "The file.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "additionalProperties": true
        }
       }
      }
     }
    }
   }
  },
  "/data/crawl-measures-2026-11-04.json": {
   "get": {
    "operationId": "download_crawl_measures_2026_11_04_json",
    "tags": [
     "downloads"
    ],
    "summary": "Crawl measures (json)",
    "description": "Read-layer measures of home pages that answered 200: headline, by category and by platform, each with the count, the denominator and the percent. Whole-file download; the tools above answer questions over the same rows.",
    "responses": {
     "200": {
      "description": "The file.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "additionalProperties": true
        }
       }
      }
     }
    }
   }
  },
  "/data/crawl-measures-2026-11-04.csv": {
   "get": {
    "operationId": "download_crawl_measures_2026_11_04_csv",
    "tags": [
     "downloads"
    ],
    "summary": "Crawl measures (csv)",
    "description": "Read-layer measures of home pages that answered 200: headline, by category and by platform, each with the count, the denominator and the percent. Whole-file download; the tools above answer questions over the same rows.",
    "responses": {
     "200": {
      "description": "The file.",
      "content": {
       "text/csv": {
        "schema": {
         "type": "string"
        }
       }
      }
     }
    }
   }
  },
  "/data/platform-scores-2026-11-04.json": {
   "get": {
    "operationId": "download_platform_scores_2026_11_04_json",
    "tags": [
     "downloads"
    ],
    "summary": "Platform scores (json)",
    "description": "The nine rubric keys and the score, evidence, source and read date of each of the 23 platforms. Whole-file download; the tools above answer questions over the same rows.",
    "responses": {
     "200": {
      "description": "The file.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "additionalProperties": true
        }
       }
      }
     }
    }
   }
  }
 },
 "components": {
  "securitySchemes": {},
  "schemas": {
   "Error": {
    "type": "object",
    "required": [
     "error"
    ],
    "properties": {
     "error": {
      "type": "object",
      "required": [
       "code",
       "message",
       "status"
      ],
      "properties": {
       "code": {
        "type": "string",
        "enum": [
         "invalid_params",
         "not_found",
         "method_not_allowed",
         "unsupported_media_type",
         "rate_limited",
         "internal"
        ]
       },
       "message": {
        "type": "string"
       },
       "hint": {
        "type": "string"
       },
       "status": {
        "type": "integer"
       },
       "docs": {
        "type": "string",
        "format": "uri"
       },
       "openapi": {
        "type": "string",
        "format": "uri"
       }
      }
     }
    }
   },
   "ApiIndex": {
    "type": "object",
    "properties": {
     "name": {
      "type": "string"
     },
     "version": {
      "type": "string"
     },
     "edition": {
      "type": "string"
     },
     "documentation": {
      "type": "string",
      "format": "uri"
     },
     "openapi": {
      "type": "string",
      "format": "uri"
     },
     "endpoints": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "path": {
         "type": "string"
        },
        "method": {
         "type": "string"
        },
        "summary": {
         "type": "string"
        }
       }
      }
     },
     "datasets": {
      "type": "array",
      "items": {
       "type": "object"
      }
     },
     "mcp": {
      "type": "object"
     },
     "ask": {
      "type": "object"
     },
     "rate_limit": {
      "type": "object"
     },
     "versioning": {
      "type": "object"
     }
    }
   },
   "AskRequest": {
    "type": "object",
    "required": [
     "query"
    ],
    "properties": {
     "query": {
      "type": "object",
      "required": [
       "text"
      ],
      "properties": {
       "text": {
        "type": "string",
        "maxLength": 500
       },
       "site": {
        "type": "string"
       }
      }
     },
     "context": {
      "type": "object",
      "additionalProperties": true
     },
     "prefer": {
      "type": "object",
      "properties": {
       "streaming": {
        "type": "boolean"
       },
       "mode": {
        "type": "string",
        "description": "list, summarize, or both comma-separated"
       },
       "response_format": {
        "type": "string",
        "enum": [
         "conversational_search",
         "chatgpt_app"
        ]
       }
      }
     },
     "meta": {
      "type": "object",
      "properties": {
       "version": {
        "type": "string"
       },
       "query_id": {
        "type": "string"
       }
      }
     }
    }
   },
   "AskMeta": {
    "type": "object",
    "required": [
     "response_type",
     "version"
    ],
    "properties": {
     "response_type": {
      "type": "string",
      "enum": [
       "answer",
       "failure"
      ]
     },
     "response_format": {
      "type": "string"
     },
     "version": {
      "type": "string"
     },
     "site": {
      "type": "string"
     },
     "edition": {
      "type": "string"
     },
     "query_id": {
      "type": "string"
     }
    }
   },
   "AskResult": {
    "type": "object",
    "required": [
     "@type",
     "name",
     "url"
    ],
    "properties": {
     "@type": {
      "type": "string"
     },
     "name": {
      "type": "string"
     },
     "url": {
      "type": "string",
      "format": "uri"
     },
     "description": {
      "type": "string"
     },
     "score": {
      "type": "number"
     },
     "grounding": {
      "type": "object",
      "properties": {
       "source": {
        "type": "string",
        "format": "uri"
       },
       "dataset": {
        "type": "string"
       },
       "edition": {
        "type": "string"
       },
       "publisher": {
        "type": "string"
       }
      }
     }
    },
    "additionalProperties": true
   },
   "AskAnswer": {
    "type": "object",
    "required": [
     "_meta"
    ],
    "properties": {
     "_meta": {
      "$ref": "#/components/schemas/AskMeta"
     },
     "results": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/AskResult"
      }
     },
     "content": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "type": {
         "type": "string"
        },
        "text": {
         "type": "string"
        }
       }
      }
     },
     "structuredData": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/AskResult"
      }
     }
    }
   },
   "AskFailure": {
    "type": "object",
    "required": [
     "_meta",
     "failure"
    ],
    "properties": {
     "_meta": {
      "$ref": "#/components/schemas/AskMeta"
     },
     "failure": {
      "type": "object",
      "required": [
       "code"
      ],
      "properties": {
       "code": {
        "type": "string",
        "enum": [
         "NO_RESULTS",
         "INVALID_QUERY",
         "UNSUPPORTED_FORMAT",
         "UNSUPPORTED_MODE",
         "RATE_LIMITED",
         "INTERNAL_ERROR"
        ]
       },
       "message": {
        "type": "string"
       }
      }
     }
    }
   }
  }
 }
}
