{
  "openapi": "3.0.3",
  "info": {
    "title": "Botcard",
    "version": "2026-10-18.9",
    "description": "Registry of AI crawler robots.txt tokens, plus a paste-in robots.txt check. Facts on each card paraphrase the vendor page linked there. The check applies RFC 9309 to the file the caller sends. The same check is available as tools/call with name check_robots at POST /mcp. Not legal advice. This API does not fetch third-party sites."
  },
  "servers": [
    {
      "url": "https://whosthatbot.com"
    }
  ],
  "paths": {
    "/v1/robots-check": {
      "post": {
        "operationId": "checkRobots",
        "summary": "Match a pasted robots.txt against every token. Does not fetch any host.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RobotsCheckRequest"
              },
              "example": {
                "robots_txt": "User-agent: GPTBot\nDisallow: /\n\nUser-agent: *\nAllow: /\n",
                "path": "/docs"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "One RFC 9309 result per requested card. fetched_target is always false.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RobotsCheckResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad JSON, a URL instead of a path, a url field, or an unknown card id."
          },
          "405": {
            "description": "Use POST."
          },
          "413": {
            "description": "Body larger than 500 KiB."
          }
        }
      }
    },
    "/mcp": {
      "post": {
        "operationId": "mcp",
        "summary": "tools/call with name check_robots. POST JSON-RPC. Does not fetch any host.",
        "description": "tools/call with name check_robots checks a pasted robots.txt and a path on this stateless MCP endpoint, and ping, tools/list, and initialize are also supported. Other tools are list_crawlers and get_crawler. A URL, or a url, host, target, website, robots_url, or fetch argument, is a tool error. GET does not open an SSE stream and returns 405. Notifications return 202.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "jsonrpc": "2.0",
                "id": 1,
                "method": "tools/call",
                "params": {
                  "name": "check_robots",
                  "arguments": {
                    "robots_txt": "User-agent: GPTBot\nDisallow: /\n\nUser-agent: *\nAllow: /\n",
                    "path": "/docs",
                    "ids": [
                      "gptbot"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "One JSON-RPC response. Tool failures use result.isError, not an HTTP error."
          },
          "202": {
            "description": "Accepted a notification, including notifications/initialized."
          },
          "400": {
            "description": "Parse error, invalid request, or an unsupported MCP-Protocol-Version header."
          },
          "405": {
            "description": "POST JSON-RPC tools/call with name check_robots. This server does not open an SSE stream. GET /mcp/server-card returns the discovery card."
          },
          "406": {
            "description": "Accept allows neither application/json nor text/event-stream."
          },
          "413": {
            "description": "Body larger than 500 KiB."
          },
          "415": {
            "description": "Content-Type is not JSON."
          }
        }
      }
    },
    "/mcp/server-card": {
      "get": {
        "operationId": "mcpServerCard",
        "summary": "MCP server card for the streamable HTTP endpoint.",
        "responses": {
          "200": {
            "description": "Server card, including the three read-only tools."
          },
          "304": {
            "description": "Not modified."
          }
        }
      }
    },
    "/v1/crawlers": {
      "get": {
        "operationId": "listCrawlers",
        "summary": "List every crawler card in the current dataset.",
        "responses": {
          "200": {
            "description": "Registry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Registry"
                }
              }
            }
          }
        }
      }
    },
    "/v1/crawlers/{id}": {
      "get": {
        "operationId": "getCrawler",
        "summary": "One crawler card by id.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "examples": {
              "googleExtended": {
                "value": "google-extended"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Card",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CardResponse"
                }
              }
            }
          },
          "404": {
            "description": "Unknown id. The body is Caddy's plain 404, not a JSON error."
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Registry": {
        "type": "object",
        "required": [
          "dataset",
          "crawlers",
          "disclaimer"
        ],
        "properties": {
          "dataset": {
            "type": "string"
          },
          "disclaimer": {
            "type": "string"
          },
          "count": {
            "type": "integer"
          },
          "crawlers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Card"
            }
          }
        }
      },
      "CardResponse": {
        "type": "object",
        "required": [
          "dataset",
          "card",
          "disclaimer"
        ],
        "properties": {
          "dataset": {
            "type": "string"
          },
          "disclaimer": {
            "type": "string"
          },
          "card": {
            "$ref": "#/components/schemas/Card"
          }
        }
      },
      "RobotsCheckRequest": {
        "type": "object",
        "required": [
          "robots_txt"
        ],
        "properties": {
          "robots_txt": {
            "type": "string",
            "description": "The robots.txt file contents. Not a URL."
          },
          "path": {
            "type": "string",
            "description": "Path to test, starting with /. Defaults to /.",
            "default": "/"
          },
          "ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Card ids to check. Omit to check every card."
          }
        }
      },
      "RobotsCheckResponse": {
        "type": "object",
        "required": [
          "dataset",
          "path",
          "fetched_target",
          "results",
          "disclaimer"
        ],
        "properties": {
          "dataset": {
            "type": "string"
          },
          "path": {
            "type": "string"
          },
          "fetched_target": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "spec": {
            "type": "string"
          },
          "spec_url": {
            "type": "string"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RobotsCheckResult"
            }
          },
          "disclaimer": {
            "type": "string"
          }
        }
      },
      "RobotsCheckResult": {
        "type": "object",
        "required": [
          "id",
          "robots_token",
          "decision",
          "vendor_stance"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "robots_token": {
            "type": "string"
          },
          "kind": {
            "type": "string"
          },
          "vendor_stance": {
            "type": "string"
          },
          "stance_note": {
            "type": "string"
          },
          "decision": {
            "type": "string",
            "enum": [
              "allow",
              "disallow"
            ]
          },
          "matched_group": {
            "type": "string",
            "nullable": true
          },
          "rule": {
            "type": "string",
            "nullable": true
          },
          "line": {
            "type": "integer",
            "nullable": true
          },
          "reason": {
            "type": "string"
          },
          "follows_when_unmentioned": {
            "type": "string"
          },
          "follows_when_unmentioned_note": {
            "type": "string"
          },
          "opt_out_ledger": {
            "type": "object"
          }
        }
      },
      "Card": {
        "type": "object",
        "required": [
          "id",
          "robots_token",
          "operator",
          "kind",
          "robots_txt",
          "summary",
          "source"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "robots_token": {
            "type": "string"
          },
          "operator": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "training",
              "search",
              "user_fetch",
              "ads_check",
              "control_token",
              "owner_requested",
              "open_crawl"
            ]
          },
          "robots_txt": {
            "type": "string",
            "enum": [
              "disallow_is_opt_out",
              "obeys",
              "may_not_apply",
              "generally_ignores",
              "recommends_allow",
              "not_stated",
              "control_token",
              "respects_no_crawl_delay",
              "obeys_unless_agreed",
              "governs_sites",
              "published_tag",
              "ignores_star",
              "indexes_unless_named",
              "disallow_opts_out_ignores_star"
            ]
          },
          "follows_when_unmentioned": {
            "type": "string"
          },
          "opt_out_ledger": {
            "type": "object"
          },
          "http_user_agent_example": {
            "type": "string",
            "nullable": true
          },
          "summary": {
            "type": "string"
          },
          "source": {
            "type": "object"
          }
        }
      }
    }
  }
}
