{
  "openapi": "3.1.0",
  "info": {
    "title": "pbmate.ro Public AI Content API",
    "version": "1.0.0",
    "description": "A READ-ONLY content API for AI agents and assistants, not a developer platform.\n\npbmate.ro sells a Romanian school-maths practice product (grades 5-12, \nBacalaureat / Evaluarea Nationala prep). This document describes the \nsmall, genuinely-existing public surface an agent can use to answer \nquestions about pbmate.ro or to sample its content: a handful of static \nJSON files under /ai/*, a read-only MCP JSON-RPC server at POST /api/mcp, \nand the crawler/feed endpoints (llms.txt, sitemap, Atom feed, and \nMarkdown twins of key pages).\n\nThere are NO API keys, NO authentication, NO rate-limit tier, and NO \nwrite operations anywhere in this document. Every endpoint listed is a \nGET (or, for the MCP server, a stateless POST) over build-time-constant \nor already-public data - the same content already rendered on the \npublic HTML pages it links back to. pbmate does not offer a developer \nAPI product; nothing here should be read as one.\n\nEvery JSON payload links back to a canonical pbmate.ro HTML page - link \nthat page when citing pbmate, never a .json/.md/API URL.",
    "contact": {
      "name": "pbmate.ro",
      "url": "https://pbmate.ro"
    }
  },
  "servers": [
    {
      "url": "https://pbmate.ro",
      "description": "Production"
    }
  ],
  "security": [],
  "tags": [
    {
      "name": "Site facts",
      "description": "What pbmate.ro is, costs, and offers."
    },
    {
      "name": "Exercises",
      "description": "The public exercise taster, by chapter."
    },
    {
      "name": "Formulas",
      "description": "The /formule reference library."
    },
    {
      "name": "MCP",
      "description": "The read-only MCP JSON-RPC server (Streamable HTTP)."
    },
    {
      "name": "Discovery",
      "description": "Crawler/agent discovery surface: llms.txt, sitemap, feed, Markdown page twins."
    }
  ],
  "paths": {
    "/ai/pbmate.json": {
      "get": {
        "operationId": "getSiteFacts",
        "summary": "Site facts",
        "description": "Argument-free facts about pbmate.ro: what it is, pricing, what's free, grade coverage, and canonical/markdown/endpoint URLs. Static JSON, revalidated daily.",
        "tags": [
          "Site facts"
        ],
        "responses": {
          "200": {
            "description": "Site facts.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "_note": {
                      "type": "string"
                    },
                    "_reuse": {
                      "type": "string",
                      "description": "Bilingual (RO/EN) reuse/attribution note — factual, not a license grant."
                    },
                    "name": {
                      "type": "string"
                    },
                    "summary": {
                      "type": "string"
                    },
                    "positioning": {
                      "type": "string"
                    },
                    "librarySize": {
                      "type": "string"
                    },
                    "grades": {
                      "type": "array",
                      "items": {
                        "type": "integer"
                      }
                    },
                    "pricing": {
                      "type": "object",
                      "properties": {
                        "currency": {
                          "type": "string",
                          "enum": [
                            "RON"
                          ]
                        },
                        "monthlyPerMonth": {
                          "type": "number"
                        },
                        "yearlyPerMonth": {
                          "type": "number"
                        },
                        "yearlyTotal": {
                          "type": "number"
                        },
                        "display": {
                          "type": "object",
                          "description": "Romanian-formatted display strings (comma decimal separator), the exact copy shown on pbmate.ro.",
                          "properties": {
                            "monthly": {
                              "type": "string"
                            },
                            "yearly": {
                              "type": "string"
                            },
                            "yearlyWas": {
                              "type": "string"
                            },
                            "yearlyTotal": {
                              "type": "string"
                            },
                            "unit": {
                              "type": "string"
                            },
                            "discountBadge": {
                              "type": "string"
                            },
                            "savingsPill": {
                              "type": "string"
                            }
                          },
                          "required": [
                            "monthly",
                            "yearly",
                            "yearlyWas",
                            "yearlyTotal",
                            "unit",
                            "discountBadge",
                            "savingsPill"
                          ]
                        }
                      },
                      "required": [
                        "currency",
                        "monthlyPerMonth",
                        "yearlyPerMonth",
                        "yearlyTotal",
                        "display"
                      ]
                    },
                    "free": {
                      "type": "string"
                    },
                    "canonicalUrl": {
                      "type": "string",
                      "format": "uri"
                    },
                    "markdownUrls": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "format": "uri"
                      }
                    },
                    "endpoints": {
                      "type": "object",
                      "properties": {
                        "capitole": {
                          "type": "string",
                          "format": "uri"
                        },
                        "formule": {
                          "type": "string",
                          "format": "uri"
                        },
                        "mcp": {
                          "type": "string",
                          "format": "uri"
                        }
                      },
                      "required": [
                        "capitole",
                        "formule",
                        "mcp"
                      ]
                    }
                  },
                  "required": [
                    "name",
                    "summary",
                    "canonicalUrl",
                    "pricing"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/ai/capitole.json": {
      "get": {
        "operationId": "listCapitole",
        "summary": "List all exercise chapters",
        "description": "Enumerates every valid {clasa, capitolSlug} pair with a public exercise taster. This closes the parameter space for GET /ai/exercitii/{bucket}.json - a caller may only ever request a bucket that appears in this list.",
        "tags": [
          "Exercises"
        ],
        "responses": {
          "200": {
            "description": "Every chapter with public exercises.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "_note": {
                      "type": "string"
                    },
                    "_reuse": {
                      "type": "string"
                    },
                    "canonicalUrl": {
                      "type": "string",
                      "format": "uri"
                    },
                    "capitole": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "clasa": {
                            "type": "integer",
                            "enum": [
                              5,
                              6,
                              7,
                              8,
                              9,
                              10,
                              11,
                              12
                            ]
                          },
                          "capitolSlug": {
                            "type": "string"
                          },
                          "titlu": {
                            "type": "string"
                          },
                          "exerciseCount": {
                            "type": "integer"
                          },
                          "pageUrl": {
                            "type": "string",
                            "format": "uri"
                          },
                          "bucket": {
                            "type": "string",
                            "description": "`${clasa}-${capitolSlug}` — the id GET /ai/exercitii/{bucket}.json expects."
                          }
                        },
                        "required": [
                          "clasa",
                          "capitolSlug",
                          "titlu",
                          "exerciseCount",
                          "pageUrl",
                          "bucket"
                        ]
                      }
                    }
                  },
                  "required": [
                    "canonicalUrl",
                    "capitole"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/ai/formule.json": {
      "get": {
        "operationId": "listFormule",
        "summary": "List all formula reference topics",
        "description": "The closed set of /formule topic pages (e.g. derivate, integrale, trigonometrie).",
        "tags": [
          "Formulas"
        ],
        "responses": {
          "200": {
            "description": "Every formula reference topic.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "_note": {
                      "type": "string"
                    },
                    "_reuse": {
                      "type": "string"
                    },
                    "canonicalUrl": {
                      "type": "string",
                      "format": "uri"
                    },
                    "formule": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "slug": {
                            "type": "string",
                            "enum": [
                              "integrale",
                              "trigonometrie",
                              "derivate",
                              "logaritmi",
                              "limite",
                              "progresii",
                              "binomul-lui-newton",
                              "combinatorica",
                              "numere-complexe",
                              "matrice",
                              "geometrie",
                              "ecuatii-trigonometrice",
                              "ecuatii-gradul-doi",
                              "probabilitati",
                              "continuitate"
                            ]
                          },
                          "titlu": {
                            "type": "string"
                          },
                          "chapter": {
                            "type": "string"
                          },
                          "pageUrl": {
                            "type": "string",
                            "format": "uri"
                          },
                          "markdownUrl": {
                            "type": "string",
                            "format": "uri"
                          }
                        },
                        "required": [
                          "slug",
                          "titlu",
                          "chapter",
                          "pageUrl",
                          "markdownUrl"
                        ]
                      }
                    }
                  },
                  "required": [
                    "canonicalUrl",
                    "formule"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/ai/exercitii/{bucket}.json": {
      "get": {
        "operationId": "getExercitiiBucket",
        "summary": "Get one chapter's exercise taster",
        "description": "One prerendered file per {clasa, capitol} bucket, id = `${clasa}-${capitolSlug}` (e.g. `11-derivate.json`). Valid bucket ids come from GET /ai/capitole.json's `bucket` field. Answers ARE included here (correctIndex/solution) - this file mirrors the public /p/exercitii page's DOM, which already reveals them behind a collapsed detail. An unknown bucket 404s.",
        "tags": [
          "Exercises"
        ],
        "parameters": [
          {
            "name": "bucket",
            "in": "path",
            "required": true,
            "description": "`${clasa}-${capitolSlug}.json`, e.g. `11-derivate.json`. Enumerated by GET /ai/capitole.json.",
            "schema": {
              "type": "string",
              "pattern": "^(5|6|7|8|9|10|11|12)-[a-z0-9-]+\\.json$"
            },
            "example": "11-derivate.json"
          }
        ],
        "responses": {
          "200": {
            "description": "The chapter's exercise taster, with answers.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "_note": {
                      "type": "string"
                    },
                    "clasa": {
                      "type": "integer",
                      "enum": [
                        5,
                        6,
                        7,
                        8,
                        9,
                        10,
                        11,
                        12
                      ]
                    },
                    "capitolSlug": {
                      "type": "string"
                    },
                    "titlu": {
                      "type": "string"
                    },
                    "pageUrl": {
                      "type": "string",
                      "format": "uri"
                    },
                    "markdownUrl": {
                      "type": "string",
                      "format": "uri",
                      "description": "The Markdown twin of `pageUrl`."
                    },
                    "totalEligible": {
                      "type": "integer",
                      "description": "Full eligible count in this bucket; `exercises` is a taster capped well below it."
                    },
                    "_reuse": {
                      "type": "string"
                    },
                    "exercises": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "description": "One MCQ exercise from pbmate's public taster set — the same data already rendered on the indexable /p/exercitii page.",
                        "properties": {
                          "id": {
                            "type": "string",
                            "description": "Opaque stable id — pass it verbatim to POST /api/mcp's `rezolvare` tool. Do not construct or parse it; the format is not stable across authoring pipelines."
                          },
                          "prompt": {
                            "type": "string",
                            "description": "The question, as Markdown/LaTeX (`$…$` / `$$…$$`)."
                          },
                          "choices": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            },
                            "minItems": 2,
                            "description": "Answer options, in display order."
                          },
                          "correctIndex": {
                            "type": "integer",
                            "minimum": 0,
                            "description": "0-based index into `choices`. Omitted from the MCP `exercitii` tool result on purpose (see /api/mcp docs) — present here because this static JSON mirrors the public page DOM, which already reveals it behind a collapsed <details>."
                          },
                          "hint": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "solution": {
                            "type": "string",
                            "description": "Worked solution, Markdown/LaTeX."
                          },
                          "tier": {
                            "type": "string",
                            "enum": [
                              "Beginner",
                              "Medium",
                              "Advanced",
                              "Expert",
                              "Olympiad"
                            ],
                            "description": "Difficulty tier."
                          },
                          "points": {
                            "type": "integer"
                          },
                          "url": {
                            "type": "string",
                            "format": "uri",
                            "description": "Canonical HTML page for this exercise's chapter. There is no per-exercise page; every exercise in a bucket carries its chapter's URL, repeated per item so a client quoting one exercise still has a link."
                          }
                        },
                        "required": [
                          "id",
                          "prompt",
                          "choices",
                          "correctIndex",
                          "hint",
                          "solution",
                          "tier",
                          "points",
                          "url"
                        ]
                      }
                    }
                  },
                  "required": [
                    "clasa",
                    "capitolSlug",
                    "titlu",
                    "pageUrl",
                    "markdownUrl",
                    "totalEligible",
                    "exercises"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Unknown bucket id — not one of GET /ai/capitole.json's enumerated buckets. NOTE: this 404 is served by the framework as text/html, not JSON; do not attempt to parse the body."
          }
        }
      }
    },
    "/api/mcp": {
      "post": {
        "operationId": "callMcpServer",
        "summary": "MCP JSON-RPC 2.0 endpoint (Streamable HTTP)",
        "description": "A hand-rolled MCP server (protocolVersion 2025-06-18, also accepts \n2025-03-26), Streamable HTTP transport, POST only. Read-only: every \none of its 5 tools reads the same build-time-constant data as the \nGET /ai/*.json files above; there is no database on this request \npath and no write operation of any kind.\n\nSend `{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\"}` to discover \nthe live tool catalog (name, description, inputSchema, outputSchema) - \nthe 5 tools are also listed below as this operation's `x-mcp-tools` \nextension, for a client that wants typed schemas without an extra \nround trip. Call a tool with \n`{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/call\",\"params\":{\"name\":\"...\",\"arguments\":{...}}}`.\n\nUnauthenticated, CORS-open (`Access-Control-Allow-Origin: *`), rate- \nlimited per IP (60 req/60s, best-effort/per-instance) and body-capped \n(16 KB request, 32 KB response). GET on this path returns a JSON 405 \nexplaining the transport (it does not offer an SSE stream).",
        "tags": [
          "MCP"
        ],
        "x-mcp-tools": [
          {
            "name": "despre_pbmate",
            "summary": "What pbmate.ro is: summary, positioning, price, and links. No arguments.",
            "inputSchema": {
              "type": "object",
              "properties": {},
              "additionalProperties": false
            },
            "outputSchema": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "summary": {
                  "type": "string"
                },
                "positioning": {
                  "type": "string"
                },
                "librarySize": {
                  "type": "string"
                },
                "grades": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  }
                },
                "pricing": {
                  "type": "object",
                  "properties": {
                    "currency": {
                      "type": "string"
                    },
                    "monthlyPerMonth": {
                      "type": "number"
                    },
                    "yearlyPerMonth": {
                      "type": "number"
                    },
                    "yearlyTotal": {
                      "type": "number"
                    },
                    "display": {
                      "type": "object"
                    }
                  }
                },
                "free": {
                  "type": "string"
                },
                "canonicalUrl": {
                  "type": "string"
                },
                "markdownUrls": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "endpoints": {
                  "type": "object"
                },
                "_reuse": {
                  "type": "string"
                }
              },
              "required": [
                "name",
                "summary",
                "canonicalUrl",
                "pricing"
              ]
            }
          },
          {
            "name": "lista_capitole",
            "summary": "The chapters with public exercises (clasa, slug, title, exercise count, URL). Pass `clasa` to filter.",
            "inputSchema": {
              "type": "object",
              "properties": {
                "clasa": {
                  "type": "integer",
                  "enum": [
                    5,
                    6,
                    7,
                    8,
                    9,
                    10,
                    11,
                    12
                  ],
                  "description": "Optional. Grade 5-12. Omitted -> every chapter."
                }
              },
              "additionalProperties": false
            },
            "outputSchema": {
              "type": "object",
              "properties": {
                "canonicalUrl": {
                  "type": "string"
                },
                "clasa": {
                  "type": [
                    "integer",
                    "null"
                  ]
                },
                "capitole": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "clasa": {
                        "type": "integer"
                      },
                      "capitolSlug": {
                        "type": "string"
                      },
                      "titlu": {
                        "type": "string"
                      },
                      "exerciseCount": {
                        "type": "integer"
                      },
                      "pageUrl": {
                        "type": "string"
                      },
                      "bucket": {
                        "type": "string"
                      }
                    },
                    "required": [
                      "clasa",
                      "capitolSlug",
                      "titlu",
                      "exerciseCount",
                      "pageUrl",
                      "bucket"
                    ]
                  }
                },
                "_reuse": {
                  "type": "string"
                }
              },
              "required": [
                "canonicalUrl",
                "capitole"
              ]
            }
          },
          {
            "name": "exercitii",
            "summary": "Exercises from one chapter (clasa + capitol), WITHOUT the answer. Optional `dificultate` filter and `numar` cap.",
            "inputSchema": {
              "type": "object",
              "properties": {
                "clasa": {
                  "type": "integer",
                  "enum": [
                    5,
                    6,
                    7,
                    8,
                    9,
                    10,
                    11,
                    12
                  ],
                  "description": "Grade, 5-12."
                },
                "capitol": {
                  "type": "string",
                  "description": "Chapter slug (see `lista_capitole`), specific to each grade."
                },
                "dificultate": {
                  "description": "Optional difficulty filter - a single value or an array of values from: Beginner, Medium, Advanced, Expert, Olympiad. Default: no filter.",
                  "oneOf": [
                    {
                      "type": "string",
                      "enum": [
                        "Beginner",
                        "Medium",
                        "Advanced",
                        "Expert",
                        "Olympiad"
                      ]
                    },
                    {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "enum": [
                          "Beginner",
                          "Medium",
                          "Advanced",
                          "Expert",
                          "Olympiad"
                        ]
                      },
                      "minItems": 1
                    }
                  ]
                },
                "numar": {
                  "type": "integer",
                  "minimum": 1,
                  "maximum": 12,
                  "description": "Maximum number of exercises to return. Default: all available after the difficulty filter."
                }
              },
              "required": [
                "clasa",
                "capitol"
              ],
              "additionalProperties": false
            },
            "outputSchema": {
              "type": "object",
              "properties": {
                "clasa": {
                  "type": "integer"
                },
                "capitolSlug": {
                  "type": "string"
                },
                "titlu": {
                  "type": "string"
                },
                "pageUrl": {
                  "type": "string"
                },
                "markdownUrl": {
                  "type": "string"
                },
                "totalEligible": {
                  "type": "integer"
                },
                "_reuse": {
                  "type": "string"
                },
                "exercises": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "prompt": {
                        "type": "string"
                      },
                      "choices": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      },
                      "hint": {
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "tier": {
                        "type": "string"
                      },
                      "url": {
                        "type": "string"
                      }
                    },
                    "required": [
                      "id",
                      "prompt",
                      "choices",
                      "tier",
                      "url"
                    ]
                  }
                }
              },
              "required": [
                "clasa",
                "capitolSlug",
                "titlu",
                "pageUrl",
                "markdownUrl",
                "totalEligible",
                "exercises"
              ]
            }
          },
          {
            "name": "rezolvare",
            "summary": "The correct answer and worked solution for ONE exercise, by the exact `id` `exercitii` returned. Call only after the user attempted it or asked for it.",
            "inputSchema": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "description": "Exercise id exactly as returned by `exercitii` (format `capitol:id`)."
                }
              },
              "required": [
                "id"
              ],
              "additionalProperties": false
            },
            "outputSchema": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "correctIndex": {
                  "type": "integer"
                },
                "solution": {
                  "type": "string"
                },
                "pageUrl": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "_reuse": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "correctIndex",
                "solution",
                "pageUrl",
                "url"
              ]
            }
          },
          {
            "name": "formule",
            "summary": "The formulas for one reference topic (e.g. derivate, integrale, trigonometrie) and its public pbmate.ro/formule page URL.",
            "inputSchema": {
              "type": "object",
              "properties": {
                "capitol": {
                  "type": "string",
                  "enum": [
                    "integrale",
                    "trigonometrie",
                    "derivate",
                    "logaritmi",
                    "limite",
                    "progresii",
                    "binomul-lui-newton",
                    "combinatorica",
                    "numere-complexe",
                    "matrice",
                    "geometrie",
                    "ecuatii-trigonometrice",
                    "ecuatii-gradul-doi",
                    "probabilitati",
                    "continuitate"
                  ],
                  "description": "Formula chapter slug."
                }
              },
              "required": [
                "capitol"
              ],
              "additionalProperties": false
            },
            "outputSchema": {
              "type": "object",
              "properties": {
                "slug": {
                  "type": "string"
                },
                "titlu": {
                  "type": "string"
                },
                "chapter": {
                  "type": "string"
                },
                "pageUrl": {
                  "type": "string"
                },
                "markdownUrl": {
                  "type": "string"
                },
                "_reuse": {
                  "type": "string"
                },
                "directAnswer": {
                  "type": "string"
                },
                "groups": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "title": {
                        "type": "string"
                      },
                      "intro": {
                        "type": "string"
                      },
                      "table": {
                        "type": "object",
                        "properties": {
                          "head": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "rows": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "label": {
                                  "type": "string"
                                },
                                "cells": {
                                  "type": "array",
                                  "items": {
                                    "type": "string"
                                  }
                                }
                              },
                              "required": [
                                "label",
                                "cells"
                              ]
                            }
                          }
                        },
                        "required": [
                          "head",
                          "rows"
                        ]
                      },
                      "formulas": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string"
                            },
                            "name": {
                              "type": "string"
                            },
                            "latex": {
                              "type": "string"
                            },
                            "condition": {
                              "type": "string"
                            }
                          },
                          "required": [
                            "id",
                            "latex"
                          ]
                        }
                      }
                    },
                    "required": [
                      "id",
                      "title",
                      "formulas"
                    ]
                  }
                },
                "note": {
                  "type": "string"
                }
              },
              "required": [
                "slug",
                "titlu",
                "chapter",
                "pageUrl",
                "markdownUrl",
                "directAnswer",
                "groups"
              ]
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "JSON-RPC 2.0 request. `tools/list` takes no params; `tools/call` takes { name, arguments }; `initialize` and `ping` are also supported.",
                "properties": {
                  "jsonrpc": {
                    "type": "string",
                    "enum": [
                      "2.0"
                    ]
                  },
                  "id": {
                    "oneOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "number"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "method": {
                    "type": "string",
                    "enum": [
                      "initialize",
                      "ping",
                      "tools/list",
                      "tools/call"
                    ]
                  },
                  "params": {
                    "type": "object"
                  }
                },
                "required": [
                  "jsonrpc",
                  "method"
                ]
              },
              "examples": {
                "tools/list": {
                  "value": {
                    "jsonrpc": "2.0",
                    "id": 1,
                    "method": "tools/list"
                  }
                },
                "tools/call": {
                  "value": {
                    "jsonrpc": "2.0",
                    "id": 2,
                    "method": "tools/call",
                    "params": {
                      "name": "exercitii",
                      "arguments": {
                        "clasa": 11,
                        "capitol": "derivate",
                        "numar": 3
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC 2.0 success or error result (JSON-RPC errors are still HTTP 200, per spec).",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "type": "object",
                      "properties": {
                        "jsonrpc": {
                          "type": "string",
                          "enum": [
                            "2.0"
                          ]
                        },
                        "id": {
                          "oneOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "number"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "result": {
                          "type": "object",
                          "description": "Shape depends on `method` — see the `tools/list`/`tools/call` examples on this operation."
                        }
                      },
                      "required": [
                        "jsonrpc",
                        "id",
                        "result"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "jsonrpc": {
                          "type": "string",
                          "enum": [
                            "2.0"
                          ]
                        },
                        "id": {
                          "oneOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "number"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "error": {
                          "type": "object",
                          "properties": {
                            "code": {
                              "type": "integer"
                            },
                            "message": {
                              "type": "string"
                            },
                            "data": {}
                          },
                          "required": [
                            "code",
                            "message"
                          ]
                        }
                      },
                      "required": [
                        "jsonrpc",
                        "id",
                        "error"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "202": {
            "description": "Accepted with no body - the request was a JSON-RPC Notification (no `id`), which per spec gets no reply."
          },
          "405": {
            "description": "Wrong method (e.g. a GET probe). JSON body, not bare text.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    },
                    "transport": {
                      "type": "string"
                    },
                    "method": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error",
                    "message"
                  ]
                }
              }
            }
          },
          "413": {
            "description": "Request body exceeded 16 KB."
          },
          "429": {
            "description": "Per-IP rate limit exceeded (60 requests / 60s).",
            "headers": {
              "retry-after": {
                "schema": {
                  "type": "integer"
                },
                "description": "Seconds until the window resets."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "jsonrpc": {
                      "type": "string",
                      "enum": [
                        "2.0"
                      ]
                    },
                    "id": {
                      "oneOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "number"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "integer"
                        },
                        "message": {
                          "type": "string"
                        },
                        "data": {}
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "jsonrpc",
                    "id",
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/llms.txt": {
      "get": {
        "operationId": "getLlmsTxt",
        "summary": "Machine-readable site map for AI agents",
        "description": "Every public page pbmate.ro has, what the platform costs, which pages have a Markdown twin, and the /ai/*.json + /api/mcp endpoints - as plain-text prose meant to be read directly by a language model, not parsed as structured data.",
        "tags": [
          "Discovery"
        ],
        "responses": {
          "200": {
            "description": "The llms.txt document.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/sitemap.xml": {
      "get": {
        "operationId": "getSitemap",
        "summary": "XML sitemap",
        "description": "Standard sitemaps.org XML sitemap of every indexable pbmate.ro URL.",
        "tags": [
          "Discovery"
        ],
        "responses": {
          "200": {
            "description": "The sitemap.",
            "content": {
              "application/xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/feed.xml": {
      "get": {
        "operationId": "getFeed",
        "summary": "Atom feed",
        "description": "Atom feed of pbmate.ro's public posts/articles.",
        "tags": [
          "Discovery"
        ],
        "responses": {
          "200": {
            "description": "The feed.",
            "content": {
              "application/atom+xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/{page}.md": {
      "get": {
        "operationId": "getMarkdownTwin",
        "summary": "Markdown twin of a marketing page",
        "description": "One of pbmate.ro's 11 fixed Markdown twins - a plain-Markdown mirror of an HTML marketing page, meant to be read by an assistant instead of scraping the rendered page. Carries `Link: rel=\"canonical\"` back to the HTML page and `X-Robots-Tag: noindex`. Two more content types (exercise chapters, formula topics) get a generated twin at `/p/exercitii/clasa-{N}/{capitol}.md` and `/formule/{slug}.md` respectively - not modeled here as a fixed enum since the valid {N, capitol, slug} values are the same open sets GET /ai/capitole.json and GET /ai/formule.json enumerate.",
        "tags": [
          "Discovery"
        ],
        "parameters": [
          {
            "name": "page",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "index",
                "platforma",
                "formule",
                "parinte",
                "preturi",
                "grile",
                "olimpiada",
                "program-afiliere",
                "liceu",
                "admitere-politehnica",
                "pentru-profesori"
              ]
            },
            "example": "platforma"
          }
        ],
        "responses": {
          "200": {
            "description": "The page as Markdown.",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "SiteFacts": {
        "type": "object",
        "properties": {
          "_note": {
            "type": "string"
          },
          "_reuse": {
            "type": "string",
            "description": "Bilingual (RO/EN) reuse/attribution note — factual, not a license grant."
          },
          "name": {
            "type": "string"
          },
          "summary": {
            "type": "string"
          },
          "positioning": {
            "type": "string"
          },
          "librarySize": {
            "type": "string"
          },
          "grades": {
            "type": "array",
            "items": {
              "type": "integer"
            }
          },
          "pricing": {
            "type": "object",
            "properties": {
              "currency": {
                "type": "string",
                "enum": [
                  "RON"
                ]
              },
              "monthlyPerMonth": {
                "type": "number"
              },
              "yearlyPerMonth": {
                "type": "number"
              },
              "yearlyTotal": {
                "type": "number"
              },
              "display": {
                "type": "object",
                "description": "Romanian-formatted display strings (comma decimal separator), the exact copy shown on pbmate.ro.",
                "properties": {
                  "monthly": {
                    "type": "string"
                  },
                  "yearly": {
                    "type": "string"
                  },
                  "yearlyWas": {
                    "type": "string"
                  },
                  "yearlyTotal": {
                    "type": "string"
                  },
                  "unit": {
                    "type": "string"
                  },
                  "discountBadge": {
                    "type": "string"
                  },
                  "savingsPill": {
                    "type": "string"
                  }
                },
                "required": [
                  "monthly",
                  "yearly",
                  "yearlyWas",
                  "yearlyTotal",
                  "unit",
                  "discountBadge",
                  "savingsPill"
                ]
              }
            },
            "required": [
              "currency",
              "monthlyPerMonth",
              "yearlyPerMonth",
              "yearlyTotal",
              "display"
            ]
          },
          "free": {
            "type": "string"
          },
          "canonicalUrl": {
            "type": "string",
            "format": "uri"
          },
          "markdownUrls": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uri"
            }
          },
          "endpoints": {
            "type": "object",
            "properties": {
              "capitole": {
                "type": "string",
                "format": "uri"
              },
              "formule": {
                "type": "string",
                "format": "uri"
              },
              "mcp": {
                "type": "string",
                "format": "uri"
              }
            },
            "required": [
              "capitole",
              "formule",
              "mcp"
            ]
          }
        },
        "required": [
          "name",
          "summary",
          "canonicalUrl",
          "pricing"
        ]
      },
      "CapitolSummary": {
        "type": "object",
        "properties": {
          "clasa": {
            "type": "integer",
            "enum": [
              5,
              6,
              7,
              8,
              9,
              10,
              11,
              12
            ]
          },
          "capitolSlug": {
            "type": "string"
          },
          "titlu": {
            "type": "string"
          },
          "exerciseCount": {
            "type": "integer"
          },
          "pageUrl": {
            "type": "string",
            "format": "uri"
          },
          "bucket": {
            "type": "string",
            "description": "`${clasa}-${capitolSlug}` — the id GET /ai/exercitii/{bucket}.json expects."
          }
        },
        "required": [
          "clasa",
          "capitolSlug",
          "titlu",
          "exerciseCount",
          "pageUrl",
          "bucket"
        ]
      },
      "FormuleSummary": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string",
            "enum": [
              "integrale",
              "trigonometrie",
              "derivate",
              "logaritmi",
              "limite",
              "progresii",
              "binomul-lui-newton",
              "combinatorica",
              "numere-complexe",
              "matrice",
              "geometrie",
              "ecuatii-trigonometrice",
              "ecuatii-gradul-doi",
              "probabilitati",
              "continuitate"
            ]
          },
          "titlu": {
            "type": "string"
          },
          "chapter": {
            "type": "string"
          },
          "pageUrl": {
            "type": "string",
            "format": "uri"
          },
          "markdownUrl": {
            "type": "string",
            "format": "uri"
          }
        },
        "required": [
          "slug",
          "titlu",
          "chapter",
          "pageUrl",
          "markdownUrl"
        ]
      },
      "PublicExercise": {
        "type": "object",
        "description": "One MCQ exercise from pbmate's public taster set — the same data already rendered on the indexable /p/exercitii page.",
        "properties": {
          "id": {
            "type": "string",
            "description": "Opaque stable id — pass it verbatim to POST /api/mcp's `rezolvare` tool. Do not construct or parse it; the format is not stable across authoring pipelines."
          },
          "prompt": {
            "type": "string",
            "description": "The question, as Markdown/LaTeX (`$…$` / `$$…$$`)."
          },
          "choices": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "minItems": 2,
            "description": "Answer options, in display order."
          },
          "correctIndex": {
            "type": "integer",
            "minimum": 0,
            "description": "0-based index into `choices`. Omitted from the MCP `exercitii` tool result on purpose (see /api/mcp docs) — present here because this static JSON mirrors the public page DOM, which already reveals it behind a collapsed <details>."
          },
          "hint": {
            "type": [
              "string",
              "null"
            ]
          },
          "solution": {
            "type": "string",
            "description": "Worked solution, Markdown/LaTeX."
          },
          "tier": {
            "type": "string",
            "enum": [
              "Beginner",
              "Medium",
              "Advanced",
              "Expert",
              "Olympiad"
            ],
            "description": "Difficulty tier."
          },
          "points": {
            "type": "integer"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Canonical HTML page for this exercise's chapter. There is no per-exercise page; every exercise in a bucket carries its chapter's URL, repeated per item so a client quoting one exercise still has a link."
          }
        },
        "required": [
          "id",
          "prompt",
          "choices",
          "correctIndex",
          "hint",
          "solution",
          "tier",
          "points",
          "url"
        ]
      },
      "ExercitiiBucketPayload": {
        "type": "object",
        "properties": {
          "_note": {
            "type": "string"
          },
          "clasa": {
            "type": "integer",
            "enum": [
              5,
              6,
              7,
              8,
              9,
              10,
              11,
              12
            ]
          },
          "capitolSlug": {
            "type": "string"
          },
          "titlu": {
            "type": "string"
          },
          "pageUrl": {
            "type": "string",
            "format": "uri"
          },
          "markdownUrl": {
            "type": "string",
            "format": "uri",
            "description": "The Markdown twin of `pageUrl`."
          },
          "totalEligible": {
            "type": "integer",
            "description": "Full eligible count in this bucket; `exercises` is a taster capped well below it."
          },
          "_reuse": {
            "type": "string"
          },
          "exercises": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "One MCQ exercise from pbmate's public taster set — the same data already rendered on the indexable /p/exercitii page.",
              "properties": {
                "id": {
                  "type": "string",
                  "description": "Opaque stable id — pass it verbatim to POST /api/mcp's `rezolvare` tool. Do not construct or parse it; the format is not stable across authoring pipelines."
                },
                "prompt": {
                  "type": "string",
                  "description": "The question, as Markdown/LaTeX (`$…$` / `$$…$$`)."
                },
                "choices": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "minItems": 2,
                  "description": "Answer options, in display order."
                },
                "correctIndex": {
                  "type": "integer",
                  "minimum": 0,
                  "description": "0-based index into `choices`. Omitted from the MCP `exercitii` tool result on purpose (see /api/mcp docs) — present here because this static JSON mirrors the public page DOM, which already reveals it behind a collapsed <details>."
                },
                "hint": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "solution": {
                  "type": "string",
                  "description": "Worked solution, Markdown/LaTeX."
                },
                "tier": {
                  "type": "string",
                  "enum": [
                    "Beginner",
                    "Medium",
                    "Advanced",
                    "Expert",
                    "Olympiad"
                  ],
                  "description": "Difficulty tier."
                },
                "points": {
                  "type": "integer"
                },
                "url": {
                  "type": "string",
                  "format": "uri",
                  "description": "Canonical HTML page for this exercise's chapter. There is no per-exercise page; every exercise in a bucket carries its chapter's URL, repeated per item so a client quoting one exercise still has a link."
                }
              },
              "required": [
                "id",
                "prompt",
                "choices",
                "correctIndex",
                "hint",
                "solution",
                "tier",
                "points",
                "url"
              ]
            }
          }
        },
        "required": [
          "clasa",
          "capitolSlug",
          "titlu",
          "pageUrl",
          "markdownUrl",
          "totalEligible",
          "exercises"
        ]
      },
      "JsonRpcRequest": {
        "type": "object",
        "description": "JSON-RPC 2.0 request. `tools/list` takes no params; `tools/call` takes { name, arguments }; `initialize` and `ping` are also supported.",
        "properties": {
          "jsonrpc": {
            "type": "string",
            "enum": [
              "2.0"
            ]
          },
          "id": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "method": {
            "type": "string",
            "enum": [
              "initialize",
              "ping",
              "tools/list",
              "tools/call"
            ]
          },
          "params": {
            "type": "object"
          }
        },
        "required": [
          "jsonrpc",
          "method"
        ]
      },
      "JsonRpcSuccess": {
        "type": "object",
        "properties": {
          "jsonrpc": {
            "type": "string",
            "enum": [
              "2.0"
            ]
          },
          "id": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "result": {
            "type": "object",
            "description": "Shape depends on `method` — see the `tools/list`/`tools/call` examples on this operation."
          }
        },
        "required": [
          "jsonrpc",
          "id",
          "result"
        ]
      },
      "JsonRpcError": {
        "type": "object",
        "properties": {
          "jsonrpc": {
            "type": "string",
            "enum": [
              "2.0"
            ]
          },
          "id": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "integer"
              },
              "message": {
                "type": "string"
              },
              "data": {}
            },
            "required": [
              "code",
              "message"
            ]
          }
        },
        "required": [
          "jsonrpc",
          "id",
          "error"
        ]
      }
    }
  }
}