{
  "openapi": "3.1.0",
  "info": {"title": "LOSGL API", "version": "1.0", "description": "League of Sharpe Gets Last — read-only league data plus a tokened write endpoint for external power rankings and the survivor pool. Agent guide: https://losgl.thebatcave.cloud/api/llms.txt"},
  "servers": [{"url": "https://losgl.thebatcave.cloud/api/v1"}],
  "components": {
    "securitySchemes": {"bearer": {"type": "http", "scheme": "bearer"}},
    "schemas": {
      "RankingSubmission": {"type": "object", "required": ["year", "week", "entries"], "properties": {
        "year": {"type": "integer"}, "week": {"type": "integer", "minimum": 1, "maximum": 25}, "title": {"type": "string", "maxLength": 2000}, "intro": {"type": "string", "maxLength": 2000},
        "entries": {"type": "array", "items": {"type": "object", "required": ["season_team_id", "rank"], "properties": {"season_team_id": {"type": "integer"}, "rank": {"type": "integer", "minimum": 1}, "comment": {"type": "string", "maxLength": 1200}}}}}},
      "SurvivorPick": {"oneOf": [{"type": "string", "description": "NFL team code"}, {"type": "object", "properties": {"team": {"type": ["string", "null"]}, "result": {"type": "string", "enum": ["win", "loss", "pending", "push", "none"]}}}]},
      "SurvivorSubmission": {"type": "object", "required": ["year", "participants"], "properties": {
        "year": {"type": "integer"}, "title": {"type": "string", "maxLength": 120}, "notes": {"type": "string", "maxLength": 4000}, "weeks_played": {"type": "integer"},
        "participants": {"type": "array", "maxItems": 200, "items": {"type": "object", "required": ["name"], "properties": {"name": {"type": "string", "maxLength": 40}, "alive": {"type": "boolean"}, "eliminated_week": {"type": ["integer", "null"]}, "picks": {"type": "object", "additionalProperties": {"$ref": "#/components/schemas/SurvivorPick"}}}}}}},
      "Error": {"type": "object", "properties": {"error": {"type": "string"}}}
    }
  },
  "paths": {
    "/published.json": {"get": {"summary": "Last publish time + content hash", "responses": {"200": {"description": "ok"}}}},
    "/site.json": {"get": {"summary": "League meta, seasons list, sync status", "responses": {"200": {"description": "ok"}}}},
    "/seasons/{year}.json": {"get": {"summary": "One season: standings, weekly tickets, playoffs, draft, draft report, outcomes, gaps", "parameters": [{"name": "year", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "ok"}, "404": {"description": "no such season"}}}},
    "/managers.json": {"get": {"summary": "All managers with careers, titles, rivals", "responses": {"200": {"description": "ok"}}}},
    "/franchises.json": {"get": {"summary": "Franchise lineages and ownership", "responses": {"200": {"description": "ok"}}}},
    "/h2h.json": {"get": {"summary": "Head-to-head for every manager and franchise pair", "responses": {"200": {"description": "ok"}}}},
    "/records.json": {"get": {"summary": "Record book with inclusion rules", "responses": {"200": {"description": "ok"}}}},
    "/rankings/{year}.json": {"get": {"summary": "Statistical, commissioner and external power rankings", "parameters": [{"name": "year", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "ok"}}}},
    "/draft/{year}.json": {"get": {"summary": "Draft report card", "parameters": [{"name": "year", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "ok"}}}},
    "/notes.json": {"get": {"summary": "Published commissioner notes", "responses": {"200": {"description": "ok"}}}},
    "/sleepers.json": {"get": {"summary": "Sleepers per season + all-time sleeper-hunter board", "responses": {"200": {"description": "ok"}}}},
    "/transactions/{year}.json": {"get": {"summary": "Waiver / free-agent / trade log with FAAB remaining (current season onward)", "parameters": [{"name": "year", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "ok"}}}},
    "/survivor/{year}.json": {"get": {"summary": "Survivor pool snapshot", "parameters": [{"name": "year", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "ok"}}}},
    "/nfl/schedule/{year}.json": {"get": {"summary": "NFL schedule with kickoffs, scores and lines (ESPN public scoreboard)", "parameters": [{"name": "year", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "ok"}}}},
    "/submit/whoami": {"get": {"summary": "Token check", "security": [{"bearer": []}], "responses": {"200": {"description": "{name, scope, kind}"}, "401": {"description": "bad token"}}}},
    "/submit/teams/{year}": {"get": {"summary": "season_team_ids for a year", "security": [{"bearer": []}], "parameters": [{"name": "year", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "ok"}}}},
    "/submit/rankings": {"post": {"summary": "Publish an external power-ranking edition (replaces same year+week for this token)", "security": [{"bearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/RankingSubmission"}}}}, "responses": {"201": {"description": "stored; public within ~15 min"}, "400": {"description": "malformed"}, "401": {"description": "bad token"}, "403": {"description": "scope"}, "413": {"description": "too large"}, "422": {"description": "validation", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}}}},
    "/submit/survivor": {"post": {"summary": "Replace the survivor snapshot for a season", "security": [{"bearer": []}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SurvivorSubmission"}}}}, "responses": {"201": {"description": "stored; public within ~15 min"}, "422": {"description": "validation", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}}}}
  }
}