{
  "openapi": "3.1.0",
  "info": {
    "title": "CodeOCE Valorant API",
    "version": "1.0.0",
    "description": "Independent Valorant collection, match history, stats, sessions, live events, and legacy-compatible response routes."
  },
  "servers": [
    { "url": "/", "description": "The centrally operated CodeOCE API" }
  ],
  "security": [{ "CodeOCEApiKey": [] }],
  "tags": [
    { "name": "System" },
    { "name": "Players" },
    { "name": "Sessions" },
    { "name": "Events" },
    { "name": "Operator" },
    { "name": "Legacy compatibility" }
  ],
  "paths": {
    "/health": {
      "get": {
        "tags": ["System"],
        "summary": "Check server health",
        "operationId": "getHealth",
        "security": [],
        "responses": { "200": { "description": "Server is running" } }
      }
    },
    "/api/status": {
      "get": {
        "tags": ["System"],
        "summary": "Inspect providers and runtime budget",
        "operationId": "getStatus",
        "security": [],
        "responses": { "200": { "description": "Runtime status" } }
      }
    },
    "/api/players": {
      "get": {
        "tags": ["Players"],
        "summary": "List tracked players",
        "operationId": "listPlayers",
        "security": [{ "OperatorKey": [] }],
        "responses": { "200": { "description": "Player states" } }
      },
      "post": {
        "tags": ["Players"],
        "summary": "Track a Riot ID",
        "operationId": "trackPlayer",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "type": "object", "required": ["riotId"], "properties": { "riotId": { "type": "string" }, "region": { "type": "string" } } },
              "example": { "riotId": "Nick#OCE", "region": "eu" }
            }
          }
        },
        "responses": { "200": { "description": "Tracked player state" }, "400": { "description": "Invalid Riot ID" } }
      }
    },
    "/api/players/{id}": {
      "parameters": [
        { "name": "id", "in": "path", "required": true, "description": "PUUID or Riot ID", "schema": { "type": "string" }, "example": "Nick#OCE" }
      ],
      "get": {
        "tags": ["Players"],
        "summary": "Get rank, session, lifetime, and last match",
        "operationId": "getPlayer",
        "responses": { "200": { "description": "Complete player state" }, "404": { "description": "Player is not stored" } }
      },
      "delete": {
        "tags": ["Players"],
        "summary": "Stop tracking a player",
        "operationId": "untrackPlayer",
        "security": [{ "OperatorKey": [] }],
        "parameters": [
          { "name": "purge", "in": "query", "required": false, "description": "Also remove stored history", "schema": { "type": "boolean" }, "example": false }
        ],
        "responses": { "200": { "description": "Player is no longer tracked" } }
      }
    },
    "/api/players/{id}/refresh": {
      "post": {
        "tags": ["Players"],
        "summary": "Force an upstream sync",
        "operationId": "refreshPlayer",
        "security": [{ "OperatorKey": [] }],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "example": "Nick#OCE" }
        ],
        "responses": { "200": { "description": "Fresh player state" } }
      }
    },
    "/api/players/{id}/matches": {
      "get": {
        "tags": ["Players"],
        "summary": "Read stored matches",
        "operationId": "getMatches",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "example": "Nick#OCE" },
          { "name": "limit", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 1, "maximum": 200 }, "example": 10 },
          { "name": "mode", "in": "query", "required": false, "schema": { "type": "string" }, "example": "competitive" }
        ],
        "responses": { "200": { "description": "Stored matches" } }
      }
    },
    "/api/players/{id}/stats": {
      "get": {
        "tags": ["Players"],
        "summary": "Calculate match statistics",
        "operationId": "getStats",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "example": "Nick#OCE" },
          { "name": "recent", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 1, "maximum": 50 }, "example": 10 },
          { "name": "mode", "in": "query", "required": false, "schema": { "type": "string" }, "example": "competitive" }
        ],
        "responses": { "200": { "description": "Calculated statistics" } }
      }
    },
    "/api/players/{id}/breakdown": {
      "get": {
        "tags": ["Players"],
        "summary": "Break stats down by map or agent",
        "operationId": "getBreakdown",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "example": "Nick#OCE" },
          { "name": "by", "in": "query", "required": false, "schema": { "type": "string", "enum": ["map", "agent"] }, "example": "map" }
        ],
        "responses": { "200": { "description": "Grouped statistics" } }
      }
    },
    "/api/players/{id}/rank-history": {
      "get": {
        "tags": ["Players"],
        "summary": "Read stored rank points",
        "operationId": "getRankHistory",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "example": "Nick#OCE" },
          { "name": "limit", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 1, "maximum": 1000 }, "example": 20 }
        ],
        "responses": { "200": { "description": "Rank history" } }
      }
    },
    "/api/players/{id}/sessions": {
      "get": {
        "tags": ["Sessions"],
        "summary": "List session boundaries",
        "operationId": "listSessions",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "example": "Nick#OCE" }
        ],
        "responses": { "200": { "description": "Player sessions" } }
      }
    },
    "/api/players/{id}/session": {
      "parameters": [
        { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "example": "Nick#OCE" }
      ],
      "get": {
        "tags": ["Sessions"],
        "summary": "Get the current session",
        "operationId": "getSession",
        "responses": { "200": { "description": "Current session" } }
      },
      "post": {
        "tags": ["Sessions"],
        "summary": "Start a new session boundary",
        "operationId": "startSession",
        "security": [{ "OperatorKey": [] }],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": { "type": "object", "properties": { "label": { "type": ["string", "null"] } } },
              "example": { "label": "Wednesday ranked" }
            }
          }
        },
        "responses": { "200": { "description": "New session" } }
      },
      "delete": {
        "tags": ["Sessions"],
        "summary": "End the current session",
        "operationId": "endSession",
        "security": [{ "OperatorKey": [] }],
        "responses": { "200": { "description": "Session ended" } }
      }
    },
    "/api/events": {
      "get": {
        "tags": ["Events"],
        "summary": "Read the persisted event log",
        "operationId": "getEvents",
        "security": [{ "OperatorKey": [] }],
        "parameters": [
          { "name": "limit", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 1, "maximum": 500 }, "example": 20 },
          { "name": "player", "in": "query", "required": false, "schema": { "type": "string" }, "example": "Nick#OCE" }
        ],
        "responses": { "200": { "description": "Persisted events" } }
      }
    },
    "/admin/keys": {
      "get": {
        "tags": ["Operator"],
        "summary": "List issued consumer keys",
        "operationId": "listApiKeys",
        "security": [{ "OperatorKey": [] }],
        "responses": { "200": { "description": "API keys without plaintext secrets" } }
      },
      "post": {
        "tags": ["Operator"],
        "summary": "Issue a consumer key",
        "operationId": "createApiKey",
        "security": [{ "OperatorKey": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "type": "object", "required": ["name"], "properties": { "name": { "type": "string" }, "rateLimit": { "type": "integer" } } },
              "example": { "name": "Customer app", "rateLimit": 30 }
            }
          }
        },
        "responses": { "200": { "description": "New key; plaintext is returned once" } }
      }
    },
    "/admin/keys/{id}": {
      "delete": {
        "tags": ["Operator"],
        "summary": "Revoke a consumer key",
        "operationId": "revokeApiKey",
        "security": [{ "OperatorKey": [] }],
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": { "200": { "description": "Key revoked" } }
      }
    },
    "/valorant/v1/account/{name}/{tag}": {
      "get": {
        "tags": ["Legacy compatibility"],
        "summary": "Get account in the legacy v1 shape",
        "operationId": "getCompatAccount",
        "parameters": [
          { "name": "name", "in": "path", "required": true, "schema": { "type": "string" }, "example": "Nick" },
          { "name": "tag", "in": "path", "required": true, "schema": { "type": "string" }, "example": "OCE" }
        ],
        "responses": { "200": { "description": "Legacy-compatible account response" } }
      }
    },
    "/valorant/v3/mmr/{affinity}/{platform}/{name}/{tag}": {
      "get": {
        "tags": ["Legacy compatibility"],
        "summary": "Get current MMR in the legacy v3 shape",
        "operationId": "getCompatMmr",
        "parameters": [
          { "name": "affinity", "in": "path", "required": true, "schema": { "type": "string" }, "example": "eu" },
          { "name": "platform", "in": "path", "required": true, "schema": { "type": "string" }, "example": "pc" },
          { "name": "name", "in": "path", "required": true, "schema": { "type": "string" }, "example": "Nick" },
          { "name": "tag", "in": "path", "required": true, "schema": { "type": "string" }, "example": "OCE" }
        ],
        "responses": { "200": { "description": "Legacy-compatible MMR response" } }
      }
    },
    "/valorant/v1/stored-matches/{affinity}/{name}/{tag}": {
      "get": {
        "tags": ["Legacy compatibility"],
        "summary": "Get stored matches in the legacy shape",
        "operationId": "getCompatStoredMatches",
        "parameters": [
          { "name": "affinity", "in": "path", "required": true, "schema": { "type": "string" }, "example": "eu" },
          { "name": "name", "in": "path", "required": true, "schema": { "type": "string" }, "example": "Nick" },
          { "name": "tag", "in": "path", "required": true, "schema": { "type": "string" }, "example": "OCE" },
          { "name": "size", "in": "query", "required": false, "schema": { "type": "integer" }, "example": 10 },
          { "name": "mode", "in": "query", "required": false, "schema": { "type": "string" }, "example": "competitive" }
        ],
        "responses": { "200": { "description": "Legacy-compatible stored matches" } }
      }
    },
    "/valorant/v2/stored-mmr-history/{affinity}/{platform}/{name}/{tag}": {
      "get": {
        "tags": ["Legacy compatibility"],
        "summary": "Get stored MMR history in the legacy v2 shape",
        "operationId": "getCompatStoredMmr",
        "parameters": [
          { "name": "affinity", "in": "path", "required": true, "schema": { "type": "string" }, "example": "eu" },
          { "name": "platform", "in": "path", "required": true, "schema": { "type": "string" }, "example": "pc" },
          { "name": "name", "in": "path", "required": true, "schema": { "type": "string" }, "example": "Nick" },
          { "name": "tag", "in": "path", "required": true, "schema": { "type": "string" }, "example": "OCE" }
        ],
        "responses": { "200": { "description": "Legacy-compatible stored MMR history" } }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "CodeOCEApiKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "coce_live_...",
        "description": "Consumer key issued by CodeOCE"
      },
      "OperatorKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Admin-Key",
        "description": "Private operator secret; never give this to customers"
      }
    }
  },
  "x-websocket": {
    "url": "/ws?player=Nick%23OCE",
    "events": ["MATCH_STARTED", "MATCH_FINISHED", "RANK_CHANGED", "RR_CHANGED", "SESSION_UPDATED", "PLAYER_UPDATED", "SYNC_ERROR"]
  }
}
