{
  "openapi": "3.1.0",
  "info": {
    "title": "whale.ag Public API",
    "version": "1.0.0",
    "description": "Read-only public API for the whale.ag on-chain perpetual aggregator. Returns leaderboards, trader analytics, asset breakdowns and DEX-level views. Free for the basic tier; pay-per-call (x402) for extended endpoints.",
    "termsOfService": "https://whale.ag/terms",
    "contact": { "name": "whale.ag team", "email": "support@whale.ag", "url": "https://whale.ag/contact" },
    "license": { "name": "Proprietary", "url": "https://whale.ag/terms" }
  },
  "servers": [
    { "url": "https://whale.ag/api/public", "description": "Public read-only" },
    { "url": "https://whale.ag/api/paid", "description": "Pay-per-call (x402) extended" }
  ],
  "tags": [
    { "name": "leaderboard", "description": "Cross-DEX trader rankings." },
    { "name": "trader", "description": "Single trader analytics." },
    { "name": "asset", "description": "Per-asset trader views." },
    { "name": "dex", "description": "Per-DEX leaderboards." }
  ],
  "paths": {
    "/leaderboard": {
      "get": {
        "tags": ["leaderboard"],
        "summary": "Top traders ranked by composite copy score",
        "parameters": [
          { "name": "dex", "in": "query", "schema": { "type": "string", "enum": ["all", "hyperliquid", "dydx", "gmx", "vertex", "drift", "aster", "lighter", "pacifica", "jupiter"], "default": "hyperliquid" } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 50, "minimum": 1, "maximum": 50 } },
          { "name": "rankBy", "in": "query", "schema": { "type": "string", "enum": ["copyScore", "sharpe", "drawdown", "winRate", "pnl30d"], "default": "copyScore" } },
          { "name": "format", "in": "query", "schema": { "type": "string", "enum": ["json", "csv"], "default": "json" } }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/LeaderboardResponse" }
              },
              "text/csv": { "schema": { "type": "string" } }
            }
          }
        }
      }
    },
    "/trader/{address}": {
      "get": {
        "tags": ["trader"],
        "summary": "Detailed trader analytics",
        "parameters": [
          { "name": "address", "in": "path", "required": true, "schema": { "type": "string", "pattern": "^0x[a-fA-F0-9]{40}$" } },
          { "name": "windowDays", "in": "query", "schema": { "type": "integer", "enum": [7, 14, 30, 90, 365], "default": 30 } }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TraderResponse" } } }
          },
          "404": { "description": "Trader not found" }
        }
      }
    },
    "/asset/{symbol}": {
      "get": {
        "tags": ["asset"],
        "summary": "Top traders of a specific asset",
        "parameters": [
          { "name": "symbol", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 25, "maximum": 50 } }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeaderboardResponse" } } }
          }
        }
      }
    },
    "/dex/{slug}": {
      "get": {
        "tags": ["dex"],
        "summary": "Top traders on a specific DEX",
        "parameters": [
          { "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 50, "maximum": 50 } }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeaderboardResponse" } } }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "LeaderboardEntry": {
        "type": "object",
        "required": ["address", "rank", "copyScore"],
        "properties": {
          "address": { "type": "string", "pattern": "^0x[a-fA-F0-9]{40}$" },
          "rank": { "type": "integer" },
          "classification": { "type": "string", "enum": ["scalp", "day", "swing", "position"] },
          "accountValueUsd": { "type": "number" },
          "volume14dUsd": { "type": "number" },
          "winRatePct": { "type": "number" },
          "maxDrawdownPct": { "type": "number" },
          "sharpe90d": { "type": "number" },
          "copyScore": { "type": "integer", "minimum": 0, "maximum": 100 },
          "topAssets": { "type": "array", "items": { "type": "string" }, "maxItems": 5 }
        }
      },
      "LeaderboardResponse": {
        "type": "object",
        "required": ["data"],
        "properties": {
          "data": { "type": "array", "items": { "$ref": "#/components/schemas/LeaderboardEntry" } },
          "lastUpdated": { "type": "string", "format": "date-time" },
          "tier": { "type": "string", "enum": ["free", "paid"] }
        }
      },
      "TraderResponse": {
        "type": "object",
        "properties": {
          "address": { "type": "string" },
          "stats": {
            "type": "object",
            "properties": {
              "accountValueUsd": { "type": "number" },
              "sharpe": { "type": "number" },
              "sortino": { "type": "number" },
              "calmar": { "type": "number" },
              "maxDrawdownPct": { "type": "number" },
              "winRatePct": { "type": "number" },
              "fillsCount": { "type": "integer" },
              "avgHoldingHours": { "type": "number" }
            }
          },
          "positions": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "coin": { "type": "string" },
                "side": { "type": "string", "enum": ["LONG", "SHORT"] },
                "notional": { "type": "number" },
                "leverage": { "type": "number" },
                "entryPrice": { "type": "number" },
                "unrealizedPnl": { "type": "number" }
              }
            }
          }
        }
      }
    }
  }
}
