{
  "openapi": "3.1.0",
  "info": {
    "title": "OneBag Kit read-only API",
    "version": "1.0.0",
    "summary": "Free, read-only access to OneBag Kit's carry-on and one-bag packing guides.",
    "description": "OneBag Kit (onebagkit.com) publishes free carry-on and one-bag packing guides. This API is read-only: no key, no account, no writes. It exposes a JSON index of every public page, a simple keyword search, and the Markdown mirror of each page. Please cache responses and keep request rates modest. Content is general packing guidance, not airline policy. An MCP server with the same data is at https://onebagkit.com/mcp (see the developer page).",
    "contact": {
      "name": "OneBag Kit",
      "url": "https://onebagkit.com/developers/",
      "email": "hello@onebagkit.com"
    }
  },
  "externalDocs": {
    "description": "Developer page (API and MCP server)",
    "url": "https://onebagkit.com/developers/"
  },
  "servers": [{ "url": "https://onebagkit.com" }],
  "paths": {
    "/api/pages.json": {
      "get": {
        "operationId": "listPages",
        "summary": "Index of every public page",
        "description": "Static JSON generated at build time. Each page has url, title, description, dateModified, md_url (Markdown mirror) and FAQ question/answer pairs.",
        "responses": {
          "200": {
            "description": "Page index",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PagesIndex" } } }
          }
        }
      }
    },
    "/api/search": {
      "get": {
        "operationId": "searchAnswers",
        "summary": "Keyword search over the page index",
        "description": "Case-insensitive keyword search over page titles, URLs, descriptions and FAQ text. Returns the top 10 matches.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "Search words, e.g. \"liquids\" or \"packing cubes\". Max 200 characters.",
            "schema": { "type": "string", "minLength": 1, "maxLength": 200 },
            "example": "packing cubes"
          }
        ],
        "responses": {
          "200": {
            "description": "Search results (possibly empty)",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SearchResponse" } } }
          },
          "400": {
            "description": "Missing query",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          }
        }
      }
    },
    "/index.md": {
      "get": {
        "operationId": "getHomeMarkdown",
        "summary": "Markdown mirror of the homepage",
        "responses": {
          "200": { "description": "Markdown text", "content": { "text/markdown": { "schema": { "type": "string" } } } }
        }
      }
    },
    "/{slug}/index.md": {
      "get": {
        "operationId": "getPageMarkdown",
        "summary": "Markdown mirror of a page",
        "description": "Every HTML page at https://onebagkit.com/{slug}/ has a Markdown mirror at /{slug}/index.md. Valid slugs are listed in /api/pages.json (md_url).",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "Page slug, e.g. how-many-packing-cubes-for-40l",
            "schema": { "type": "string", "pattern": "^[a-z0-9-]+$" },
            "example": "how-many-packing-cubes-for-40l"
          }
        ],
        "responses": {
          "200": { "description": "Markdown text", "content": { "text/markdown": { "schema": { "type": "string" } } } },
          "404": { "description": "No page with that slug" }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "FaqPair": {
        "type": "object",
        "required": ["question", "answer"],
        "properties": {
          "question": { "type": "string" },
          "answer": { "type": "string" }
        }
      },
      "Page": {
        "type": "object",
        "required": ["url", "path", "title", "description", "md_url", "faq"],
        "properties": {
          "url": { "type": "string", "format": "uri" },
          "path": { "type": "string", "example": "/how-many-packing-cubes-for-40l/" },
          "title": { "type": "string" },
          "description": { "type": "string" },
          "dateModified": { "type": ["string", "null"], "format": "date" },
          "md_url": { "type": "string", "format": "uri" },
          "faq": { "type": "array", "items": { "$ref": "#/components/schemas/FaqPair" } }
        }
      },
      "PagesIndex": {
        "type": "object",
        "required": ["site", "generated", "count", "pages"],
        "properties": {
          "name": { "type": "string" },
          "description": { "type": "string" },
          "site": { "type": "string", "format": "uri" },
          "docs": { "type": "string", "format": "uri" },
          "openapi": { "type": "string", "format": "uri" },
          "generated": { "type": "string", "format": "date-time" },
          "count": { "type": "integer" },
          "pages": { "type": "array", "items": { "$ref": "#/components/schemas/Page" } }
        }
      },
      "SearchHit": {
        "type": "object",
        "required": ["title", "url", "description", "md_url", "score"],
        "properties": {
          "title": { "type": "string" },
          "url": { "type": "string", "format": "uri" },
          "description": { "type": "string" },
          "md_url": { "type": "string", "format": "uri" },
          "dateModified": { "type": ["string", "null"], "format": "date" },
          "score": { "type": "integer", "description": "Relative match score (higher is better)" }
        }
      },
      "SearchResponse": {
        "type": "object",
        "required": ["query", "count", "results"],
        "properties": {
          "query": { "type": "string" },
          "count": { "type": "integer", "maximum": 10 },
          "results": { "type": "array", "maxItems": 10, "items": { "$ref": "#/components/schemas/SearchHit" } },
          "index": { "type": "string", "format": "uri" }
        }
      },
      "Error": {
        "type": "object",
        "required": ["error", "message"],
        "properties": {
          "error": { "type": "string" },
          "message": { "type": "string" },
          "docs": { "type": "string", "format": "uri" }
        }
      }
    }
  }
}
