{"components":{"schemas":{"ApiError":{"additionalProperties":false,"properties":{"error":{"additionalProperties":false,"properties":{"code":{"type":"string"},"hint":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"type":"object"}},"required":["error"],"type":"object"},"Product":{"additionalProperties":false,"properties":{"ageRange":{"description":"Human-readable age range, or null.","type":["string","null"]},"brand":{"type":"string"},"categories":{"items":{"type":"string"},"type":"array"},"currency":{"enum":["USD","CAD","EUR"],"type":"string"},"description":{"type":["string","null"]},"imageUrl":{"type":["string","null"]},"name":{"type":"string"},"pickedBy":{"description":"Which curator picked the product.","enum":["SAM","KAREL",null],"type":["string","null"]},"price":{"description":"Integer price in the product currency, or null if unpriced.","type":["integer","null"]},"slug":{"type":"string"},"staffPick":{"type":"boolean"},"url":{"format":"uri","type":"string"},"whyWePicked":{"type":["string","null"]}},"required":["ageRange","brand","categories","currency","description","imageUrl","name","pickedBy","price","slug","staffPick","url","whyWePicked"],"type":"object"}},"securitySchemes":{"adminOAuth":{"description":"Admin-only OAuth 2.0 for the MCP server. Public catalog endpoints do not use this.","flows":{"authorizationCode":{"authorizationUrl":"https://www.education.supply/api/auth/authorize","scopes":{},"tokenUrl":"https://www.education.supply/api/auth/token"}},"type":"oauth2"}}},"info":{"contact":{"email":"hello@education.supply","name":"Education Supply","url":"https://www.education.supply/contact"},"description":"Public catalog API for Education Supply — curated hands-on, screen-free learning products. No API key and no signup. Rate limits apply only to `/api/mcp` (admin). HTML pages also serve `text/markdown` when requested via the Accept header (see acceptmarkdown.com).","title":"Education Supply API","version":"1.0.0"},"openapi":"3.1.0","paths":{"/api/health":{"get":{"description":"Liveness probe. Returns `{ status: \"ok\" }` when the app can serve traffic. No catalog data.","operationId":"getHealth","responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":false,"properties":{"status":{"enum":["ok"],"type":"string"}},"required":["status"],"type":"object"}}},"description":"The process is up."}},"summary":"Health check","tags":["meta"]}},"/api/mcp":{"post":{"description":"Admin-only Model Context Protocol endpoint. Requires an OAuth access token for an allowlisted admin. Third-party agents should use `/api/products.json` instead.","operationId":"postMcp","responses":{"200":{"description":"JSON-RPC MCP response."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"Missing or invalid admin OAuth token."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"GET is not allowed; use POST."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"Admin MCP rate limit exceeded (60 req/min)."}},"security":[{"adminOAuth":[]}],"summary":"Admin MCP (not public)","tags":["admin"]}},"/api/products.json":{"get":{"description":"Return every published product in one JSON document. No authentication. Use this for bulk retrieval, RAG corpora, and function-calling tools that need the full catalog. For a single product, prefer `getProductBySlug`.","operationId":"listProducts","responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":false,"properties":{"count":{"type":"integer"},"generatedAt":{"format":"date-time","type":"string"},"products":{"items":{"$ref":"#/components/schemas/Product"},"type":"array"}},"required":["count","generatedAt","products"],"type":"object"}}},"description":"Published catalog snapshot."}},"summary":"List all published products","tags":["catalog"]}},"/api/products/{slug}":{"get":{"description":"Return one published product by its URL slug. No authentication. Responds with a structured JSON error if the slug is unknown.","operationId":"getProductBySlug","parameters":[{"description":"Product slug as it appears in `/products/{slug}` on the site. Max 200 characters.","in":"path","name":"slug","required":true,"schema":{"maxLength":200,"minLength":1,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Product"}}},"description":"The published product."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"No published product has this slug."}},"summary":"Get a published product by slug","tags":["catalog"]}},"/llms-full.txt":{"get":{"description":"Markdown dump of every published product with editorial notes. Prefer `/api/products.json` when you need typed fields.","operationId":"getLlmsFullTxt","responses":{"200":{"content":{"text/plain":{"schema":{"type":"string"}}},"description":"Full catalog as Markdown."}},"summary":"Full product catalog (Markdown)","tags":["agents"]}},"/llms.txt":{"get":{"description":"Agent index for Education Supply: when to use the site, key pages, and links to the catalog feeds.","operationId":"getLlmsTxt","responses":{"200":{"content":{"text/plain":{"schema":{"type":"string"}}},"description":"llms.txt body."}},"summary":"Agent index (llms.txt)","tags":["agents"]}},"/openapi.json":{"get":{"description":"This OpenAPI 3.1 document.","operationId":"getOpenApi","responses":{"200":{"content":{"application/json":{"schema":{"type":"object"}}},"description":"OpenAPI 3.1 specification."}},"summary":"OpenAPI specification","tags":["meta"]}}},"servers":[{"description":"Education Supply","url":"https://www.education.supply"}],"tags":[{"description":"Public product catalog. No auth.","name":"catalog"},{"description":"Agent discovery files.","name":"agents"},{"description":"Service metadata.","name":"meta"},{"description":"Admin-only. Not part of the public catalog.","name":"admin"}]}