{
  "openapi": "3.1.0",
  "info": {
    "title": "Mexifan public content API",
    "version": "1.0.0",
    "summary": "Read-only, unauthenticated access to the public pages of mexifan.app as Markdown, plus llms.txt, the sitemap and this document.",
    "description": "Mexifan es el fantasy de la Liga MX. Esta especificación describe lo único que es público y sin autenticación: el contenido del sitio en Markdown (por negociación de `Accept` o con el sufijo `.md`), el índice llms.txt, el sitemap y este documento.\n\n**There is no gameplay API.** No endpoint creates accounts, lineups or leagues, or reads user data, scores or player statistics; the web and mobile apps use a private, session-bound API that is neither documented nor supported for third parties.\n\nAuthentication: none. Rate limit: none published; fair use is expected (one request per second reads the whole site) with a `User-Agent` that names your agent or product. Markdown responses are `Cache-Control: private, no-store`; cache them on your side.\n\nGuide for developers and agents: https://mexifan.app/desarrolladores. Partnerships and data requests: info@mexifan.mx.",
    "termsOfService": "https://mexifan.app/terminos",
    "license": {
      "name": "Mexifan terms of service",
      "url": "https://mexifan.app/terminos"
    },
    "contact": {
      "name": "Mexifan",
      "url": "https://mexifan.app/contactanos",
      "email": "info@mexifan.mx"
    }
  },
  "externalDocs": {
    "description": "Guía para desarrolladores y agentes",
    "url": "https://mexifan.app/desarrolladores"
  },
  "servers": [
    {
      "url": "https://mexifan.app",
      "description": "Producción"
    }
  ],
  "security": [],
  "tags": [
    {
      "name": "pages",
      "description": "Public pages of the site, served as HTML or Markdown depending on `Accept`, or always as Markdown with a `.md` suffix."
    },
    {
      "name": "discovery",
      "description": "Machine-readable indexes: llms.txt, the full-text bundle, the sitemap, robots.txt and this document."
    }
  ],
  "paths": {
    "/": {
      "get": {
        "operationId": "getHome",
        "tags": [
          "pages"
        ],
        "summary": "Home page (HTML or Markdown)",
        "description": "The home page: what Mexifan is, how points are scored, the rules in short and the plans. Content negotiation per acceptmarkdown.com: `Accept` is ranked by q-value and specificity, `q=0` is honored, and `text/markdown` wins when it ranks above `text/html`. Without an `Accept` header, or with `*/*`, the response is HTML. The Markdown body is the same content as the HTML page, without navigation, with absolute links.",
        "responses": {
          "200": {
            "description": "The home page in the negotiated representation.",
            "headers": {
              "Vary": {
                "$ref": "#/components/headers/Vary"
              }
            },
            "content": {
              "text/markdown": {
                "schema": {
                  "$ref": "#/components/schemas/MarkdownDocument"
                }
              },
              "text/html": {
                "schema": {
                  "$ref": "#/components/schemas/HtmlDocument"
                }
              }
            }
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          }
        }
      }
    },
    "/{page}": {
      "get": {
        "operationId": "getPage",
        "tags": [
          "pages"
        ],
        "summary": "A public page (HTML or Markdown)",
        "description": "One of the public pages: how to play, the rulebook, the FAQ, the blog index, about, contact, the developer guide, terms and privacy. Content negotiation per acceptmarkdown.com: `Accept` is ranked by q-value and specificity, `q=0` is honored, and `text/markdown` wins when it ranks above `text/html`. Without an `Accept` header, or with `*/*`, the response is HTML. The Markdown body is the same content as the HTML page, without navigation, with absolute links.",
        "parameters": [
          {
            "$ref": "#/components/parameters/PageSlug"
          }
        ],
        "responses": {
          "200": {
            "description": "The page in the negotiated representation.",
            "headers": {
              "Vary": {
                "$ref": "#/components/headers/Vary"
              }
            },
            "content": {
              "text/markdown": {
                "schema": {
                  "$ref": "#/components/schemas/MarkdownDocument"
                }
              },
              "text/html": {
                "schema": {
                  "$ref": "#/components/schemas/HtmlDocument"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          }
        }
      }
    },
    "/{page}.md": {
      "get": {
        "operationId": "getPageMarkdown",
        "tags": [
          "pages"
        ],
        "summary": "A public page, always as Markdown",
        "description": "The Markdown twin of a public page regardless of the `Accept` header, following the llms.txt convention of appending `.md`. `index.md` is the home page.",
        "parameters": [
          {
            "$ref": "#/components/parameters/PageSlugWithIndex"
          }
        ],
        "responses": {
          "200": {
            "description": "The page as Markdown.",
            "headers": {
              "Vary": {
                "$ref": "#/components/headers/Vary"
              }
            },
            "content": {
              "text/markdown": {
                "schema": {
                  "$ref": "#/components/schemas/MarkdownDocument"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/blog/{slug}": {
      "get": {
        "operationId": "getBlogPost",
        "tags": [
          "pages"
        ],
        "summary": "A blog post (HTML or Markdown)",
        "description": "A published blog post. Slugs are listed in llms.txt and in the sitemap; a draft or future-dated post answers 404. Content negotiation per acceptmarkdown.com: `Accept` is ranked by q-value and specificity, `q=0` is honored, and `text/markdown` wins when it ranks above `text/html`. Without an `Accept` header, or with `*/*`, the response is HTML. The Markdown body is the same content as the HTML page, without navigation, with absolute links.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BlogSlug"
          }
        ],
        "responses": {
          "200": {
            "description": "The post in the negotiated representation.",
            "headers": {
              "Vary": {
                "$ref": "#/components/headers/Vary"
              }
            },
            "content": {
              "text/markdown": {
                "schema": {
                  "$ref": "#/components/schemas/MarkdownDocument"
                }
              },
              "text/html": {
                "schema": {
                  "$ref": "#/components/schemas/HtmlDocument"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          }
        }
      }
    },
    "/blog/{slug}.md": {
      "get": {
        "operationId": "getBlogPostMarkdown",
        "tags": [
          "pages"
        ],
        "summary": "A blog post, always as Markdown",
        "description": "The Markdown twin of a published blog post regardless of the `Accept` header.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BlogSlug"
          }
        ],
        "responses": {
          "200": {
            "description": "The post as Markdown.",
            "headers": {
              "Vary": {
                "$ref": "#/components/headers/Vary"
              }
            },
            "content": {
              "text/markdown": {
                "schema": {
                  "$ref": "#/components/schemas/MarkdownDocument"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/llms.txt": {
      "get": {
        "operationId": "getLlmsTxt",
        "tags": [
          "discovery"
        ],
        "summary": "llms.txt index for agents",
        "description": "The llmstxt.org index: what the site is, when to use it, and links with notes to every public page and published post. Rebuilt hourly.",
        "responses": {
          "200": {
            "description": "The llms.txt file.",
            "headers": {
              "Vary": {
                "$ref": "#/components/headers/Vary"
              }
            },
            "content": {
              "text/markdown": {
                "schema": {
                  "$ref": "#/components/schemas/MarkdownDocument"
                }
              }
            }
          },
          "4XX": {
            "description": "Client error (for example a method other than GET or HEAD): the HTML error page.",
            "content": {
              "text/html": {
                "schema": {
                  "$ref": "#/components/schemas/HtmlDocument"
                }
              }
            }
          }
        }
      }
    },
    "/llms-full.txt": {
      "get": {
        "operationId": "getLlmsFullTxt",
        "tags": [
          "discovery"
        ],
        "summary": "Every public page in one Markdown file",
        "description": "All public pages and published posts concatenated as Markdown, separated by horizontal rules. Rebuilt hourly.",
        "responses": {
          "200": {
            "description": "The full-text bundle.",
            "headers": {
              "Vary": {
                "$ref": "#/components/headers/Vary"
              }
            },
            "content": {
              "text/markdown": {
                "schema": {
                  "$ref": "#/components/schemas/MarkdownDocument"
                }
              }
            }
          },
          "4XX": {
            "description": "Client error (for example a method other than GET or HEAD): the HTML error page.",
            "content": {
              "text/html": {
                "schema": {
                  "$ref": "#/components/schemas/HtmlDocument"
                }
              }
            }
          }
        }
      }
    },
    "/sitemap.xml": {
      "get": {
        "operationId": "getSitemap",
        "tags": [
          "discovery"
        ],
        "summary": "XML sitemap",
        "description": "Every indexable public URL, including published blog posts. Rebuilt hourly.",
        "responses": {
          "200": {
            "description": "The sitemap.",
            "content": {
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/XmlDocument"
                }
              }
            }
          },
          "4XX": {
            "description": "Client error (for example a method other than GET or HEAD): the HTML error page.",
            "content": {
              "text/html": {
                "schema": {
                  "$ref": "#/components/schemas/HtmlDocument"
                }
              }
            }
          }
        }
      }
    },
    "/robots.txt": {
      "get": {
        "operationId": "getRobotsTxt",
        "tags": [
          "discovery"
        ],
        "summary": "robots.txt",
        "description": "Crawl rules and the sitemap location.",
        "responses": {
          "200": {
            "description": "The robots.txt file.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PlainText"
                }
              }
            }
          },
          "4XX": {
            "description": "Client error (for example a method other than GET or HEAD): the HTML error page.",
            "content": {
              "text/html": {
                "schema": {
                  "$ref": "#/components/schemas/HtmlDocument"
                }
              }
            }
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "operationId": "getOpenApiDocument",
        "tags": [
          "discovery"
        ],
        "summary": "This OpenAPI document",
        "description": "This specification, as JSON (OpenAPI 3.1.0).",
        "responses": {
          "200": {
            "description": "The OpenAPI document.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OpenApiDocument"
                }
              }
            }
          },
          "4XX": {
            "description": "Client error (for example a method other than GET or HEAD): the HTML error page.",
            "content": {
              "text/html": {
                "schema": {
                  "$ref": "#/components/schemas/HtmlDocument"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "parameters": {
      "PageSlug": {
        "name": "page",
        "in": "path",
        "required": true,
        "description": "The public page to read.",
        "schema": {
          "type": "string",
          "enum": [
            "como-jugar",
            "reglamento",
            "preguntas-frecuentes",
            "blog",
            "nosotros",
            "contactanos",
            "terminos",
            "privacidad",
            "desarrolladores"
          ]
        }
      },
      "PageSlugWithIndex": {
        "name": "page",
        "in": "path",
        "required": true,
        "description": "The public page to read; `index` is the home page.",
        "schema": {
          "type": "string",
          "enum": [
            "index",
            "como-jugar",
            "reglamento",
            "preguntas-frecuentes",
            "blog",
            "nosotros",
            "contactanos",
            "terminos",
            "privacidad",
            "desarrolladores"
          ]
        }
      },
      "BlogSlug": {
        "name": "slug",
        "in": "path",
        "required": true,
        "description": "The post slug, as listed in llms.txt (for example `2026-10-05-guia-primera-jornada`).",
        "schema": {
          "type": "string",
          "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"
        }
      }
    },
    "headers": {
      "Vary": {
        "description": "Always includes `Accept`: the representation depends on the request header.",
        "schema": {
          "type": "string"
        }
      }
    },
    "schemas": {
      "MarkdownDocument": {
        "type": "string",
        "contentMediaType": "text/markdown",
        "description": "A Markdown document: an H1 title, the page content with absolute links, and a final line naming the page URL."
      },
      "HtmlDocument": {
        "type": "string",
        "contentMediaType": "text/html",
        "description": "The HTML page, as a browser receives it."
      },
      "NotFoundMarkdown": {
        "type": "string",
        "contentMediaType": "text/markdown",
        "description": "A Markdown explanation of the miss with links to the home page, llms.txt and the sitemap."
      },
      "NotAcceptable": {
        "type": "string",
        "contentMediaType": "text/plain",
        "description": "A plain-text body listing the representations available for the URL."
      },
      "XmlDocument": {
        "type": "string",
        "contentMediaType": "application/xml"
      },
      "PlainText": {
        "type": "string",
        "contentMediaType": "text/plain"
      },
      "OpenApiDocument": {
        "type": "object",
        "description": "An OpenAPI 3.1 document.",
        "required": [
          "openapi",
          "info",
          "paths"
        ],
        "properties": {
          "openapi": {
            "type": "string",
            "const": "3.1.0"
          },
          "info": {
            "type": "object"
          },
          "paths": {
            "type": "object"
          }
        }
      }
    },
    "responses": {
      "NotFound": {
        "description": "No such page or post. Markdown when the client asked for Markdown, HTML otherwise.",
        "headers": {
          "Vary": {
            "$ref": "#/components/headers/Vary"
          }
        },
        "content": {
          "text/markdown": {
            "schema": {
              "$ref": "#/components/schemas/NotFoundMarkdown"
            }
          },
          "text/html": {
            "schema": {
              "$ref": "#/components/schemas/HtmlDocument"
            }
          }
        }
      },
      "NotAcceptable": {
        "description": "The `Accept` header rejects every representation the URL can produce.",
        "headers": {
          "Vary": {
            "$ref": "#/components/headers/Vary"
          }
        },
        "content": {
          "text/plain": {
            "schema": {
              "$ref": "#/components/schemas/NotAcceptable"
            }
          }
        }
      }
    }
  }
}