{
  "openapi": "3.1.0",
  "info": {
    "title": "Decibel Trading API",
    "description": "RESTful API for Decibel. Provides read-only endpoints for market data, trading operations, positions, and analytics.",
    "contact": {
      "name": "Decibel Team",
      "url": "https://decibel.trade/"
    },
    "license": {
      "name": ""
    },
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://api.mainnet.aptoslabs.com/decibel",
      "description": "Mainnet"
    },
    {
      "url": "https://api.testnet.aptoslabs.com/decibel",
      "description": "Testnet"
    }
  ],
  "paths": {
    "/api/v1/account_fund_history": {
      "get": {
        "tags": [
          "User"
        ],
        "summary": "Get user fund history (deposits and withdrawals)",
        "description": "Retrieve deposit and withdrawal history for a specific user.\nReturns chronological list of fund movements with amounts and timestamps.\nSupports filtering by timestamp range, sorting by timestamp, and pagination. Page size is capped at 200.",
        "operationId": "handle_account_fund_history",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "description": "User account address (`user` query alias is also accepted)",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 10,
              "maximum": 200,
              "minimum": 0
            },
            "example": 100
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Page offset",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0,
              "maximum": 10000,
              "minimum": 0
            },
            "example": 0
          },
          {
            "name": "start_timestamp",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "end_timestamp",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "sort_key",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/HistorySortKey"
            }
          },
          {
            "name": "sort_dir",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/SortDir"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Fund history retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserFundHistoryResponse"
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/account_overviews": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Get account overview",
        "description": "Retrieve comprehensive perp account information including equity,\nrealized/unrealized PnL, margin utilization, and optional performance metrics.\nUse `include_performance=true` to get historical return metrics.",
        "operationId": "handle_account_overview",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "description": "User account address (`user` query alias is also accepted)",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0x123..."
          },
          {
            "name": "volume_window",
            "in": "query",
            "description": "Volume time window (e.g., \"7d\", \"14d\", \"30d\", \"90d\"). Omit to exclude volume data.",
            "required": false,
            "schema": {
              "type": "string",
              "description": "Time window for volume queries",
              "enum": [
                "7d",
                "14d",
                "30d",
                "90d"
              ]
            },
            "example": "30d"
          },
          {
            "name": "include_performance",
            "in": "query",
            "description": "Include performance metrics",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            },
            "example": false
          },
          {
            "name": "performance_lookback_days",
            "in": "query",
            "description": "Performance lookback window in days.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 90,
              "minimum": 0
            },
            "example": 90
          }
        ],
        "responses": {
          "200": {
            "description": "Account overview retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountOverviewDto"
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/account_owned_vaults": {
      "get": {
        "tags": [
          "Vaults"
        ],
        "summary": "Get account-owned vaults",
        "description": "Retrieve paginated list of vaults owned by a specific account.\nIncludes vault performance metrics, AUM, and depositor count.",
        "operationId": "handle_account_owned_vaults",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "description": "Account address (`user` query alias is also accepted)",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 10,
              "maximum": 1000,
              "minimum": 0
            },
            "example": 100
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Page offset",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0,
              "maximum": 10000,
              "minimum": 0
            },
            "example": 0
          }
        ],
        "responses": {
          "200": {
            "description": "Account-owned vaults retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_VaultDto"
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/account_positions": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Get account positions",
        "description": "Retrieve all open perp positions for a specific account with optional filtering\nby one perp market address.\nIncludes position size, entry price, unrealized PnL, liquidation price, and margin details.",
        "operationId": "handle_account_positions",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "description": "Account address (`user` query alias is also accepted)",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0x123..."
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of positions to return",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 500,
              "minimum": 0
            },
            "example": 10
          },
          {
            "name": "include_deleted",
            "in": "query",
            "description": "Include deleted positions",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "example": false
          },
          {
            "name": "market_address",
            "in": "query",
            "description": "Filter by one perp market address",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "0xmarket123..."
          }
        ],
        "responses": {
          "200": {
            "description": "Account positions retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PositionDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/account_vault_performance": {
      "get": {
        "tags": [
          "Vaults"
        ],
        "summary": "Get account vault performance for all vaults where account has deposits",
        "description": "Retrieve performance metrics for all vaults where the account has deposits, including net deposits, current value, returns, and PnL.\nResults are ordered by net deposits (descending) and support pagination.",
        "operationId": "handle_account_vault_performance",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "description": "Account address",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0xaccount123..."
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of results to skip (for pagination)",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64",
              "default": 0,
              "maximum": 10000,
              "minimum": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of results to return",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64",
              "default": 20,
              "maximum": 1000,
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Account vault performance retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AccountVaultPerformanceDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/account_volume": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Get aggregate account volume over a date range",
        "description": "Returns the account's total, maker, and taker volume (in whole USD) for the requested\ninclusive date range. When `start_date` and `end_date` are omitted the range defaults\nto the past 30 days (today() - 29 .. today(), UTC).\n\nBoth `start_date` and `end_date` must be supplied together (YYYY-MM-DD format).\nVolume data has up to 5-minute delay (MV refresh interval).",
        "operationId": "handle_account_volume",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "description": "User account address",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "start_date",
            "in": "query",
            "description": "Optional inclusive start date (YYYY-MM-DD, UTC).\nMust be provided together with `end_date`.\nDefaults to today() - 29 (UTC) when both are omitted.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "end_date",
            "in": "query",
            "description": "Optional inclusive end date (YYYY-MM-DD, UTC).\nMust be provided together with `start_date`.\nDefaults to today (UTC) when both are omitted.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Account volume retrieved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountVolumeDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid account address or date parameters"
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/active_twaps": {
      "get": {
        "tags": [
          "TWAP"
        ],
        "summary": "Get active TWAP orders",
        "description": "Retrieve currently active TWAP (time-weighted average price) orders for a specific user.\nShows orders that have remaining size to be executed.",
        "operationId": "handle_active_twaps",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "description": "User account address (`user` query alias is also accepted)",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0x123..."
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of active TWAPs to return",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 10,
              "minimum": 0
            },
            "example": 10
          }
        ],
        "responses": {
          "200": {
            "description": "Active TWAPs retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/TwapDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/affiliates/codes/{account}": {
      "get": {
        "tags": [
          "Affiliates"
        ],
        "summary": "GET /api/v1/affiliates/codes/{account}",
        "description": "Returns referral codes owned by an account with per-code usage stats.\nAffiliate codes (is_affiliate = true) are always returned.\nNon-affiliate codes are only returned if the account has >= $1,000\nall-time trade volume. Maps to the Affiliates dashboard.",
        "operationId": "handle_get_affiliate_codes",
        "parameters": [
          {
            "name": "account",
            "in": "path",
            "description": "The owner's wallet address (not a subaccount address)",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Affiliate codes with usage stats",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AffiliateCodesResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid account address"
          },
          "500": {
            "description": "Internal server error"
          }
        }
      }
    },
    "/api/v1/affiliates/codes/{account}/analytics": {
      "get": {
        "tags": [
          "Affiliates"
        ],
        "summary": "GET /api/v1/affiliates/codes/{account}/analytics",
        "description": "Internal only: requires the API Gateway `x-aptos-identifier` header to match an allowlisted application ID. Returns 403 otherwise.",
        "operationId": "handle_get_affiliate_code_analytics",
        "parameters": [
          {
            "name": "account",
            "in": "path",
            "description": "The owner's wallet address (not a subaccount address)",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Per-code L1 analytics",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AffiliateCodeAnalyticsResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid account address"
          },
          "403": {
            "description": "Caller is not an allowlisted internal service"
          },
          "500": {
            "description": "Internal server error"
          }
        }
      }
    },
    "/api/v1/affiliates/earnings/{account}": {
      "get": {
        "tags": [
          "Affiliates"
        ],
        "summary": "GET /api/v1/affiliates/earnings/{account}\nReturns affiliate earnings breakdown for an account, including per-user\nreferral amps earned at L1 (10%/15%) and L2 (5%) rates.",
        "operationId": "handle_get_affiliate_earnings",
        "parameters": [
          {
            "name": "account",
            "in": "path",
            "description": "The affiliate's wallet address",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 10,
              "maximum": 1000,
              "minimum": 0
            },
            "example": 100
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Page offset",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0,
              "maximum": 10000,
              "minimum": 0
            },
            "example": 0
          }
        ],
        "responses": {
          "200": {
            "description": "Affiliate earnings breakdown",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AffiliateEarningsResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid account address"
          },
          "500": {
            "description": "Internal server error"
          }
        }
      }
    },
    "/api/v1/asset_contexts": {
      "get": {
        "tags": [
          "Market Data"
        ],
        "summary": "Get asset contexts",
        "description": "Retrieve perp market contexts including current prices, 24h volume,\n24h price change, funding rates, and open interest for all perp markets or\none perp market address.",
        "operationId": "handle_asset_context",
        "parameters": [
          {
            "name": "market",
            "in": "query",
            "description": "Filter by one perp market address",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "0xmarket123..."
          }
        ],
        "responses": {
          "200": {
            "description": "Asset context retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AssetContextDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/bulk_order_fills": {
      "get": {
        "tags": [
          "Bulk Orders"
        ],
        "summary": "Get bulk order fills",
        "description": "Retrieve fills for bulk orders with optional filtering by one concrete market, sequence\nnumber, or range. By default returns both perp and spot fills together\n(each row tagged with `asset_type`); set `?asset_type=perp|spot` to filter.",
        "operationId": "handle_bulk_order_fills",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "description": "User account address (`user` query alias is also accepted)",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "market",
            "in": "query",
            "description": "Filter by one concrete market address. Use `all` to disable market filtering.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sequence_number",
            "in": "query",
            "description": "Single sequence number to query.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 0
            }
          },
          {
            "name": "start_sequence_number",
            "in": "query",
            "description": "Start of sequence number range.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 0
            }
          },
          {
            "name": "end_sequence_number",
            "in": "query",
            "description": "End of sequence number range.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 0
            }
          },
          {
            "name": "asset_type",
            "in": "query",
            "description": "Optional asset_type filter: `\"perp\"` | `\"spot\"`.",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/AssetType"
            },
            "example": "perp"
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Effective page size (clamped to 1..=1000 at runtime)",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 10,
              "maximum": 1000,
              "minimum": 1
            },
            "example": 100
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Page offset",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0,
              "maximum": 10000,
              "minimum": 0
            },
            "example": 0
          }
        ],
        "responses": {
          "200": {
            "description": "Bulk order fills retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/BulkOrderFillDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/bulk_order_status": {
      "get": {
        "tags": [
          "Bulk Orders"
        ],
        "summary": "Get bulk order status",
        "description": "Retrieve the status of a specific bulk order (placed or rejected). Use\n`?asset_type=spot` to query the spot bulk-order tables; defaults to perp.\nThe `market` parameter is one concrete market address, not a base-asset group.",
        "operationId": "handle_bulk_order_status",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "description": "User account address (`user` query alias is also accepted)",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0x123..."
          },
          {
            "name": "market",
            "in": "query",
            "description": "Concrete market address. Spot and perp markets with the same base asset\nhave different addresses.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0xmarket123..."
          },
          {
            "name": "sequence_number",
            "in": "query",
            "description": "Sequence number of the bulk order",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 0
            },
            "example": 12345
          },
          {
            "name": "asset_type",
            "in": "query",
            "description": "Asset type discriminator. Defaults to `\"perp\"` when omitted so the\nendpoint preserves prior behaviour for perp callers; pass `\"spot\"` to\nquery the spot tables instead. (Bulk-order status is keyed by\n(account, market, sequence_number) — those keys are independent\nacross products, so a single call cannot meaningfully UNION both.)",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/AssetType"
            },
            "example": "perp"
          }
        ],
        "responses": {
          "200": {
            "description": "Bulk order status retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkOrderStatusResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/bulk_orders": {
      "get": {
        "tags": [
          "Bulk Orders"
        ],
        "summary": "Get bulk orders",
        "description": "Retrieve the latest bulk orders for a specific user with optional filtering by\none concrete market address.\nReturns one bulk order per market (perp + spot together by default) with the\ncurrent bid/ask levels and fills applied. Each row carries an `asset_type`\ndiscriminator (`\"perp\"` or `\"spot\"`) and the request may optionally filter\nto a single product via `?asset_type=perp|spot`.",
        "operationId": "handle_bulk_orders",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "description": "User account address (`user` query alias is also accepted)",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "market",
            "in": "query",
            "description": "Filter by one concrete market address. Use `all` to disable market filtering.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "asset_type",
            "in": "query",
            "description": "Optional asset_type filter: `\"perp\"` | `\"spot\"`. Omit to UNION both.",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/AssetType"
            },
            "example": "perp"
          }
        ],
        "responses": {
          "200": {
            "description": "Bulk orders retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/BulkOrderDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/campaign_locks": {
      "get": {
        "tags": [
          "Campaigns"
        ],
        "summary": "Get account's campaign locks",
        "description": "Returns the latest state of each FFT campaign lock for the account,\nsorted by lock time descending. Optionally filtered by campaign and status.",
        "operationId": "handle_campaign_locks",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "description": "User account address (`user` query alias is also accepted)",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "campaign_addr",
            "in": "query",
            "description": "Optional campaign address filter",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Optional status filter (Active, Claimed)",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/LockStatus"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 10,
              "maximum": 200,
              "minimum": 0
            },
            "example": 100
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Page offset",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0,
              "maximum": 10000,
              "minimum": 0
            },
            "example": 0
          }
        ],
        "responses": {
          "200": {
            "description": "Campaign locks retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CampaignLocksResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid address"
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/campaigns/account": {
      "get": {
        "tags": [
          "Campaigns"
        ],
        "summary": "Aggregates sum over all campaigns; `claims` is paged by `limit` / `offset`.",
        "operationId": "handle_account",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "description": "User wallet address. `user=` is accepted as an alias for parity with sibling endpoints.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0xb8a5788314451ce4d2fbbad32e1bad88d4184b73943b7fe5166eab93cf1a5a95"
          },
          {
            "name": "pagination",
            "in": "query",
            "required": true,
            "schema": {
              "type": "object",
              "properties": {
                "limit": {
                  "type": "integer",
                  "format": "int32",
                  "description": "Maximum number of items to return per page (capped at 1000)",
                  "maximum": 1000,
                  "minimum": 0
                },
                "offset": {
                  "type": "integer",
                  "format": "int32",
                  "description": "Number of items to skip before returning results (capped at 10000)",
                  "maximum": 10000,
                  "minimum": 0
                }
              }
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 10,
              "maximum": 200,
              "minimum": 0
            },
            "example": 100
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0,
              "maximum": 10000,
              "minimum": 0
            },
            "example": 0
          }
        ],
        "responses": {
          "200": {
            "description": "Per-user campaign state",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserCampaigns"
                }
              }
            }
          },
          "400": {
            "description": "Invalid address"
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/campaigns/active": {
      "get": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "handle_active",
        "responses": {
          "200": {
            "description": "Active campaigns",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CampaignMetadata"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/candlesticks": {
      "get": {
        "tags": [
          "Market Data"
        ],
        "summary": "Get candlestick (OHLC) data",
        "description": "Retrieve perp candlestick data for one perp market address and time range.\nSpot candlesticks are available from the `market_candlestick:{marketAddr}:{interval}`\nWebSocket topic; spot and perp markets with the same base asset have different\nmarket addresses and must be requested separately.\nSupports intervals: 1m, 15m, 1h, 4h, 1d. Missing intervals are interpolated using the last known close price.\nMaximum 1000 candles per request.\n\nOptionally set `filterWicks=true` to suppress extreme H/L wicks caused by liquidation\ncascades or low-liquidity outlier fills. The filter computes a cross-candle\nvolume-weighted typical price and standard deviation, then clamps each candle's\nhigh and low to `[VWAP ± nSigma × σ_v]` without touching open or close.",
        "operationId": "handle_candlestick_snapshot",
        "parameters": [
          {
            "name": "market",
            "in": "query",
            "description": "Market address",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0xmarket123..."
          },
          {
            "name": "interval",
            "in": "query",
            "description": "Candlestick interval (1m, 5m, 15m, 30m, 1h, 2h, 4h, 1d, 1w, 1mo)",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/Interval"
            },
            "example": "1h"
          },
          {
            "name": "startTime",
            "in": "query",
            "description": "Start time in milliseconds",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 1634567890000
          },
          {
            "name": "endTime",
            "in": "query",
            "description": "End time in milliseconds",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 1634654290000
          },
          {
            "name": "filterWicks",
            "in": "query",
            "description": "When true, caps extreme H/L wicks using cross-candle volume-weighted standard deviation.\nFor each candle, H and L are clamped to [VWAP ± nSigma × σ_v] while preserving\nthe candle body (open/close). No extra database queries are required.",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "example": false
          },
          {
            "name": "nSigma",
            "in": "query",
            "description": "Number of volume-weighted standard deviations used as the wick-filter band (default: 3.0).\nOnly applies when filterWicks is true.",
            "required": false,
            "schema": {
              "type": "number",
              "format": "double"
            },
            "example": 3.0
          }
        ],
        "responses": {
          "200": {
            "description": "Candlestick data retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CandlestickResponseItemDto"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters (e.g., start_time > end_time or exceeds max candles)"
          },
          "404": {
            "description": "Market not found"
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/contract_specs": {
      "get": {
        "tags": [
          "Market Data"
        ],
        "summary": "Get contract specifications",
        "description": "Returns contract specifications for all perpetual contracts,\nper the CoinGecko/CMC derivatives endpoint spec.",
        "operationId": "handle_contract_specs",
        "responses": {
          "200": {
            "description": "Contract specifications",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContractSpecsResponse"
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/contracts": {
      "get": {
        "tags": [
          "Market Data"
        ],
        "summary": "Get contracts summary",
        "description": "Returns a summary of all perpetual contracts traded on the exchange,",
        "operationId": "handle_contracts",
        "responses": {
          "200": {
            "description": "Contracts summary",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContractsResponse"
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/daily_stats": {
      "get": {
        "tags": [
          "Analytics"
        ],
        "summary": "Get daily stats",
        "description": "Returns perp daily volume, fees, revenue, and open interest for a given time range.\nDesigned for DefiLlama integration.",
        "operationId": "handle_daily_stats",
        "parameters": [
          {
            "name": "start_timestamp",
            "in": "query",
            "description": "Start of the time range (UNIX seconds)",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 0
            }
          },
          {
            "name": "end_timestamp",
            "in": "query",
            "description": "End of the time range (UNIX seconds)",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Daily stats retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DailyStatsDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters"
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/delegations": {
      "get": {
        "tags": [
          "User"
        ],
        "summary": "Get delegations",
        "description": "Retrieve active delegations for a specific subaccount.\nShows delegated accounts and their associated permissions.",
        "operationId": "handle_delegations",
        "parameters": [
          {
            "name": "subaccount",
            "in": "query",
            "description": "Subaccount address",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0x123..."
          }
        ],
        "responses": {
          "200": {
            "description": "Delegations retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/DelegationDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/dex": {
      "get": {
        "tags": [
          "Market Data"
        ],
        "summary": "Get DEX registration",
        "description": "Retrieve DEX configuration and registration details.",
        "operationId": "handle_dex_registration",
        "responses": {
          "200": {
            "description": "DEX registration retrieved successfully",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/funding_rate_history": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Get user funding rate history",
        "description": "Retrieve perp funding rate payment history for a specific user.\nShows funding payments including the direction, amount, and associated fees.\nSupports filtering by perp market, side, and timestamp range. Supports sorting and pagination. Page size is capped at 200.",
        "operationId": "handle_funding_rate_history",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "description": "User account address (`user` query alias is also accepted)",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "market",
            "in": "query",
            "description": "Filter by market address",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "side",
            "in": "query",
            "description": "Filter by side",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/SideFilter"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 10,
              "maximum": 200,
              "minimum": 0
            },
            "example": 100
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Page offset",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0,
              "maximum": 10000,
              "minimum": 0
            },
            "example": 0
          },
          {
            "name": "start_timestamp",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "end_timestamp",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "sort_key",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/HistorySortKey"
            }
          },
          {
            "name": "sort_dir",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/SortDir"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Funding rate history retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_FundingRateHistory"
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/leaderboard": {
      "get": {
        "tags": [
          "Analytics"
        ],
        "summary": "Get leaderboard",
        "description": "Retrieve the trading leaderboard with rankings based on trading performance metrics.\nResults are paginated and can be sorted by account value, realized PnL, ROI, or trading volume.\nUse the `search_term` parameter to filter accounts by address prefix.",
        "operationId": "handle_leaderboard",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Page size",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 10,
              "maximum": 1000,
              "minimum": 0
            },
            "example": 100
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Page offset",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0,
              "maximum": 10000,
              "minimum": 0
            },
            "example": 0
          },
          {
            "name": "sort_key",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/LeaderboardSortKey"
            }
          },
          {
            "name": "sort_dir",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/SortDir"
            }
          },
          {
            "name": "search_term",
            "in": "query",
            "description": "Optional search term to filter accounts by address prefix",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated leaderboard entries with rankings",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_LeaderboardEntryDto"
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/markets": {
      "get": {
        "tags": [
          "Market Data"
        ],
        "summary": "Get all available markets",
        "description": "Returns a list of all trading markets (perp + spot) with their configuration\ndetails including leverage limits, tick sizes, decimal precision, and\ncurrent market mode (Open, ReduceOnly, CloseOnly). Each row carries an\n`asset_type` discriminator (`\"perp\"` or `\"spot\"`).",
        "operationId": "handle_markets",
        "responses": {
          "200": {
            "description": "List of available markets",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/MarketDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/open_orders": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Get account's open orders",
        "description": "Retrieve all currently open perp and spot orders for a specific account.\nEach order row carries `asset_type`; use `?asset_type=perp|spot` to filter.\nIncludes limit orders, stop orders, and TP/SL orders attached to positions. Supports pagination.",
        "operationId": "handle_open_orders",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "description": "User account address (`user` query alias is also accepted)",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "asset_type",
            "in": "query",
            "description": "Optional asset_type filter (`\"perp\"` | `\"spot\"`). Omit to UNION both.\nEach row carries an `asset_type` field for client-side demux.",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/AssetType"
            },
            "example": "perp"
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 10,
              "maximum": 1000,
              "minimum": 0
            },
            "example": 100
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Page offset",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0,
              "maximum": 10000,
              "minimum": 0
            },
            "example": 0
          }
        ],
        "responses": {
          "200": {
            "description": "Open orders retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_OrderDto"
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/order_history": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Get user order history",
        "description": "Retrieve paginated perp and spot order history for a specific user including\nfilled, cancelled, and expired orders. Supports filtering by one concrete\nmarket address, order type, status, side, reduce-only, and timestamp range.\nSupports sorting by timestamp (default: descending). Page size is capped at 200.",
        "operationId": "handle_account_order_history",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "description": "User account address (`user` query alias is also accepted)",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "asset_type",
            "in": "query",
            "description": "Optional asset_type filter (`\"perp\"` | `\"spot\"`). Omit to UNION both;\neach row carries an `asset_type` field for client-side demux.",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/AssetType"
            },
            "example": "perp"
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 10,
              "maximum": 200,
              "minimum": 0
            },
            "example": 100
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Page offset",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0,
              "maximum": 10000,
              "minimum": 0
            },
            "example": 0
          },
          {
            "name": "start_timestamp",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "end_timestamp",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "sort_key",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/HistorySortKey"
            }
          },
          {
            "name": "sort_dir",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/SortDir"
            }
          },
          {
            "name": "market",
            "in": "query",
            "description": "Filter by one concrete market address.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "order_type",
            "in": "query",
            "description": "Filter by order type",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by order status",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "side",
            "in": "query",
            "description": "Filter by side",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/SideFilter"
            }
          },
          {
            "name": "reduce_only",
            "in": "query",
            "description": "Filter by reduce-only flag (perp-only; ignored for spot rows)",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Order history retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_OrderDto"
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/orderbook": {
      "get": {
        "tags": [
          "Market Data"
        ],
        "summary": "Get orderbook depth",
        "description": "Returns bid/ask depth (50 levels each side) for one concrete market address.\nSupports both perp and spot market addresses; spot and perp markets with the\nsame base asset are different markets with different addresses and are never\ncombined.",
        "operationId": "handle_orderbook",
        "parameters": [
          {
            "name": "market",
            "in": "query",
            "description": "Market address. Spot and perp markets with the same base asset are\nseparate markets with separate addresses.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0x5e0e16f34adfb4b316f8d532d68acbfa206826feaaa418d3938046bdc2044861"
          }
        ],
        "responses": {
          "200": {
            "description": "Orderbook depth",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderbookResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid market address"
          },
          "404": {
            "description": "Market not found"
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/orders": {
      "get": {
        "tags": [
          "User"
        ],
        "description": "Get single order details\n\nRetrieve details of a specific order by order_id (perp + spot) or\nclient_order_id (perp only). The `market` parameter is one concrete market\naddress; spot and perp markets with the same base asset have different\naddresses and are not combined. The response is the perp `OrderUpdate` shape;\nfor spot, the inner `order` DTO carries `asset_type: \"spot\"` and the spot\n`time_in_force` field is populated.",
        "operationId": "handle_order",
        "parameters": [
          {
            "name": "market",
            "in": "query",
            "description": "Concrete market address. Spot and perp markets with the same base asset\nhave different addresses.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0xmarket123..."
          },
          {
            "name": "account",
            "in": "query",
            "description": "Account address",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0x123..."
          },
          {
            "name": "order_id",
            "in": "query",
            "description": "Order ID (provide either this or client_order_id)",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "12345"
          },
          {
            "name": "client_order_id",
            "in": "query",
            "description": "Client order ID (provide either this or order_id). Spot orders do not\nsupport client_order_id — this lookup is perp-only.",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "client_order_abc"
          },
          {
            "name": "asset_type",
            "in": "query",
            "description": "Optional asset_type filter. Omit (default) to look up the order in\nboth perp and spot tables — the first non-empty hit wins. Pass\n`\"perp\"` or `\"spot\"` to scope to one product.",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/AssetType"
            },
            "example": "perp"
          }
        ],
        "responses": {
          "200": {
            "description": "Order details retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderUpdate"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/points/amps": {
      "get": {
        "tags": [
          "Points"
        ],
        "summary": "Get amps breakdown for an owner",
        "description": "Returns total amps with per-category breakdown (trading, streak, referral, vault).\nAll values are sourced from the points leaderboard MV, guaranteeing consistency\nwith the leaderboard rankings.",
        "operationId": "handle_owner_amps",
        "parameters": [
          {
            "name": "owner",
            "in": "query",
            "description": "Owner wallet address",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0xb8a5788314451ce4d2fbbad32e1bad88d4184b73943b7fe5166eab93cf1a5a95"
          }
        ],
        "responses": {
          "200": {
            "description": "Owner amps breakdown",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OwnerAmpsDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid address format"
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/points/amps/daily": {
      "get": {
        "tags": [
          "Points"
        ],
        "summary": "Get per-day Amps for an owner",
        "description": "Returns one row per season day, newest first, split into trading / streak /\nreferral / vault. Excludes `bonus_amps` — there is no per-day source for it.",
        "operationId": "handle_owner_amps_daily",
        "parameters": [
          {
            "name": "owner",
            "in": "query",
            "description": "Owner wallet address (not a subaccount)",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "days",
            "in": "query",
            "description": "Most recent season days to return. Defaults to 14, clamped to 90.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 0
            }
          },
          {
            "name": "season",
            "in": "query",
            "description": "Season name. Defaults to the season containing today.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Per-day amps for an owner",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OwnerAmpsDailyDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid address, unknown season, or no season configured"
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/points/global": {
      "get": {
        "tags": [
          "Analytics"
        ],
        "summary": "Returns the total number of users with points and total amps distributed.",
        "operationId": "handle_global_points_stats",
        "responses": {
          "200": {
            "description": "Global points statistics",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GlobalPointsStatsDto"
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/points/tier": {
      "get": {
        "tags": [
          "Tier"
        ],
        "summary": "Get tier info for a user based on percentile-based thresholds",
        "operationId": "handle_tier_info",
        "parameters": [
          {
            "name": "owner",
            "in": "query",
            "description": "Owner wallet address",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0xb8a5788314451ce4d2fbbad32e1bad88d4184b73943b7fe5166eab93cf1a5a95"
          }
        ],
        "responses": {
          "200": {
            "description": "Tier info with progress",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TierInfoDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid address format"
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/points/trading/account": {
      "get": {
        "tags": [
          "Trading Points"
        ],
        "summary": "Get aggregated trading points for an owner across all their active subaccounts\nReturns total points and per-subaccount breakdown",
        "operationId": "handle_owner_trading_points",
        "parameters": [
          {
            "name": "owner",
            "in": "query",
            "description": "Owner wallet address. Used to look up all subaccounts owned by this address\nand aggregate their trading points.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0xb8a5788314451ce4d2fbbad32e1bad88d4184b73943b7fe5166eab93cf1a5a95"
          }
        ],
        "responses": {
          "200": {
            "description": "Owner trading points with breakdown",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OwnerTradingPoints"
                }
              }
            }
          },
          "400": {
            "description": "Invalid address format"
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/points/trading/amps": {
      "get": {
        "tags": [
          "Trading Hz"
        ],
        "summary": "Get aggregated trading Hz for an owner across all their subaccounts",
        "operationId": "handle_owner_trading_hz",
        "parameters": [
          {
            "name": "owner",
            "in": "query",
            "description": "Owner wallet address",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0xb8a5788314451ce4d2fbbad32e1bad88d4184b73943b7fe5166eab93cf1a5a95"
          },
          {
            "name": "season",
            "in": "query",
            "description": "Optional season name to filter by (e.g. \"season1\"). Omit to aggregate across all seasons.",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "season1"
          },
          {
            "name": "days",
            "in": "query",
            "description": "Number of days to look back. 1 = today only, 7 = last week, etc. Omit for lifetime totals.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 0
            },
            "example": "1"
          }
        ],
        "responses": {
          "200": {
            "description": "Owner trading Hz with breakdown",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OwnerTradingHz"
                }
              }
            }
          },
          "400": {
            "description": "Invalid address format or season not configured"
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/points_leaderboard": {
      "get": {
        "tags": [
          "Analytics"
        ],
        "summary": "Get points leaderboard",
        "description": "Retrieve the Hz/Amps points leaderboard with rankings by total Hz or realized PnL.\nResults are paginated and can be sorted by total_amps or realized_pnl.\nUse the `search_term` parameter to filter by owner address prefix.",
        "operationId": "handle_points_leaderboard",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Page size",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 10,
              "maximum": 1000,
              "minimum": 0
            },
            "example": 100
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Page offset",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0,
              "maximum": 10000,
              "minimum": 0
            },
            "example": 0
          },
          {
            "name": "sort_key",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/PointsLeaderboardSortKey"
            }
          },
          {
            "name": "sort_dir",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/SortDir"
            }
          },
          {
            "name": "search_term",
            "in": "query",
            "description": "Optional search term to filter by owner address prefix",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tier",
            "in": "query",
            "description": "Optional tier filter",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/PointsLeaderboardTier"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated points leaderboard entries with rankings",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_PointsLeaderboardEntryDto"
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/portfolio_chart": {
      "get": {
        "tags": [
          "Analytics"
        ],
        "summary": "Get portfolio chart data",
        "description": "Returns time series data for PnL or account value over specified time range.\nPnL = Cumulative Realized PnL from completed trades.\nAccount Value = Initial Deposits - Withdrawals + Realized PnL (excludes unrealized PnL).",
        "operationId": "handle_portfolio_chart",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "description": "User account address (`user` query alias is also accepted)",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0x123..."
          },
          {
            "name": "range",
            "in": "query",
            "description": "Time range for chart data",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/TimeRange"
            }
          },
          {
            "name": "data_type",
            "in": "query",
            "description": "Data type: pnl or account_value",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/PortfolioChartDataType"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Portfolio chart data retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PortfolioPointDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/predeposits/rewards": {
      "get": {
        "tags": [
          "Predeposit Rewards"
        ],
        "summary": "Get S0 predeposit USDC reward for a user",
        "operationId": "handle_predeposit_rewards",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "description": "Account address (`user` query alias is also accepted)",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0xb8a5788314451ce4d2fbbad32e1bad88d4184b73943b7fe5166eab93cf1a5a95"
          }
        ],
        "responses": {
          "200": {
            "description": "S0 predeposit USDC reward",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PredepositRewardsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid address format"
          },
          "404": {
            "description": "No rewards found for this account"
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/prices": {
      "get": {
        "tags": [
          "Market Data"
        ],
        "summary": "Get market prices",
        "description": "Retrieve current perp prices for one or all perp markets, including oracle price,\nmark price, funding rate, and open interest. Use `market=all` or omit the\nparameter to fetch all perp markets. Spot markets do not publish `/prices`\nrows; derive spot mid price from `/orderbook` or the `depth:{marketAddr}`\nWebSocket topic.",
        "operationId": "handle_prices",
        "parameters": [
          {
            "name": "market",
            "in": "query",
            "description": "Perp market address filter (use \"all\" or omit for all perp markets)",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "0xmarket123..."
          }
        ],
        "responses": {
          "200": {
            "description": "Market prices retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PriceDto"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Market not found"
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/protected_trials": {
      "get": {
        "tags": [
          "Campaigns"
        ],
        "summary": "Get account's protected (FFT) trials",
        "description": "Returns the account's active protected trials plus a paginated terminal\nhistory (organic closes and admin resets). `limit`/`offset` apply to\n`history` only. An optional `campaign_addr` scopes the whole response.",
        "operationId": "handle_protected_trials",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "description": "User account address (`user` query alias is also accepted)",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "campaign_addr",
            "in": "query",
            "description": "Optional campaign address filter (default: all campaigns)",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size — paginates `history` only",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 10,
              "maximum": 200,
              "minimum": 0
            },
            "example": 100
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Page offset — paginates `history` only",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0,
              "maximum": 10000,
              "minimum": 0
            },
            "example": 0
          }
        ],
        "responses": {
          "200": {
            "description": "Protected trials retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProtectedTrialsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid address"
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/referrals/account/{account}": {
      "get": {
        "tags": [
          "Referrals"
        ],
        "summary": "Handler to get referral info for an account (who referred them)",
        "operationId": "handle_get_account_referral",
        "parameters": [
          {
            "name": "account",
            "in": "path",
            "description": "The wallet address to look up referral info for (not a subaccount address)",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successfully retrieved account referral info",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountReferralInfo"
                }
              }
            }
          },
          "400": {
            "description": "Invalid account address"
          },
          "404": {
            "description": "Account was not referred or not found"
          },
          "500": {
            "description": "Internal server error"
          }
        }
      }
    },
    "/api/v1/referrals/activity": {
      "get": {
        "tags": [
          "Referrals"
        ],
        "summary": "Get trading activity of a referrer's referred clients",
        "description": "Per-level window totals plus a page of direct (L1) referrals, each carrying the L2\nclients it referred. Carries no commission figures: the accrual ledger those would\ncome from does not exist yet.",
        "operationId": "handle_referral_activity",
        "parameters": [
          {
            "name": "referrer_account",
            "in": "query",
            "description": "The referrer's wallet address (not a subaccount address)",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "days",
            "in": "query",
            "description": "Trailing UTC days to cover. Defaults to 14, clamped to 90.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Direct (L1) clients per page. Defaults to 25, clamped to 200.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 0
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Direct (L1) clients to skip. Clamped to 10000.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Referral activity summary and client page",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReferralActivityResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid address"
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/referrals/clients": {
      "get": {
        "tags": [
          "Referrals"
        ],
        "summary": "Get a referrer's referred clients with lifecycle segments",
        "description": "Segment counts across the whole referral set, plus a filtered page of clients ordered\nby window volume. Carries no commission amounts: the accrual ledger is not built yet.",
        "operationId": "handle_referral_clients",
        "parameters": [
          {
            "name": "referrer_account",
            "in": "query",
            "description": "The referrer's wallet address (not a subaccount address)",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "days",
            "in": "query",
            "description": "Trailing UTC days the volume columns cover. Defaults to 30, clamped to 90.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Clients per page. Defaults to 25, clamped to 200.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 0
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Clients to skip. Clamped to 10000.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 0
            }
          },
          {
            "name": "segment",
            "in": "query",
            "description": "Keep only one lifecycle bucket: active, at_risk, dormant or never_traded.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Case-insensitive substring match on the client address.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Segment counts and a page of clients",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReferralClientsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid address or unknown segment"
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/referrals/code-performance": {
      "get": {
        "tags": [
          "Referrals"
        ],
        "summary": "Get per-code performance for a referrer",
        "description": "Redemptions and traded volume per referral code. Not paginated: an affiliate is capped\nat a handful of codes, so the whole set fits one response.",
        "operationId": "handle_code_performance",
        "parameters": [
          {
            "name": "referrer_account",
            "in": "query",
            "description": "The referrer's wallet address (not a subaccount address)",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "days",
            "in": "query",
            "description": "Trailing UTC days the volume columns cover. Defaults to 30, clamped to 90.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Per-code redemption and volume stats",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CodePerformance"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid address"
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/referrals/code/{code}": {
      "get": {
        "tags": [
          "Referrals"
        ],
        "summary": "GET /api/v1/referrals/code/{code}",
        "description": "Pre-wallet-connect validation of a referral code. Returns whether the code\nexists and is still active (can accept new referrals). No auth needed.\n\nIf the code doesn't exist, returns `is_valid: false` (not a 404).",
        "operationId": "handle_validate_code",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "description": "The referral code to validate",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Code validation result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReferralCodeValidationDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid code format"
          },
          "500": {
            "description": "Internal server error"
          }
        }
      }
    },
    "/api/v1/referrals/commissions": {
      "get": {
        "tags": [
          "Referrals"
        ],
        "summary": "Get an affiliate's accrued commission",
        "description": "What the affiliate has earned: today, since Monday, and over all time, plus a daily\nbreakdown carrying the tier and any anti-farming penalty that was in force each day.\n\nThis is not what is claimable. Claimable commission is an on-chain campaign allocation\nand comes from the campaigns endpoints; this is the off-chain ledger of what is owed.",
        "operationId": "handle_referral_commissions",
        "parameters": [
          {
            "name": "affiliate_account",
            "in": "query",
            "description": "The affiliate's wallet address (not a subaccount address)",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "days",
            "in": "query",
            "description": "Trailing UTC days of daily breakdown to return. Defaults to 30, clamped to 180.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The affiliate's accrued commission",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AffiliateCommissions"
                }
              }
            }
          },
          "400": {
            "description": "Invalid address"
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/referrals/fees": {
      "get": {
        "tags": [
          "Referrals"
        ],
        "summary": "Get fee revenue generated by a referrer's network",
        "description": "Net fees the referred network paid, the builder kickbacks owed on those same fills,\nand the difference — the basis an affiliate commission would be computed on. Returns\nno commission amount: no rate is signed off and no accrual ledger exists.",
        "operationId": "handle_referral_fees",
        "parameters": [
          {
            "name": "referrer_account",
            "in": "query",
            "description": "The referrer's wallet address (not a subaccount address)",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "days",
            "in": "query",
            "description": "Trailing UTC days to cover. Defaults to 30, clamped to 90.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Fee revenue generated by the referral network",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReferralFees"
                }
              }
            }
          },
          "400": {
            "description": "Invalid address"
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/referrals/funnel": {
      "get": {
        "tags": [
          "Referrals"
        ],
        "summary": "Get the referral funnel for a referrer",
        "description": "Sign-ups and first-time deposits per UTC day, newest day first. Days with no\nactivity are omitted; clients fill the gaps.",
        "operationId": "handle_referral_funnel",
        "parameters": [
          {
            "name": "referrer_account",
            "in": "query",
            "description": "The referrer's wallet address (not a subaccount address)",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "days",
            "in": "query",
            "description": "Most recent UTC days to return. Defaults to 14, clamped to 90.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Per-day sign-ups and first deposits",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ReferralFunnelDay"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid address"
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/referrals/redeem": {
      "post": {
        "tags": [
          "Referrals"
        ],
        "summary": "POST /api/v1/referrals/redeem",
        "description": "Redeems a referral code for an account. Validates the code in ClickHouse,\nthen submits an `admin_create_new_subaccount` transaction on-chain to create\nthe user's subaccount (bypassing invite-only gating).\n\nReferral tracking (code → user → referrer) stays entirely off-chain in ClickHouse.\nFee discounts and on-chain referral relationships will be bulk-registered post-TGE.\n\nAfter successful on-chain tx, writes a record to `referral_redemptions` in ClickHouse\nto track usage_count for code exhaustion.\n\nThis handler is **idempotent**: retrying the same (account, code) pair returns 200.\nRetrying with a *different* code returns 409.\n\n**Graceful degradation**: if ClickHouse writes fail after on-chain tx success,\nthe handler still returns 200 (the tx is the source of truth). Failed CH writes\nare logged with `RECONCILE_NEEDED` prefix for manual follow-up.",
        "operationId": "handle_redeem_referral",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RedeemReferralRequestDto"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Referral code redeemed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RedeemReferralResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid account or referral code format"
          },
          "404": {
            "description": "Referral code not found"
          },
          "409": {
            "description": "Already redeemed or code inactive"
          },
          "500": {
            "description": "Internal server error"
          },
          "501": {
            "description": "Referral redemption not enabled"
          }
        }
      }
    },
    "/api/v1/referrals/stats/{account}": {
      "get": {
        "tags": [
          "Referrals"
        ],
        "summary": "Handler to get referrer statistics.\nNon-affiliate referrers must meet the minimum trade volume threshold\nto see their referral codes. Affiliate referrers always see all codes.",
        "operationId": "handle_get_referrer_stats",
        "parameters": [
          {
            "name": "account",
            "in": "path",
            "description": "The referrer's wallet address (not a subaccount address)",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successfully retrieved referrer stats",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReferrerStatsDto"
                }
              }
            }
          },
          "404": {
            "description": "Referrer not found"
          },
          "500": {
            "description": "Internal server error"
          }
        }
      }
    },
    "/api/v1/referrals/sub-affiliates": {
      "get": {
        "tags": [
          "Referrals"
        ],
        "summary": "Get a referrer's sub-affiliates",
        "description": "Direct referrals who went on to refer others, with their downline size and that\ndownline's window volume. Carries no override amounts: the accrual ledger they would\ncome from does not exist yet.",
        "operationId": "handle_sub_affiliates",
        "parameters": [
          {
            "name": "referrer_account",
            "in": "query",
            "description": "The referrer's wallet address (not a subaccount address)",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "days",
            "in": "query",
            "description": "Trailing UTC days the network-volume column covers. Defaults to 30, clamped to 90.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Sub-affiliates per page. Defaults to 25, clamped to 200.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 0
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Sub-affiliates to skip. Clamped to 10000.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Sub-affiliate totals and a page of rows",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubAffiliatesResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid address"
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/referrals/users": {
      "get": {
        "tags": [
          "Referrals"
        ],
        "summary": "Handler to get users referred by a referrer",
        "operationId": "handle_get_user_referrals",
        "parameters": [
          {
            "name": "referrer_account",
            "in": "query",
            "description": "The referrer's wallet address (not a subaccount address)",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 10,
              "maximum": 1000,
              "minimum": 0
            },
            "example": 100
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Page offset",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0,
              "maximum": 10000,
              "minimum": 0
            },
            "example": 0
          }
        ],
        "responses": {
          "200": {
            "description": "Successfully retrieved user referrals",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/UserReferralInfo"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters"
          },
          "500": {
            "description": "Internal server error"
          }
        }
      }
    },
    "/api/v1/referrals/volume/daily": {
      "get": {
        "tags": [
          "Referrals"
        ],
        "summary": "Get referred volume per day for a referrer",
        "description": "Both-sides USD notional traded by the referrer's network, newest day first. Days\nwith no trading are omitted; clients fill the gaps.",
        "operationId": "handle_referred_volume",
        "parameters": [
          {
            "name": "referrer_account",
            "in": "query",
            "description": "The referrer's wallet address (not a subaccount address)",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "days",
            "in": "query",
            "description": "Most recent UTC days to return. Defaults to 14, clamped to 90.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Per-day referred volume",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ReferredVolumeDay"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid address"
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/spot/asset_contexts": {
      "get": {
        "tags": [
          "Market Data"
        ],
        "summary": "Get spot asset contexts",
        "description": "24h stats (volume, high/low, last price, prev-day price) plus the live\nbook mid for every registered spot market. The spot counterpart of\n`/asset_contexts`; perp-only concepts (funding, open interest, mark and\noracle prices) are deliberately absent. 24h change = (last_price -\nprev_day_price) / prev_day_price, derived client-side; `prev_day_price`\nis null for markets that never traded before the 24h boundary.",
        "operationId": "handle_spot_asset_contexts",
        "responses": {
          "200": {
            "description": "Spot asset contexts",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/SpotAssetContextDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/streaks/account": {
      "get": {
        "tags": [
          "Streaks"
        ],
        "summary": "Get account streak data including qualifying dates and grace days",
        "operationId": "handle_account_streaks",
        "parameters": [
          {
            "name": "owner",
            "in": "query",
            "description": "Owner wallet address. Used to look up all subaccounts and aggregate streak data.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0xb8a5788314451ce4d2fbbad32e1bad88d4184b73943b7fe5166eab93cf1a5a95"
          }
        ],
        "responses": {
          "200": {
            "description": "Account streak data with qualifying dates",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountStreaksResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid address format"
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/subaccounts": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Get subaccounts",
        "description": "Retrieve all subaccounts for a specific owner address.\nReturns subaccount addresses and their associated metadata.",
        "operationId": "handle_subaccounts",
        "parameters": [
          {
            "name": "owner",
            "in": "query",
            "description": "Owner account address",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0x123..."
          }
        ],
        "responses": {
          "200": {
            "description": "Subaccounts retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/SubaccountDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/trade_history": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Get user trade history",
        "description": "Retrieve perp trade history for a specific user with optional filtering by one\nperp market address, order ID, side, and timestamp range. Returns executed\ntrades with price, size, PnL, and fee details.\nSupports sorting by timestamp (default: descending) and pagination. Page size is capped at 200.",
        "operationId": "handle_account_trade_history",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "description": "User account address (`user` query alias is also accepted)",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "order_id",
            "in": "query",
            "description": "Filter by specific order ID (requires market to also be provided)",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "market",
            "in": "query",
            "description": "Filter by market address",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "side",
            "in": "query",
            "description": "Filter by side",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/SideFilter"
            }
          },
          {
            "name": "asset_type",
            "in": "query",
            "description": "Filter by product (\"perp\" | \"spot\"); omit to include both",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/AssetType"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 10,
              "maximum": 200,
              "minimum": 0
            },
            "example": 100
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Page offset",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0,
              "maximum": 10000,
              "minimum": 0
            },
            "example": 0
          },
          {
            "name": "start_timestamp",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "end_timestamp",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "sort_key",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/HistorySortKey"
            }
          },
          {
            "name": "sort_dir",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/SortDir"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Trade history retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_TradeDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters (order_id requires market)"
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/trades": {
      "get": {
        "tags": [
          "Market Data"
        ],
        "summary": "Get trades",
        "description": "Retrieve recent trades for a specific market ordered by most recent first.\nOptionally filter by order ID to get trades for a specific order. Supports pagination.\nSpot markets return one row per fill from the taker's perspective (matching the\n`market_trades` WS topic); the order ID filter matches either side's order.",
        "operationId": "handle_trades",
        "parameters": [
          {
            "name": "market",
            "in": "query",
            "description": "Market address",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "order_id",
            "in": "query",
            "description": "Order ID",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 10,
              "maximum": 200,
              "minimum": 0
            },
            "example": 100
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Page offset",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0,
              "maximum": 10000,
              "minimum": 0
            },
            "example": 0
          }
        ],
        "responses": {
          "200": {
            "description": "Market trade history retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_TradeDto"
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/transfers": {
      "post": {
        "tags": [
          "Transfers"
        ],
        "summary": "POST /api/v1/transfers",
        "description": "Records a confirmed deposit or withdrawal for attribution analytics. Called by\nthe web client (fire-and-forget) once a transfer confirms. This is an off-chain\nrecord — the on-chain UserMovement cannot distinguish a Mesh/CEX deposit, a\nbridge, and a direct wallet transfer. Generalizes the narrower /mesh/deposit\nendpoint to all transfer methods and both directions.\n\nKeyed on `account` so it joins to on-chain trading volume. Reliable for\nattribution, NOT for accounting.",
        "operationId": "handle_record_transfer",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RecordTransferRequestDto"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Transfer recorded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecordTransferResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request"
          },
          "500": {
            "description": "Internal server error"
          }
        }
      }
    },
    "/api/v1/twap_history": {
      "get": {
        "tags": [
          "TWAP"
        ],
        "summary": "Get TWAP order history",
        "description": "Retrieve TWAP order history for a specific user including completed and cancelled orders.\nReturns historical TWAP orders sorted by most recent first.\nSupports filtering by timestamp range, sorting by timestamp, and pagination. Page size is capped at 200.",
        "operationId": "handle_twap_history",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "description": "User account address (`user` query alias is also accepted)",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 10,
              "maximum": 200,
              "minimum": 0
            },
            "example": 100
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Page offset",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0,
              "maximum": 10000,
              "minimum": 0
            },
            "example": 0
          },
          {
            "name": "start_timestamp",
            "in": "query",
            "description": "Start timestamp in Unix milliseconds (inclusive). Must be provided together with `end_timestamp`.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 1700000000000
          },
          {
            "name": "end_timestamp",
            "in": "query",
            "description": "End timestamp in Unix milliseconds (inclusive). Must be provided together with `start_timestamp`.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 1701000000000
          },
          {
            "name": "sort_key",
            "in": "query",
            "description": "Sort key for history ordering. Defaults to `timestamp` when omitted.",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/HistorySortKey"
            }
          },
          {
            "name": "sort_dir",
            "in": "query",
            "description": "Sort direction for history ordering. Defaults to `DESC` when omitted.",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/SortDir"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "TWAP history retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_TwapDto"
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/user_fee_rates": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Get user fees and fee schedule",
        "description": "Returns the user's current maker/taker fee rates, fee tier based on the on-chain fee window,\nthe full fee schedule for all VIP tiers, and daily volume history for that same window.\n\nFee rates are decimal numbers where 0.000450 = 0.045%.\nVolume values are in whole USD. Volume data has up to 5-minute delay (MV refresh interval).\nThe current on-chain fee window includes today plus the previous 30 UTC calendar days.",
        "operationId": "handle_user_fees",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "description": "User account address (`user` query alias is also accepted)",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "User fee information retrieved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserFeesDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid account address"
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/user_fund_history": {
      "get": {
        "tags": [
          "User"
        ],
        "summary": "Get user fund history (deprecated)",
        "description": "**Deprecated:** This endpoint is deprecated. Please use `/api/v1/account_fund_history` instead.\nThis endpoint is maintained for backwards compatibility only.",
        "operationId": "handle_user_fund_history",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "description": "User account address (`user` query alias is also accepted)",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 10,
              "maximum": 200,
              "minimum": 0
            },
            "example": 100
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Page offset",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0,
              "maximum": 10000,
              "minimum": 0
            },
            "example": 0
          },
          {
            "name": "start_timestamp",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "end_timestamp",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "sort_key",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/HistorySortKey"
            }
          },
          {
            "name": "sort_dir",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/SortDir"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Fund history retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserFundHistoryResponse"
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/user_owned_vaults": {
      "get": {
        "tags": [
          "Vaults"
        ],
        "summary": "Get user-owned vaults (deprecated)",
        "description": "**Deprecated:** This endpoint is deprecated. Please use `/api/v1/account_owned_vaults` instead.\nThis endpoint is maintained for backwards compatibility only.",
        "operationId": "handle_user_owned_vaults",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "description": "Account address (`user` query alias is also accepted)",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 10,
              "maximum": 1000,
              "minimum": 0
            },
            "example": 100
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Page offset",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0,
              "maximum": 10000,
              "minimum": 0
            },
            "example": 0
          }
        ],
        "responses": {
          "200": {
            "description": "User-owned vaults retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_VaultDto"
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/user_positions": {
      "get": {
        "tags": [
          "User"
        ],
        "summary": "Get user positions (deprecated)",
        "description": "**Deprecated:** This perp-only endpoint is deprecated. Please use\n`/api/v1/account_positions` instead. This endpoint is maintained for\nbackwards compatibility only.",
        "operationId": "handle_user_positions",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "description": "Account address (`user` query alias is also accepted)",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0x123..."
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of positions to return",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 500,
              "minimum": 0
            },
            "example": 10
          },
          {
            "name": "include_deleted",
            "in": "query",
            "description": "Include deleted positions",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "example": false
          },
          {
            "name": "market_address",
            "in": "query",
            "description": "Filter by one perp market address",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "0xmarket123..."
          }
        ],
        "responses": {
          "200": {
            "description": "User positions retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PositionDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/user_vault_performance": {
      "get": {
        "tags": [
          "Vaults"
        ],
        "summary": "Get user vault performance (deprecated)",
        "description": "**Deprecated:** This endpoint is deprecated. Please use `/api/v1/account_vault_performance` instead.\nThis endpoint is maintained for backwards compatibility only.",
        "operationId": "handle_user_vault_performance",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "description": "Account address",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0xaccount123..."
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of results to skip (for pagination)",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64",
              "default": 0,
              "maximum": 10000,
              "minimum": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of results to return",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64",
              "default": 20,
              "maximum": 1000,
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "User vault performance retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AccountVaultPerformanceDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/vaults": {
      "get": {
        "tags": [
          "Vaults"
        ],
        "summary": "Get public vaults",
        "description": "Retrieve paginated list of public vaults with optional status, vault type, vault address, and search filtering.\nUse `vault_type` query parameter to filter by 'user' or 'protocol' vaults.\nUse `vault_address` query parameter to fetch a specific vault by its address (exact match).\nUse `search` query parameter to filter by vault address, vault name, or manager address (case-insensitive partial match).",
        "operationId": "handle_public_vaults",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "description": "Vault status filter (created, active, inactive). Defaults to `active` when omitted.",
            "required": false,
            "schema": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/VaultStatus"
                }
              ],
              "default": "active"
            },
            "example": "active"
          },
          {
            "name": "vault_type",
            "in": "query",
            "description": "Vault type filter (`user` or `protocol`). Returns all vaults when omitted.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "vault_address",
            "in": "query",
            "description": "Vault address filter. If provided, returns only the matching vault address.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Case-insensitive search across vault address, vault name, and manager address.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 10,
              "maximum": 1000,
              "minimum": 0
            },
            "example": 100
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Page offset",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0,
              "maximum": 10000,
              "minimum": 0
            },
            "example": 0
          },
          {
            "name": "sort_key",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/VaultSortKey"
            }
          },
          {
            "name": "sort_dir",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/SortDir"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Public vaults retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicVaultsResponse"
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    },
    "/api/v1/withdraw_queue": {
      "get": {
        "tags": [
          "User"
        ],
        "summary": "Get withdrawal queue entries for an account",
        "description": "Returns all withdrawal queue entries for the specified account,\noptionally filtered by status.",
        "operationId": "handle_withdraw_queue",
        "parameters": [
          {
            "name": "account",
            "in": "query",
            "description": "Account address",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Optional status filter (Queued, Processed, Cancelled)",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/WithdrawQueueStatus"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 10,
              "maximum": 200,
              "minimum": 0
            },
            "example": 100
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Page offset",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0,
              "maximum": 10000,
              "minimum": 0
            },
            "example": 0
          }
        ],
        "responses": {
          "200": {
            "description": "Withdraw queue entries retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_WithdrawQueueEntryDto"
                }
              }
            }
          },
          "500": {
            "description": "Database error"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "AccountOverviewDto": {
        "type": "object",
        "required": [
          "perp_equity_balance",
          "perp_equity_haircutted",
          "unrealized_pnl",
          "unrealized_funding_cost",
          "cross_margin_ratio",
          "maintenance_margin",
          "cross_account_leverage_ratio",
          "total_margin",
          "usdc_cross_withdrawable_balance",
          "usdc_isolated_withdrawable_balance",
          "margin_deficit",
          "cross_available_to_trade"
        ],
        "properties": {
          "all_time_return": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "average_cash_position": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "average_leverage": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "cross_account_leverage_ratio": {
            "type": "number",
            "format": "double",
            "example": 40.99
          },
          "cross_account_position": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "cross_available_to_trade": {
            "type": "number",
            "format": "double",
            "description": "Total cross-margin buying power across all collateral assets (USDC + secondary).\nFormula: max(0, raw_free_collateral − order_margin)\n       = max(0, cross_margin + secondary_collateral_value + min(0, uPnL − funding) − initial_margin − order_margin)\nUse this for \"Available to Trade\" display. Unlike usdc_cross_withdrawable_balance\n(which is capped at the USDC balance), this reflects the full buying power including\nDLP and other secondary collateral.",
            "example": 4791.47
          },
          "cross_margin_ratio": {
            "type": "number",
            "format": "double",
            "example": 0.01
          },
          "fee_income": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Non-trade fee income (vault/BLP accounts only).\nProtocol fee distributions recorded as CBH Fee entries but not captured in trade fee_amount.\nRegular users: always null (their CBH fee entries exactly match trade fee amounts).",
            "example": 5386.0
          },
          "free_vault_equity": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "USDC value of vault shares NOT currently pledged as DLP collateral on this\nsubaccount's perp account (\"free\" shares × NAV). This is the additive\ncomplement to `perp_equity_balance`: summing the two gives the subaccount's\ntotal wealth with no double-count of pledged DLP (which `perp_equity_balance`\nalready covers via `secondary_collateral`).\n\nEquals 0.0 for users who pledge all their vault shares as collateral. The\nfull pre-pledge total is still visible in `vault_equity` for display.\n\nNULL when not yet available (e.g., WebSocket updates before real-time vault tracking).",
            "example": 14.65
          },
          "liquidation_fees_paid": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Total fees paid during margin call liquidations (always positive).\nFee rate is configurable per market (default 0.5%, max 2% of notional).\nThis is already included in realized_pnl but shown separately for transparency.\nNull for accounts that have never been margin called.",
            "example": 45.5
          },
          "liquidation_losses": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Net collateral balance changes from liquidations (vault/BLP accounts only).\nRegular users: always null - their liquidation loss is in realized_pnl via BackStopLiquidation trades.\nVault accounts: positive = margin received from liquidated users (profit),\n                negative = bad debt covered when users were underwater (loss).",
            "example": -500.0
          },
          "maintenance_margin": {
            "type": "number",
            "format": "double",
            "example": 115.29
          },
          "margin_deficit": {
            "type": "number",
            "format": "double",
            "description": "Cross-margin deficit: 0 when healthy, negative when the account has a margin hole.\nWhen negative, new deposits will partially fill this deficit before becoming\navailable to trade. For example, deficit = -12 means a $185 deposit yields\nonly $173 available (the first $12 fills the hole).\nFormula: min(0, margin_balance - margin_for_free_collateral + min(0, unrealized_pnl - funding) - order_margin)",
            "example": -12.06
          },
          "max_drawdown": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "net_deposits": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Net deposits (total deposits - total withdrawals) in USDC.\nUsed to verify all_time_return: all_time_return = ((equity - net_deposits) / net_deposits) * 100",
            "example": 30277044.96
          },
          "perp_equity_balance": {
            "type": "number",
            "format": "double",
            "description": "Perp equity at FULL NAV — DLP / secondary collateral counted at oracle/computed\nprice WITHOUT the haircut discount. Intended for **display** (\"your total\naccount value\"). Do NOT use this as the equity input to client-side liquidation\nprice estimation; use `perp_equity_haircutted` instead so the estimate matches\nthe on-chain liquidation threshold.",
            "example": 10064.88
          },
          "perp_equity_haircutted": {
            "type": "number",
            "format": "double",
            "description": "Perp equity with the haircut applied to secondary collateral. This is the value\nthe on-chain liquidation engine uses to decide whether to liquidate. The order\nform's pre-trade liquidation-price estimate must consume this (not\n`perp_equity_balance`) to match the positions tab.\n\nDifference from `perp_equity_balance`: `perp_equity_balance - perp_equity_haircutted`\nequals the secondary collateral haircut discount (i.e. `sum(amount × NAV × haircut_bps/10000)`).\nFor accounts with no secondary collateral the two fields are equal.",
            "example": 10054.92
          },
          "pnl_90d": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "realized_pnl": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "example": 1250.5
          },
          "secondary_collateral": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/SecondaryCollateralDto"
            },
            "description": "Secondary (non-USDC) collateral held in cross margin.\nNULL when no secondary collateral exists or oracle data is unavailable."
          },
          "sharpe_ratio": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "spot": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/SpotOverviewDto",
                "description": "Spot-tradable inventory for this subaccount, sourced from PFS holdings.\nUSDC held in the PFS IS included as a PnL-less position priced 1.0: a\ntoken sits in exactly one store, so PFS USDC can never overlap the CBS\nbalance that perp equity counts (no double-count possible), and the\nspot_value_snapshots series counts it too — the live overview and the\nportfolio chart must agree. `in_flight_orders` covers amounts locked in\nescrow for open spot orders. NULL for wallet-only owners (no subaccount)."
              }
            ]
          },
          "total_margin": {
            "type": "number",
            "format": "double",
            "example": 9998.72
          },
          "unrealized_funding_cost": {
            "type": "number",
            "format": "double",
            "example": -87.84
          },
          "unrealized_pnl": {
            "type": "number",
            "format": "double",
            "example": 154.0
          },
          "usdc_cross_withdrawable_balance": {
            "type": "number",
            "format": "double",
            "example": 9843.79
          },
          "usdc_isolated_withdrawable_balance": {
            "type": "number",
            "format": "double",
            "example": 0.0
          },
          "vault_equity": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Total USDC value of vault shares attributed to this subaccount (free shares\nin the subaccount's primary store **plus** shares pledged as DLP collateral\non its perp account). Intended for direct display (\"your total vault position\nis worth $X\") — answers the question \"what do I own in vaults?\".\n\n**Do not add to `perp_equity_balance` to compute total wealth.** The pledged\nportion is already counted in `perp_equity_balance` via `secondary_collateral`,\nso summing the two double-counts pledged DLP. Use `free_vault_equity` (below)\nas the additive complement instead: `perp_equity_balance + free_vault_equity`\ngives total wealth with no overlap.\n\nNULL when not yet available (e.g., WebSocket updates before real-time vault tracking).",
            "example": 259.73
          },
          "volume": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "weekly_win_rate_12w": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          }
        }
      },
      "AccountReferralInfo": {
        "type": "object",
        "description": "Account referral information - shows who referred this account",
        "required": [
          "account",
          "referrer_account",
          "referral_code",
          "is_affiliate_referral",
          "referred_at_ms",
          "is_active"
        ],
        "properties": {
          "account": {
            "type": "string",
            "description": "The referred user's wallet address (not a subaccount address)"
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the referral code is still active (can accept new referrals)"
          },
          "is_affiliate_referral": {
            "type": "boolean"
          },
          "referral_code": {
            "type": "string"
          },
          "referred_at_ms": {
            "type": "integer",
            "format": "int64"
          },
          "referrer_account": {
            "type": "string",
            "description": "The referrer's wallet address"
          }
        }
      },
      "AccountStreaksResponse": {
        "type": "object",
        "description": "Account streaks response DTO",
        "required": [
          "owner",
          "currentStreak",
          "streakIpoints",
          "streakAmpsEstimate",
          "graceDaysAvailable",
          "graceDaysUsed",
          "qualifyingDates"
        ],
        "properties": {
          "currentStreak": {
            "type": "integer",
            "format": "int32",
            "description": "Current consecutive days streak",
            "minimum": 0
          },
          "graceDaysAvailable": {
            "type": "integer",
            "format": "int32",
            "description": "Grace days available (earned from 14d taker volume)",
            "minimum": 0
          },
          "graceDaysUsed": {
            "type": "integer",
            "format": "int32",
            "description": "Grace days used to preserve current streak",
            "minimum": 0
          },
          "owner": {
            "type": "string",
            "description": "Owner wallet address"
          },
          "qualifyingDates": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "All qualifying dates (days with $500+ volume) as ISO date strings (YYYY-MM-DD)"
          },
          "streakAmpsEstimate": {
            "type": "number",
            "format": "double",
            "description": "Estimated streak Amps based on current pool share"
          },
          "streakIpoints": {
            "type": "number",
            "format": "double",
            "description": "Streak iPoints earned today (from lookup table)"
          }
        }
      },
      "AccountVaultPerformanceDto": {
        "type": "object",
        "required": [
          "vault",
          "account_address"
        ],
        "properties": {
          "account_address": {
            "type": "string"
          },
          "all_time_earned": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "All-time profit/loss in USDC (includes both realized and unrealized)"
          },
          "all_time_return": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "All-time return percentage (includes both realized and unrealized)"
          },
          "current_num_shares": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "Number of shares owned (in base units with 6 decimals)",
            "minimum": 0
          },
          "current_value_of_shares": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Current value of user's shares in USDC"
          },
          "deposits": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/VaultDeposit"
            }
          },
          "locked_amount": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Amount currently locked (cannot withdraw). Frontend: withdrawable = current_value_of_shares - locked_amount"
          },
          "share_price": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Current share price (NAV per share)"
          },
          "total_deposited": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Total amount deposited in USDC (sum of all contributions)"
          },
          "total_withdrawn": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Total amount withdrawn in USDC (sum of all settled redemptions)"
          },
          "unrealized_pnl": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Unrealized profit/loss in USDC (only on current holdings)"
          },
          "vault": {
            "$ref": "#/components/schemas/PublicVaultDto",
            "description": "Vault object with metadata + metrics"
          },
          "volume": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Trading volume in USDC"
          },
          "weekly_win_rate_12w": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "withdrawals": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/VaultWithdrawal"
            }
          }
        }
      },
      "AccountVolumeDto": {
        "type": "object",
        "description": "Response for `GET /api/v1/account_volume?account=<address>&start_date=<YYYY-MM-DD>&end_date=<YYYY-MM-DD>`.\n\nReturns the account's aggregate trading volume (total, maker, taker) in whole USD\nfor the requested inclusive date range.\nWhen `start_date`/`end_date` are omitted the range defaults to the past 30 days\n(today() - 29 .. today() inclusive, UTC).\n\nVolume data has up to 5-minute delay (MV refresh interval).",
        "required": [
          "account",
          "start_date",
          "end_date",
          "volume",
          "maker_volume",
          "taker_volume"
        ],
        "properties": {
          "account": {
            "type": "string",
            "description": "The queried account address"
          },
          "end_date": {
            "type": "string",
            "description": "Inclusive end date of the range used (YYYY-MM-DD, UTC)"
          },
          "maker_volume": {
            "type": "string",
            "description": "Maker-side volume across the range (USD, whole-dollar integer string)"
          },
          "start_date": {
            "type": "string",
            "description": "Inclusive start date of the range used (YYYY-MM-DD, UTC)"
          },
          "taker_volume": {
            "type": "string",
            "description": "Taker-side volume across the range (USD, whole-dollar integer string)"
          },
          "volume": {
            "type": "string",
            "description": "Total volume across the range (USD, whole-dollar integer string)"
          }
        }
      },
      "AffiliateCodeAnalyticsDto": {
        "type": "object",
        "description": "Per-code analytics for an owner's affiliate codes. Kept in a distinct DTO\nfrom `AffiliateCodeDto` so that adding new metrics does not bloat the code\nmetadata surface — the metadata endpoint is on the global nav critical path\nand must stay lean.",
        "required": [
          "referral_code",
          "l1_volume_usd",
          "l1_amps_earned"
        ],
        "properties": {
          "l1_amps_earned": {
            "type": "number",
            "format": "double",
            "description": "Amps earned by the affiliate from L1 users of this code\n(L1 users' total amps × 0.15 for affiliate rows, 0.10 otherwise)."
          },
          "l1_volume_usd": {
            "type": "number",
            "format": "double",
            "description": "Total USD volume traded by L1 users who redeemed this specific code."
          },
          "referral_code": {
            "type": "string",
            "description": "The referral code string these metrics belong to."
          }
        }
      },
      "AffiliateCodeAnalyticsResponseDto": {
        "type": "object",
        "description": "Response wrapper for the affiliate code analytics endpoint.",
        "required": [
          "owner_account",
          "codes"
        ],
        "properties": {
          "codes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AffiliateCodeAnalyticsDto"
            },
            "description": "Per-code analytics rows, one per affiliate code owned by this account."
          },
          "owner_account": {
            "type": "string",
            "description": "The owner's wallet address."
          }
        }
      },
      "AffiliateCodeDto": {
        "type": "object",
        "description": "Per-code info returned by the affiliate codes endpoint",
        "required": [
          "referral_code",
          "owner_account",
          "max_usage",
          "usage_count",
          "is_active",
          "is_affiliate",
          "source",
          "created_at_ms"
        ],
        "properties": {
          "created_at_ms": {
            "type": "integer",
            "format": "int64",
            "description": "When this code was created (milliseconds since epoch)"
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the code is still active (usage_count < max_usage)"
          },
          "is_affiliate": {
            "type": "boolean",
            "description": "Whether this is an affiliate code (high-usage codes for affiliates)"
          },
          "max_usage": {
            "type": "integer",
            "format": "int64",
            "description": "Maximum number of times this code can be used",
            "minimum": 0
          },
          "owner_account": {
            "type": "string",
            "description": "The wallet address that owns this code (not a subaccount address)"
          },
          "referral_code": {
            "type": "string",
            "description": "The referral code string"
          },
          "source": {
            "$ref": "#/components/schemas/ReferralCodeSource",
            "description": "How this code was created"
          },
          "usage_count": {
            "type": "integer",
            "format": "int64",
            "description": "Current number of times this code has been used",
            "minimum": 0
          }
        }
      },
      "AffiliateCodesResponseDto": {
        "type": "object",
        "description": "Response wrapper for the affiliate codes endpoint",
        "required": [
          "owner_account",
          "codes",
          "volume_threshold_met"
        ],
        "properties": {
          "codes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AffiliateCodeDto"
            },
            "description": "List of affiliate codes with usage stats"
          },
          "owner_account": {
            "type": "string",
            "description": "The owner's wallet address"
          },
          "volume_threshold_met": {
            "type": "boolean",
            "description": "Whether the account meets the minimum trade volume threshold\nto see non-affiliate (auto-generated) codes"
          }
        }
      },
      "AffiliateCommissionDay": {
        "type": "object",
        "description": "One UTC day of accrual, with the rules that produced it.\n\nThe tier and penalty are the values that were in force on that day, read off the row\nrather than recomputed — which is the whole reason the ledger stamps them.",
        "required": [
          "date",
          "accrued_usd",
          "basis_l1_usd",
          "basis_l2_usd",
          "tier",
          "rate_l1",
          "rate_l2",
          "penalty_multiplier"
        ],
        "properties": {
          "accrued_usd": {
            "type": "number",
            "format": "double",
            "description": "Commission accrued that day, after any anti-farming penalty"
          },
          "basis_l1_usd": {
            "type": "number",
            "format": "double",
            "description": "Fee basis from direct referrals"
          },
          "basis_l2_usd": {
            "type": "number",
            "format": "double",
            "description": "Fee basis from second-level referrals"
          },
          "date": {
            "type": "string",
            "description": "UTC date, `YYYY-MM-DD`"
          },
          "penalty_multiplier": {
            "type": "number",
            "format": "double",
            "description": "1.0 when unpenalised. Below that, an anti-farming override was in force.\n\nThe multiplier is here and the *reason* is deliberately not. The reason string is the\ndetection's own working notes — `SYBIL_REFERRAL_FARM_ORCHESTRATOR: 5-member R2 cluster of\n89 activated, flag_ratio 0.20` — and serving it told anyone who asked both that a wallet\nwas flagged and exactly what tripped it, which is how an anti-abuse system stops working.\nIt also labelled an address as a fraud in a public response. An affiliate needs to know\ntheir commission was reduced, which the multiplier says; why it was reduced is a\nconversation with support, not a field."
          },
          "rate_l1": {
            "type": "number",
            "format": "double",
            "description": "The L1 share that applied that day, as a fraction — 0.25 for bronze.\n\nSent rather than left for the client to derive from `tier`, which would put a second\ncopy of the rate table in the frontend. The server stamped these; it should report\nthem. A caller splitting commission by level needs the day's own rate because the\ntier moves inside a 30-day window."
          },
          "rate_l2": {
            "type": "number",
            "format": "double",
            "description": "The L2 override share that applied that day, as a fraction — 0.10 for bronze."
          },
          "tier": {
            "type": "string",
            "description": "`bronze` | `silver` | `gold`, as stamped that day"
          }
        }
      },
      "AffiliateCommissionWeek": {
        "type": "object",
        "description": "One week of accrual and what the sweep decided about it.\n\nThe row exists as soon as the week has accruals, whether or not it has been swept. That\nis the point: an unswept week is money still coming, and a screen that only listed swept\nweeks would make the current one vanish.",
        "required": [
          "week_start_date",
          "accrued_usd",
          "status",
          "reason",
          "allocated_usd",
          "campaign_id",
          "minimum_usd"
        ],
        "properties": {
          "accrued_usd": {
            "type": "number",
            "format": "double",
            "description": "What the seven days accrued, from the ledger."
          },
          "allocated_usd": {
            "type": "number",
            "format": "double",
            "description": "What the sweep actually allocated. Zero on a forfeited or unswept week, which is why\nit is reported alongside `accrued_usd` rather than instead of it."
          },
          "campaign_id": {
            "type": "integer",
            "format": "int64",
            "description": "On-chain campaign, or 0 when the allocation has not been pushed to one yet.",
            "minimum": 0
          },
          "minimum_usd": {
            "type": "number",
            "format": "double",
            "description": "The floor in force that week. Stored per sweep because it is program config that can\nchange, and a past week must be explainable under the rule it was judged by."
          },
          "reason": {
            "type": "string",
            "description": "`below_minimum` | `flagged`, or empty. The answer to \"why was I not paid?\"."
          },
          "status": {
            "type": "string",
            "description": "`paid` | `forfeited` | `withheld`, or empty when the sweep has not run."
          },
          "week_start_date": {
            "type": "string",
            "description": "Monday of the week, `YYYY-MM-DD`"
          }
        }
      },
      "AffiliateCommissions": {
        "type": "object",
        "description": "An affiliate's accrued commission: today, the running week, and lifetime.\n\nDistinct from what is *claimable*, which lives on chain in `campaign_claims`. This\nendpoint answers \"what have I earned\"; the chain answers \"what can I take\". Keeping them\napart is what makes \"accrued but not yet swept\" and \"accrued but forfeited\" answerable\nwithout trusting either side alone.",
        "required": [
          "accrued_today_usd",
          "accrued_this_week_usd",
          "lifetime_accrued_usd",
          "week_start_date",
          "previous_week_usd",
          "previous_week_status",
          "previous_week_campaign_id",
          "minimum_payout_usd",
          "meets_minimum",
          "progress_to_minimum",
          "mode",
          "pending_mode",
          "pending_effective_from",
          "days",
          "weeks",
          "current_tier",
          "current_nuv_usd",
          "nuv_window_days",
          "tiers"
        ],
        "properties": {
          "accrued_this_week_usd": {
            "type": "number",
            "format": "double",
            "description": "Accrued since Monday. This is what the weekly sweep will pay, or forfeit."
          },
          "accrued_today_usd": {
            "type": "number",
            "format": "double",
            "description": "Accrued so far today. Provisional until the week is swept."
          },
          "current_nuv_usd": {
            "type": "number",
            "format": "double",
            "description": "The trailing-window NUV that rung was derived from."
          },
          "current_tier": {
            "type": "string",
            "description": "The rung in force, from the most recent accrual. `bronze` when there is no history:\nan affiliate whose network brings nobody new still earns, at the lowest rate."
          },
          "days": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AffiliateCommissionDay"
            },
            "description": "Daily breakdown, oldest first. Days with no activity are absent, not zero-filled."
          },
          "lifetime_accrued_usd": {
            "type": "number",
            "format": "double",
            "description": "Accrued over all time, including weeks already paid."
          },
          "meets_minimum": {
            "type": "boolean",
            "description": "Whether the running week currently clears the floor"
          },
          "minimum_payout_usd": {
            "type": "number",
            "format": "double",
            "description": "The floor a week must clear to be paid at all"
          },
          "mode": {
            "type": "string",
            "description": "`points` | `usd`, as stamped on the most recent accrual. Absent history reads\n`points`, which is the status quo for every affiliate today."
          },
          "nuv_window_days": {
            "type": "integer",
            "format": "int32",
            "description": "Days in the NUV window. Sent so the caller can label it without hardcoding 30.",
            "minimum": 0
          },
          "pending_effective_from": {
            "type": "string",
            "description": "The Monday `pending_mode` starts, `YYYY-MM-DD`, or empty when nothing is pending."
          },
          "pending_mode": {
            "type": "string",
            "description": "A recorded election that has not taken effect yet, or empty.\n\nPublished because `mode` alone cannot express it. An election lands on a future Monday, so\nbetween signing it and that day the affiliate is still earning the old currency and the\nledger still stamps it — a screen reading only `mode` shows no trace of a decision that has\nalready been made, irreversibly. The affiliate concludes it failed and tries again."
          },
          "previous_week_campaign_id": {
            "type": "integer",
            "format": "int64",
            "description": "On-chain campaign carrying the previous week, or 0 when it is not on chain yet. A\nnon-zero id means the money is claimable through the campaigns endpoints, not here.",
            "minimum": 0
          },
          "previous_week_status": {
            "type": "string",
            "description": "What the sweep decided about that week: `paid`, `forfeited`, `withheld`, or empty\nwhen it has not been swept yet. Empty is the common case early in a week."
          },
          "previous_week_usd": {
            "type": "number",
            "format": "double",
            "description": "Accrued over the week before this one. Non-zero for the two or three days between a\nweek closing and its sweep paying out — the window in which the running week reads\nnear zero while real money is still owed."
          },
          "progress_to_minimum": {
            "type": "number",
            "format": "double",
            "description": "0.0–1.0 progress toward the floor, for a progress indicator"
          },
          "tiers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CommissionTier"
            },
            "description": "The whole ladder, highest rung first. Static config, published so no client keeps a\nsecond copy of the rate table."
          },
          "week_start_date": {
            "type": "string",
            "description": "Monday of the running week, `YYYY-MM-DD`"
          },
          "weeks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AffiliateCommissionWeek"
            },
            "description": "Weekly history, newest first: what each week accrued and what the sweep decided.\n\nSeparate from `days` because the two answer different questions — `days` is how the\nfigure was built, `weeks` is what happened to it."
          }
        }
      },
      "AffiliateEarningsBreakdownDto": {
        "type": "object",
        "description": "Aggregated affiliate earnings split by referral level.",
        "required": [
          "l1_amps",
          "l2_amps",
          "total_amps",
          "l1_count",
          "l2_count"
        ],
        "properties": {
          "l1_amps": {
            "type": "number",
            "format": "double",
            "description": "Uncapped sum of amps earned from L1 (direct) referrals."
          },
          "l1_count": {
            "type": "integer",
            "format": "int64",
            "description": "Number of L1 referred users.",
            "minimum": 0
          },
          "l2_amps": {
            "type": "number",
            "format": "double",
            "description": "Uncapped sum of amps earned from L2 (sub-affiliate) referrals."
          },
          "l2_count": {
            "type": "integer",
            "format": "int64",
            "description": "Number of L2 referred users.",
            "minimum": 0
          },
          "total_amps": {
            "type": "number",
            "format": "double",
            "description": "Capped total referral amps from the materialized view."
          }
        }
      },
      "AffiliateEarningsResponseDto": {
        "type": "object",
        "description": "Response for GET /api/v1/affiliates/earnings/{account}.",
        "required": [
          "affiliate_account",
          "is_affiliate",
          "earnings",
          "users"
        ],
        "properties": {
          "affiliate_account": {
            "type": "string",
            "description": "The affiliate's wallet address."
          },
          "earnings": {
            "$ref": "#/components/schemas/AffiliateEarningsBreakdownDto",
            "description": "Aggregated earnings breakdown."
          },
          "is_affiliate": {
            "type": "boolean",
            "description": "Whether this account is a managed affiliate (15% L1 rate) or normal referrer (10%)."
          },
          "users": {
            "$ref": "#/components/schemas/PaginatedResponse_AffiliateReferredUserDto",
            "description": "Per-user referral details (paginated)."
          }
        }
      },
      "AssetContextDto": {
        "type": "object",
        "required": [
          "market",
          "volume_24h",
          "open_interest",
          "mark_price",
          "mid_price",
          "oracle_price",
          "previous_day_price",
          "price_change_pct_24h"
        ],
        "properties": {
          "mark_price": {
            "type": "number",
            "format": "double"
          },
          "market": {
            "type": "string",
            "example": "0xmarket123..."
          },
          "mid_price": {
            "type": "number",
            "format": "double"
          },
          "open_interest": {
            "type": "number",
            "format": "double"
          },
          "oracle_price": {
            "type": "number",
            "format": "double"
          },
          "previous_day_price": {
            "type": "number",
            "format": "double"
          },
          "price_change_pct_24h": {
            "type": "number",
            "format": "double"
          },
          "volume_24h": {
            "type": "number",
            "format": "double"
          }
        }
      },
      "AssetType": {
        "type": "string",
        "description": "Discriminator carried on DTOs that can mix perp and spot rows (markets,\norders, trades, bulk orders, bulk order fills, and WebSocket payloads).\nAlso accepted as a query parameter on REST endpoints that can filter to one\nproduct.\n\nWire format is lowercase (`\"perp\"` / `\"spot\"`) and accepted\ncase-insensitively on the request side via [`impl_case_insensitive_deserialize`].",
        "enum": [
          "perp",
          "spot"
        ]
      },
      "BulkOrderDto": {
        "type": "object",
        "required": [
          "asset_type",
          "market",
          "user",
          "sequence_number",
          "bid_prices",
          "bid_sizes",
          "ask_prices",
          "ask_sizes",
          "cancelled_bid_prices",
          "cancelled_bid_sizes",
          "cancelled_ask_prices",
          "cancelled_ask_sizes",
          "cancellation_reason",
          "transaction_version",
          "transaction_unix_ms",
          "event_uid"
        ],
        "properties": {
          "ask_prices": {
            "type": "array",
            "items": {
              "type": "number",
              "format": "double"
            },
            "example": [
              101.0,
              102.0,
              103.0
            ]
          },
          "ask_sizes": {
            "type": "array",
            "items": {
              "type": "number",
              "format": "double"
            },
            "example": [
              1.0,
              2.0,
              3.0
            ]
          },
          "asset_type": {
            "$ref": "#/components/schemas/AssetType",
            "description": "`\"perp\"` or `\"spot\"` — discriminator so callers can mix perp and spot\nrows in the same response without ambiguity."
          },
          "bid_prices": {
            "type": "array",
            "items": {
              "type": "number",
              "format": "double"
            },
            "example": [
              99.0,
              98.0,
              97.0
            ]
          },
          "bid_sizes": {
            "type": "array",
            "items": {
              "type": "number",
              "format": "double"
            },
            "example": [
              1.0,
              2.0,
              3.0
            ]
          },
          "cancellation_reason": {
            "type": "string"
          },
          "cancelled_ask_prices": {
            "type": "array",
            "items": {
              "type": "number",
              "format": "double"
            },
            "example": []
          },
          "cancelled_ask_sizes": {
            "type": "array",
            "items": {
              "type": "number",
              "format": "double"
            },
            "example": []
          },
          "cancelled_bid_prices": {
            "type": "array",
            "items": {
              "type": "number",
              "format": "double"
            },
            "example": [
              100.0
            ]
          },
          "cancelled_bid_sizes": {
            "type": "array",
            "items": {
              "type": "number",
              "format": "double"
            },
            "example": [
              1.0
            ]
          },
          "event_uid": {
            "$ref": "#/components/schemas/u128"
          },
          "market": {
            "type": "string",
            "example": "0xmarket123..."
          },
          "previous_seq_num": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "example": 12344,
            "minimum": 0
          },
          "sequence_number": {
            "type": "integer",
            "format": "int64",
            "example": 12345,
            "minimum": 0
          },
          "transaction_unix_ms": {
            "type": "integer",
            "format": "int64",
            "example": 1730841600000
          },
          "transaction_version": {
            "type": "integer",
            "format": "int64",
            "example": 12345,
            "minimum": 0
          },
          "user": {
            "type": "string",
            "example": "0x123..."
          }
        }
      },
      "BulkOrderFillDto": {
        "type": "object",
        "required": [
          "asset_type",
          "market",
          "sequence_number",
          "user",
          "filled_size",
          "price",
          "is_bid",
          "trade_id",
          "transaction_unix_ms",
          "transaction_version",
          "event_uid"
        ],
        "properties": {
          "asset_type": {
            "$ref": "#/components/schemas/AssetType",
            "description": "`\"perp\"` or `\"spot\"` — discriminator so callers can mix perp and spot\nrows in the same response without ambiguity."
          },
          "event_uid": {
            "$ref": "#/components/schemas/u128"
          },
          "filled_size": {
            "type": "number",
            "format": "double"
          },
          "is_bid": {
            "type": "boolean"
          },
          "market": {
            "type": "string",
            "example": "0xmarket123..."
          },
          "price": {
            "type": "number",
            "format": "double"
          },
          "sequence_number": {
            "type": "integer",
            "format": "int64",
            "example": 12345,
            "minimum": 0
          },
          "trade_id": {
            "type": "string",
            "example": "3647276"
          },
          "transaction_unix_ms": {
            "type": "integer",
            "format": "int64",
            "example": 1730841600000
          },
          "transaction_version": {
            "type": "integer",
            "format": "int64",
            "example": 12345,
            "minimum": 0
          },
          "user": {
            "type": "string",
            "example": "0x123..."
          }
        }
      },
      "BulkOrderStatusResponse": {
        "type": "object",
        "required": [
          "status",
          "details",
          "bulk_order"
        ],
        "properties": {
          "bulk_order": {
            "$ref": "#/components/schemas/BulkOrderDto"
          },
          "details": {
            "type": "string"
          },
          "status": {
            "type": "string"
          }
        }
      },
      "CampaignLocksResponse": {
        "type": "object",
        "required": [
          "account",
          "locks",
          "total_count"
        ],
        "properties": {
          "account": {
            "type": "string"
          },
          "locks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LockDto"
            }
          },
          "total_count": {
            "type": "integer",
            "format": "int32",
            "description": "Total rows matching the filters across all pages (SQL-level count:\norphan rows skipped from `locks` still count and consume page slots).",
            "minimum": 0
          }
        }
      },
      "CampaignMetadata": {
        "type": "object",
        "required": [
          "campaign_id",
          "campaign_type",
          "status",
          "title",
          "reward_asset",
          "start_ts_sec",
          "end_ts_sec",
          "claim_start_ts_sec",
          "claim_end_ts_sec",
          "total_funded"
        ],
        "properties": {
          "campaign_id": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "campaign_type": {
            "$ref": "#/components/schemas/CampaignType"
          },
          "claim_end_ts_sec": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "claim_start_ts_sec": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "end_ts_sec": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "reward_asset": {
            "type": "string"
          },
          "start_ts_sec": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "status": {
            "$ref": "#/components/schemas/CampaignStatus"
          },
          "title": {
            "type": "string"
          },
          "total_funded": {
            "type": "integer",
            "format": "int64",
            "description": "Reward-asset subunits; divide by the asset's decimals client-side for display.",
            "minimum": 0
          }
        }
      },
      "CampaignStatus": {
        "type": "string",
        "description": "Wire form: lowercase string in `campaign_status_updates.new_status`. Empty row →\n`Draft` (synthesized read-side, never written).",
        "enum": [
          "draft",
          "funded",
          "active",
          "expired",
          "reclaimed",
          "cancelled"
        ]
      },
      "CampaignType": {
        "type": "string",
        "description": "u8 mapping mirrors `campaign_manager.move::campaign_type_to_u8`.",
        "enum": [
          "fee_rebate",
          "maker_incentive",
          "liquidation_rebate",
          "volume_milestone",
          "first_funded_trial"
        ]
      },
      "CandlestickResponseItemDto": {
        "type": "object",
        "required": [
          "t",
          "T",
          "o",
          "h",
          "l",
          "c",
          "v",
          "i"
        ],
        "properties": {
          "T": {
            "type": "integer",
            "format": "int64",
            "example": 1761591599999
          },
          "c": {
            "type": "number",
            "format": "double",
            "example": 100.0
          },
          "h": {
            "type": "number",
            "format": "double",
            "example": 102.0
          },
          "i": {
            "type": "string",
            "example": "1h"
          },
          "l": {
            "type": "number",
            "format": "double",
            "example": 98.0
          },
          "o": {
            "type": "number",
            "format": "double",
            "example": 100.0
          },
          "t": {
            "type": "integer",
            "format": "int64",
            "example": 1761588000000
          },
          "v": {
            "type": "number",
            "format": "double",
            "example": 1000.0
          }
        }
      },
      "ClientSegment": {
        "type": "string",
        "description": "Where a client sits in the lifecycle, by how recently it last traded.\n\n`NeverTraded` is its own bucket rather than folded into `Dormant`: on real data it is\nthe overwhelming majority (16k of 17k referrals for one mainnet affiliate), and\nmerging it would hide the affiliate's actual problem, which is activation rather than\nretention. The four buckets partition the referral set, so they sum to the total.",
        "enum": [
          "active",
          "at_risk",
          "dormant",
          "never_traded"
        ]
      },
      "ClientSegments": {
        "type": "object",
        "description": "How many clients sit in each lifecycle bucket. Always the whole referral set, never\nthe filtered page, so the four counts sum to the affiliate's referral total.",
        "required": [
          "active",
          "at_risk",
          "dormant",
          "never_traded"
        ],
        "properties": {
          "active": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "at_risk": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "dormant": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "never_traded": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          }
        }
      },
      "CodePerformance": {
        "type": "object",
        "description": "What one referral code brought in.",
        "required": [
          "referral_code",
          "unique_users",
          "users_who_traded",
          "taker_volume_usd",
          "maker_volume_usd",
          "earnings_usd"
        ],
        "properties": {
          "earnings_usd": {
            "type": "number",
            "format": "double",
            "description": "Everything this code brought in: the L1 commission of the people who used it, plus the\nL2 override their own referrals generated. Credited to the code the sub-affiliate\narrived through, so the codes sum to the affiliate's whole commission with nothing\nstranded outside every row."
          },
          "maker_volume_usd": {
            "type": "number",
            "format": "double"
          },
          "referral_code": {
            "type": "string"
          },
          "taker_volume_usd": {
            "type": "number",
            "format": "double"
          },
          "unique_users": {
            "type": "integer",
            "format": "int64",
            "description": "Distinct wallets that redeemed this code, all-time",
            "minimum": 0
          },
          "users_who_traded": {
            "type": "integer",
            "format": "int64",
            "description": "How many of those traded inside the window",
            "minimum": 0
          }
        }
      },
      "CommissionTier": {
        "type": "object",
        "description": "One rung of the commission ladder, as the affiliate sees it.\n\nPublished by the server rather than restated in the client, for the same reason the daily\nrates are: a second copy of the rate table would let a screen quote a rate the ledger never\npaid, and an affiliate who read the wrong number read it wrong for good.",
        "required": [
          "tier",
          "nuv_threshold_usd",
          "rate_l1",
          "rate_l2"
        ],
        "properties": {
          "nuv_threshold_usd": {
            "type": "number",
            "format": "double",
            "description": "Trailing-window NUV, in USD, at or above which this rung applies. Inclusive."
          },
          "rate_l1": {
            "type": "number",
            "format": "double",
            "description": "Share of the direct-referral fee basis, as a fraction — 0.25 for bronze."
          },
          "rate_l2": {
            "type": "number",
            "format": "double",
            "description": "Share of the second-level fee basis, as a fraction — 0.10 for bronze."
          },
          "tier": {
            "type": "string",
            "description": "`bronze` | `silver` | `gold`"
          }
        }
      },
      "ContractDto": {
        "type": "object",
        "description": "Per-market derivative contract summary for aggregator integration.\nAll numeric values are serialized as strings per the CoinGecko/CMC spec.",
        "required": [
          "contract_index",
          "ticker_id",
          "base_currency",
          "target_currency",
          "last_price",
          "base_volume",
          "target_volume",
          "high",
          "low",
          "product_type",
          "open_interest",
          "open_interest_usd",
          "index_price",
          "index_currency",
          "start_timestamp",
          "end_timestamp",
          "funding_rate",
          "next_funding_rate",
          "next_funding_rate_timestamp"
        ],
        "properties": {
          "base_currency": {
            "type": "string"
          },
          "base_volume": {
            "type": "string"
          },
          "contract_index": {
            "type": "integer",
            "minimum": 0
          },
          "end_timestamp": {
            "type": "string"
          },
          "funding_rate": {
            "type": "string"
          },
          "high": {
            "type": "string"
          },
          "index_currency": {
            "type": "string"
          },
          "index_price": {
            "type": "string"
          },
          "last_price": {
            "type": "string"
          },
          "low": {
            "type": "string"
          },
          "next_funding_rate": {
            "type": "string"
          },
          "next_funding_rate_timestamp": {
            "type": "string"
          },
          "open_interest": {
            "type": "string"
          },
          "open_interest_usd": {
            "type": "string"
          },
          "product_type": {
            "type": "string"
          },
          "start_timestamp": {
            "type": "string"
          },
          "target_currency": {
            "type": "string"
          },
          "target_volume": {
            "type": "string"
          },
          "ticker_id": {
            "type": "string"
          }
        }
      },
      "ContractSpecDto": {
        "type": "object",
        "description": "Per-market contract specification for aggregator integration.",
        "required": [
          "ticker_id",
          "contract_type",
          "contract_price_currency"
        ],
        "properties": {
          "contract_price_currency": {
            "type": "string"
          },
          "contract_type": {
            "type": "string"
          },
          "ticker_id": {
            "type": "string"
          }
        }
      },
      "ContractSpecsResponse": {
        "type": "object",
        "description": "Wrapper response for the `/contract_specs` endpoint (CoinGecko/CMC spec).",
        "required": [
          "contract_specs"
        ],
        "properties": {
          "contract_specs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ContractSpecDto"
            }
          }
        }
      },
      "ContractsResponse": {
        "type": "object",
        "description": "Wrapper response matching the CoinGecko/CMC `/contracts` format.",
        "required": [
          "contracts"
        ],
        "properties": {
          "contracts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ContractDto"
            }
          }
        }
      },
      "DailyAmpsDto": {
        "type": "object",
        "description": "One season-day of Amps, split by bucket.",
        "required": [
          "day_index",
          "day_start_unix_ms",
          "total_amps",
          "trading_amps",
          "streak_amps",
          "referral_amps",
          "vault_amps"
        ],
        "properties": {
          "day_index": {
            "type": "integer",
            "format": "int64",
            "description": "Season-relative day number (0 = season start)",
            "minimum": 0
          },
          "day_start_unix_ms": {
            "type": "integer",
            "format": "int64",
            "description": "UTC start of this day, so clients never recompute season math"
          },
          "referral_amps": {
            "type": "number",
            "format": "double"
          },
          "streak_amps": {
            "type": "number",
            "format": "double"
          },
          "total_amps": {
            "type": "number",
            "format": "double",
            "description": "trading + streak + referral + vault (no bonus — see the parent doc comment)"
          },
          "trading_amps": {
            "type": "number",
            "format": "double"
          },
          "vault_amps": {
            "type": "number",
            "format": "double"
          }
        }
      },
      "DailyStatsDto": {
        "type": "object",
        "description": "Daily statistics for DefiLlama integration",
        "required": [
          "daily_volume",
          "daily_fees",
          "daily_revenue",
          "open_interest"
        ],
        "properties": {
          "daily_fees": {
            "type": "number",
            "format": "double",
            "description": "Total fees collected in USD"
          },
          "daily_revenue": {
            "type": "number",
            "format": "double",
            "description": "Net revenue (fees minus rebates) in USD"
          },
          "daily_volume": {
            "type": "number",
            "format": "double",
            "description": "Total trading volume in USD"
          },
          "open_interest": {
            "type": "number",
            "format": "double",
            "description": "Total open interest in USD"
          }
        }
      },
      "DailyUserVolumeDto": {
        "type": "object",
        "description": "Per-day trading volume entry for the current on-chain fee window.",
        "required": [
          "date",
          "volume",
          "maker_volume",
          "taker_volume"
        ],
        "properties": {
          "date": {
            "type": "string",
            "description": "Date in YYYY-MM-DD format (UTC)"
          },
          "maker_volume": {
            "type": "string",
            "description": "Maker-side volume (USD, whole-dollar integer string)"
          },
          "taker_volume": {
            "type": "string",
            "description": "Taker-side volume (USD, whole-dollar integer string)"
          },
          "volume": {
            "type": "string",
            "description": "Total volume (USD, whole-dollar integer string)"
          }
        }
      },
      "DelegationDto": {
        "type": "object",
        "description": "Represents a delegation for a subaccount",
        "required": [
          "delegated_account",
          "permission_type"
        ],
        "properties": {
          "delegated_account": {
            "type": "string",
            "description": "The address of the delegated account",
            "example": "0x123..."
          },
          "expiration_time_s": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "The expiration time in seconds (optional, None means no expiration)",
            "example": 1736326800000,
            "minimum": 0
          },
          "permission_market": {
            "type": [
              "string",
              "null"
            ],
            "description": "The market address when permission_type is \"TradePerpsOnMarket\", null otherwise",
            "example": "0x161b7b3f58327d057ee5824de0c1a4fc4fa3d121b847c138e921a255768a0dca"
          },
          "permission_type": {
            "type": "string",
            "description": "The permission type that was granted. Market-scoped grants have\npermission_type \"TradePerpsOnMarket\" with the market address in permission_market.",
            "example": "TradePerpsAllMarkets"
          }
        }
      },
      "FeeScheduleDto": {
        "type": "object",
        "description": "Fee schedule as the chain last reported it, including all thresholds.\nRead from the indexed `unified_fees_config` events, so a deployer retune is\nreflected here without a server redeploy. The server-side constants are only\na fallback covering the window before the first event lands.",
        "required": [
          "taker",
          "maker",
          "tiers",
          "referral_discount"
        ],
        "properties": {
          "maker": {
            "type": "number",
            "format": "double",
            "description": "Base maker fee (tier 0, no volume requirement). Decimal number, e.g. 0.000150"
          },
          "referral_discount": {
            "type": "number",
            "format": "double",
            "description": "Referral discount fraction applied to referred users (e.g. 0.04 = 4% discount).\n0.0 when referrals are disabled."
          },
          "taker": {
            "type": "number",
            "format": "double",
            "description": "Base taker fee (tier 0, no volume requirement). Decimal number, e.g. 0.000450"
          },
          "tiers": {
            "$ref": "#/components/schemas/FeeTiersDto",
            "description": "All fee tiers above the base"
          }
        }
      },
      "FeeTiersDto": {
        "type": "object",
        "description": "Grouped fee tier schedules.",
        "required": [
          "vip",
          "market_maker"
        ],
        "properties": {
          "market_maker": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MarketMakerTierDto"
            },
            "description": "Market-maker rebate tiers (empty when rebates are disabled)"
          },
          "vip": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/VipTierDto"
            },
            "description": "Volume-based VIP tiers (tiers 1–N; tier 0 rates are in the parent FeeScheduleDto)"
          }
        }
      },
      "FundMovementType": {
        "type": "string",
        "enum": [
          "deposit",
          "withdrawal",
          "reward"
        ]
      },
      "FundingRateHistory": {
        "type": "object",
        "required": [
          "market",
          "action",
          "size",
          "realized_funding_amount",
          "is_rebate",
          "fee_amount",
          "transaction_unix_ms"
        ],
        "properties": {
          "action": {
            "type": "string",
            "example": "Close Long"
          },
          "fee_amount": {
            "type": "number",
            "format": "double"
          },
          "is_rebate": {
            "type": "boolean"
          },
          "market": {
            "type": "string",
            "example": "0xmarket123..."
          },
          "realized_funding_amount": {
            "type": "number",
            "format": "double",
            "description": "Realized funding amount in USDC\n- Negative value: trader PAID funding (e.g., long position with positive funding rate)\n- Positive value: trader RECEIVED funding (e.g., short position with positive funding rate)\n- Zero: no funding accrued",
            "example": -15.5
          },
          "size": {
            "type": "number",
            "format": "double",
            "example": 1.0
          },
          "transaction_unix_ms": {
            "type": "integer",
            "format": "int64",
            "example": 1735758000000
          }
        }
      },
      "GlobalPointsStatsDto": {
        "type": "object",
        "required": [
          "total_users",
          "total_amps_distributed"
        ],
        "properties": {
          "total_amps_distributed": {
            "type": "number",
            "format": "double"
          },
          "total_users": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          }
        }
      },
      "HistorySortKey": {
        "type": "string",
        "description": "Sort key for history endpoints",
        "enum": [
          "timestamp"
        ]
      },
      "Interval": {
        "type": "string",
        "enum": [
          "1m",
          "5m",
          "15m",
          "30m",
          "1h",
          "2h",
          "4h",
          "8h",
          "12h",
          "1d",
          "3d",
          "1w",
          "1mo"
        ]
      },
      "LeaderboardEntryDto": {
        "type": "object",
        "required": [
          "rank",
          "account",
          "account_value",
          "realized_pnl",
          "roi",
          "volume"
        ],
        "properties": {
          "account": {
            "type": "string"
          },
          "account_value": {
            "type": "number",
            "format": "double"
          },
          "rank": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "realized_pnl": {
            "type": "number",
            "format": "double"
          },
          "roi": {
            "type": "number",
            "format": "double"
          },
          "volume": {
            "type": "number",
            "format": "double"
          }
        }
      },
      "LeaderboardSortKey": {
        "type": "string",
        "enum": [
          "account_value",
          "realized_pnl",
          "volume",
          "roi"
        ]
      },
      "LockDto": {
        "type": "object",
        "description": "A campaign reward lock. Extension fields appear on extended locks only;\nreturned/claimed fields on claimed locks only.",
        "required": [
          "lock_id",
          "campaign_addr",
          "trial_id",
          "amount",
          "amount_usd",
          "duration_days",
          "lock_subaccount",
          "locked_at_ms",
          "unlocks_at_ms",
          "status",
          "was_extended"
        ],
        "properties": {
          "amount": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "amount_usd": {
            "type": "number",
            "format": "double"
          },
          "campaign_addr": {
            "type": "string"
          },
          "claimed_at_ms": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64"
          },
          "duration_days": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "extended_at_ms": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64"
          },
          "lock_id": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "lock_subaccount": {
            "type": "string"
          },
          "locked_at_ms": {
            "type": "integer",
            "format": "int64"
          },
          "previous_unlocks_at_ms": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64"
          },
          "returned_amount": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "Trading-PnL-adjusted; may differ from `amount`.",
            "minimum": 0
          },
          "returned_amount_usd": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "status": {
            "$ref": "#/components/schemas/LockStatus"
          },
          "trial_id": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "unlocks_at_ms": {
            "type": "integer",
            "format": "int64"
          },
          "was_extended": {
            "type": "boolean"
          }
        }
      },
      "LockStatus": {
        "type": "string",
        "description": "PascalCase deliberately follows the trial-DTO family, not the campaigns\nfamily's lowercase.",
        "enum": [
          "Active",
          "Claimed"
        ]
      },
      "MarketDto": {
        "type": "object",
        "required": [
          "asset_type",
          "market_addr",
          "market_name",
          "sz_decimals",
          "max_leverage",
          "tick_size",
          "min_size",
          "lot_size",
          "max_open_interest",
          "px_decimals",
          "mode",
          "unrealized_pnl_haircut_bps",
          "category",
          "min_price",
          "max_price",
          "is_isolated_only"
        ],
        "properties": {
          "asset_type": {
            "$ref": "#/components/schemas/AssetType",
            "description": "`\"perp\"` or `\"spot\"` — discriminator so callers can mix perp and spot\nmarkets in the same `/markets` response without ambiguity."
          },
          "category": {
            "type": "string",
            "description": "Perp market category. Empty string for spot markets."
          },
          "is_isolated_only": {
            "type": "boolean",
            "description": "Perp-only; always false for spot."
          },
          "lot_size": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "market_addr": {
            "type": "string"
          },
          "market_name": {
            "type": "string"
          },
          "max_leverage": {
            "type": "integer",
            "format": "int32",
            "description": "Perp-only max leverage. Always 0 for spot markets.",
            "minimum": 0
          },
          "max_open_interest": {
            "type": "number",
            "format": "double",
            "description": "Perp-only max open interest. Always 0 for spot markets."
          },
          "max_price": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "min_price": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "min_size": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "mode": {
            "type": "string",
            "description": "Perp market mode. Spot markets currently return `\"Open\"`."
          },
          "px_decimals": {
            "type": "integer",
            "format": "int32",
            "description": "Price decimals. For spot rows this is the quote asset decimals.",
            "minimum": 0
          },
          "sz_decimals": {
            "type": "integer",
            "format": "int32",
            "description": "Size decimals. For spot rows this is the base asset decimals.",
            "minimum": 0
          },
          "tick_size": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "unrealized_pnl_haircut_bps": {
            "type": "integer",
            "format": "int32",
            "description": "Haircut for unrealized PnL when calculating withdrawable balance (in basis points, e.g., 1000 = 10%).\nAlways 0 for spot markets (which don't carry unrealized PnL).",
            "minimum": 0
          }
        }
      },
      "MarketMakerTierDto": {
        "type": "object",
        "description": "A single market-maker rebate tier.\nUsers must provide at least `maker_fraction_threshold` of total global volume as maker to qualify (inclusive, matches on-chain `>=` logic).",
        "required": [
          "maker_fraction_threshold",
          "maker"
        ],
        "properties": {
          "maker": {
            "type": "number",
            "format": "double",
            "description": "Maker rebate rate (negative decimal number, e.g. -0.000010)"
          },
          "maker_fraction_threshold": {
            "type": "string",
            "description": "Fraction of global volume the user must provide as maker (decimal string, e.g. \"0.005\")"
          }
        }
      },
      "OrderDto": {
        "type": "object",
        "required": [
          "asset_type",
          "parent",
          "market",
          "client_order_id",
          "order_id",
          "status",
          "order_type",
          "trigger_condition",
          "order_direction",
          "is_buy",
          "is_reduce_only",
          "details",
          "is_tpsl",
          "cancellation_reason",
          "transaction_version",
          "unix_ms"
        ],
        "properties": {
          "asset_type": {
            "$ref": "#/components/schemas/AssetType",
            "description": "`\"perp\"` or `\"spot\"` — discriminator so callers can mix perp and spot\nrows in the same response without ambiguity. Per-row, lowercase."
          },
          "cancellation_reason": {
            "type": "string"
          },
          "client_order_id": {
            "type": "string",
            "description": "Client-supplied order ID. Empty when the order was placed without one\n(both perp and spot carry this on the shared `OrderEvent`)."
          },
          "details": {
            "type": "string"
          },
          "is_buy": {
            "type": "boolean"
          },
          "is_reduce_only": {
            "type": "boolean",
            "description": "Perp reduce-only flag. Always false for spot orders."
          },
          "is_tpsl": {
            "type": "boolean",
            "description": "Perp TP/SL marker. Always false for spot orders."
          },
          "market": {
            "type": "string"
          },
          "order_direction": {
            "type": "string",
            "description": "Direction, in the vocabulary of this row's product. Perp is\nposition-centric (`\"Open Long\"` / `\"Close Long\"` / `\"Open Short\"` /\n`\"Close Short\"`). Spot has no position to open or close, so it is\nsimply `\"Buy\"` / `\"Sell\"`, the same values `TradeDto::action` uses for\nspot fills. Demux on `asset_type`."
          },
          "order_id": {
            "type": "string"
          },
          "order_type": {
            "type": "string",
            "description": "Perp order type. Empty for spot orders; use `time_in_force` for spot."
          },
          "orig_size": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "parent": {
            "type": "string",
            "description": "Perp parent order ID. Empty for spot orders, which are always top-level."
          },
          "price": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "remaining_size": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "size_delta": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "sl_limit_price": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Perp TP/SL field. Null for spot orders."
          },
          "sl_trigger_price": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Perp TP/SL field. Null for spot orders."
          },
          "status": {
            "type": "string"
          },
          "time_in_force": {
            "type": "string",
            "description": "Time-in-force tag for spot orders (`\"GTC\"` / `\"POST_ONLY\"` / `\"IOC\"`).\nEmpty string for perp orders, which carry this signal in `order_type`\ninstead. Surfaced separately because the spot engine reports it as a\nfirst-class field on every `OrderEvent`."
          },
          "tp_limit_price": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Perp TP/SL field. Null for spot orders."
          },
          "tp_trigger_price": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Perp TP/SL field. Null for spot orders."
          },
          "transaction_version": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "trigger_condition": {
            "type": "string",
            "description": "Perp trigger condition. Empty for spot orders."
          },
          "unix_ms": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          }
        }
      },
      "OrderUpdate": {
        "type": "object",
        "required": [
          "status",
          "details",
          "order"
        ],
        "properties": {
          "details": {
            "type": "string"
          },
          "order": {
            "$ref": "#/components/schemas/OrderDto"
          },
          "status": {
            "type": "string"
          }
        }
      },
      "OrderbookResponse": {
        "type": "object",
        "description": "CoinGecko/CMC orderbook response with bid/ask depth.\nPrices and quantities are string pairs per the aggregator spec.",
        "required": [
          "ticker_id",
          "timestamp",
          "bids",
          "asks"
        ],
        "properties": {
          "asks": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Ask levels as [price, quantity] string pairs, lowest price first"
          },
          "bids": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Bid levels as [price, quantity] string pairs, highest price first"
          },
          "ticker_id": {
            "type": "string",
            "description": "Aggregator-compatible field name; value is the requested market address."
          },
          "timestamp": {
            "type": "string",
            "description": "Unix timestamp in milliseconds of last update"
          }
        }
      },
      "OwnerAmpsDailyDto": {
        "type": "object",
        "description": "Per-day Amps for one owner over a bounded window.\n\nScoped to a single season on purpose: `day_index` is season-relative, so\naggregating two seasons would collide day 5 of each into one bucket.\n\nNote the total excludes `bonus_amps`: there is no `bonus_amps_daily` table, so\nno per-day source exists for it. Program-wide that is ~1.6% of all Amps, but for\nan owner who received a bonus this series will not sum to the `total_amps` shown\nby `/points/amps` or the leaderboard.",
        "required": [
          "owner",
          "season",
          "days"
        ],
        "properties": {
          "days": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DailyAmpsDto"
            },
            "description": "Newest day first"
          },
          "owner": {
            "type": "string",
            "description": "Owner address"
          },
          "season": {
            "type": "string",
            "description": "Season these day indexes belong to"
          }
        }
      },
      "OwnerAmpsDto": {
        "type": "object",
        "description": "Per-user amps breakdown response DTO\nAll values are sourced from the points_leaderboard_stats MV,\nguaranteeing consistency with the leaderboard.",
        "required": [
          "owner",
          "total_amps",
          "trading_amps",
          "streak_amps",
          "bonus_amps",
          "referral_amps",
          "vault_amps",
          "realized_pnl"
        ],
        "properties": {
          "bonus_amps": {
            "type": "number",
            "format": "double",
            "description": "Bonus amps earned (guild wars, campaigns, etc.)"
          },
          "owner": {
            "type": "string",
            "description": "Owner address"
          },
          "rank": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "Rank on the points leaderboard (null if not on leaderboard)",
            "minimum": 0
          },
          "realized_pnl": {
            "type": "number",
            "format": "double",
            "description": "Realized PnL across all subaccounts"
          },
          "referral_amps": {
            "type": "number",
            "format": "double",
            "description": "Referral amps earned"
          },
          "streak_amps": {
            "type": "number",
            "format": "double",
            "description": "Streak amps earned"
          },
          "total_amps": {
            "type": "number",
            "format": "double",
            "description": "Total amps (trading + streak + bonus + referral + vault)"
          },
          "trading_amps": {
            "type": "number",
            "format": "double",
            "description": "Trading amps earned"
          },
          "vault_amps": {
            "type": "number",
            "format": "double",
            "description": "Vault amps earned"
          }
        }
      },
      "OwnerTradingHz": {
        "type": "object",
        "description": "Trading Hz aggregated by owner response DTO",
        "required": [
          "owner",
          "total_amps"
        ],
        "properties": {
          "breakdown": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/SubaccountHz"
            },
            "description": "Per-subaccount breakdown (null if owner has no subaccounts)"
          },
          "owner": {
            "type": "string",
            "description": "Owner address"
          },
          "total_amps": {
            "type": "number",
            "format": "double",
            "description": "Total Hz earned across all subaccounts"
          }
        }
      },
      "OwnerTradingPoints": {
        "type": "object",
        "description": "Trading points aggregated by owner response DTO",
        "required": [
          "owner",
          "total_points"
        ],
        "properties": {
          "breakdown": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/SubaccountPoints"
            },
            "description": "Per-subaccount breakdown (null if owner has no subaccounts)"
          },
          "owner": {
            "type": "string",
            "description": "Owner address"
          },
          "total_points": {
            "type": "number",
            "format": "double",
            "description": "Total trading points across all active subaccounts"
          }
        }
      },
      "PaginatedResponse_AffiliateReferredUserDto": {
        "type": "object",
        "required": [
          "items"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "A referred user in the affiliate's referral tree, with their earned amps.",
              "required": [
                "account",
                "level",
                "total_amps",
                "affiliate_amps_earned",
                "total_volume",
                "active"
              ],
              "properties": {
                "account": {
                  "type": "string",
                  "description": "The referred user's wallet address."
                },
                "active": {
                  "type": "boolean",
                  "description": "Whether the user has traded (volume > 0)."
                },
                "affiliate_amps_earned": {
                  "type": "number",
                  "format": "double",
                  "description": "Amps earned by the affiliate from this user (total_amps * rate)."
                },
                "level": {
                  "$ref": "#/components/schemas/ReferralLevel",
                  "description": "Referral level: L1 (direct) or L2 (sub-affiliate)."
                },
                "referred_by": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "For L2 users, the L1 user who referred them. `None` for L1 users."
                },
                "total_amps": {
                  "type": "number",
                  "format": "double",
                  "description": "The user's all-time Hz from trading activity."
                },
                "total_volume": {
                  "type": "number",
                  "format": "double",
                  "description": "The user's all-time trade volume in USD."
                }
              }
            },
            "description": "The items in the current page"
          },
          "total_count": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "The total number of items across all pages.\nOptional: history endpoints omit this field to avoid expensive COUNT(*) queries.",
            "minimum": 0
          }
        }
      },
      "PaginatedResponse_FundingRateHistory": {
        "type": "object",
        "required": [
          "items"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "market",
                "action",
                "size",
                "realized_funding_amount",
                "is_rebate",
                "fee_amount",
                "transaction_unix_ms"
              ],
              "properties": {
                "action": {
                  "type": "string",
                  "example": "Close Long"
                },
                "fee_amount": {
                  "type": "number",
                  "format": "double"
                },
                "is_rebate": {
                  "type": "boolean"
                },
                "market": {
                  "type": "string",
                  "example": "0xmarket123..."
                },
                "realized_funding_amount": {
                  "type": "number",
                  "format": "double",
                  "description": "Realized funding amount in USDC\n- Negative value: trader PAID funding (e.g., long position with positive funding rate)\n- Positive value: trader RECEIVED funding (e.g., short position with positive funding rate)\n- Zero: no funding accrued",
                  "example": -15.5
                },
                "size": {
                  "type": "number",
                  "format": "double",
                  "example": 1.0
                },
                "transaction_unix_ms": {
                  "type": "integer",
                  "format": "int64",
                  "example": 1735758000000
                }
              }
            },
            "description": "The items in the current page"
          },
          "total_count": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "The total number of items across all pages.\nOptional: history endpoints omit this field to avoid expensive COUNT(*) queries.",
            "minimum": 0
          }
        }
      },
      "PaginatedResponse_LeaderboardEntryDto": {
        "type": "object",
        "required": [
          "items"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "rank",
                "account",
                "account_value",
                "realized_pnl",
                "roi",
                "volume"
              ],
              "properties": {
                "account": {
                  "type": "string"
                },
                "account_value": {
                  "type": "number",
                  "format": "double"
                },
                "rank": {
                  "type": "integer",
                  "format": "int32",
                  "minimum": 0
                },
                "realized_pnl": {
                  "type": "number",
                  "format": "double"
                },
                "roi": {
                  "type": "number",
                  "format": "double"
                },
                "volume": {
                  "type": "number",
                  "format": "double"
                }
              }
            },
            "description": "The items in the current page"
          },
          "total_count": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "The total number of items across all pages.\nOptional: history endpoints omit this field to avoid expensive COUNT(*) queries.",
            "minimum": 0
          }
        }
      },
      "PaginatedResponse_OrderDto": {
        "type": "object",
        "required": [
          "items"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "asset_type",
                "parent",
                "market",
                "client_order_id",
                "order_id",
                "status",
                "order_type",
                "trigger_condition",
                "order_direction",
                "is_buy",
                "is_reduce_only",
                "details",
                "is_tpsl",
                "cancellation_reason",
                "transaction_version",
                "unix_ms"
              ],
              "properties": {
                "asset_type": {
                  "$ref": "#/components/schemas/AssetType",
                  "description": "`\"perp\"` or `\"spot\"` — discriminator so callers can mix perp and spot\nrows in the same response without ambiguity. Per-row, lowercase."
                },
                "cancellation_reason": {
                  "type": "string"
                },
                "client_order_id": {
                  "type": "string",
                  "description": "Client-supplied order ID. Empty when the order was placed without one\n(both perp and spot carry this on the shared `OrderEvent`)."
                },
                "details": {
                  "type": "string"
                },
                "is_buy": {
                  "type": "boolean"
                },
                "is_reduce_only": {
                  "type": "boolean",
                  "description": "Perp reduce-only flag. Always false for spot orders."
                },
                "is_tpsl": {
                  "type": "boolean",
                  "description": "Perp TP/SL marker. Always false for spot orders."
                },
                "market": {
                  "type": "string"
                },
                "order_direction": {
                  "type": "string",
                  "description": "Direction, in the vocabulary of this row's product. Perp is\nposition-centric (`\"Open Long\"` / `\"Close Long\"` / `\"Open Short\"` /\n`\"Close Short\"`). Spot has no position to open or close, so it is\nsimply `\"Buy\"` / `\"Sell\"`, the same values `TradeDto::action` uses for\nspot fills. Demux on `asset_type`."
                },
                "order_id": {
                  "type": "string"
                },
                "order_type": {
                  "type": "string",
                  "description": "Perp order type. Empty for spot orders; use `time_in_force` for spot."
                },
                "orig_size": {
                  "type": [
                    "number",
                    "null"
                  ],
                  "format": "double"
                },
                "parent": {
                  "type": "string",
                  "description": "Perp parent order ID. Empty for spot orders, which are always top-level."
                },
                "price": {
                  "type": [
                    "number",
                    "null"
                  ],
                  "format": "double"
                },
                "remaining_size": {
                  "type": [
                    "number",
                    "null"
                  ],
                  "format": "double"
                },
                "size_delta": {
                  "type": [
                    "number",
                    "null"
                  ],
                  "format": "double"
                },
                "sl_limit_price": {
                  "type": [
                    "number",
                    "null"
                  ],
                  "format": "double",
                  "description": "Perp TP/SL field. Null for spot orders."
                },
                "sl_trigger_price": {
                  "type": [
                    "number",
                    "null"
                  ],
                  "format": "double",
                  "description": "Perp TP/SL field. Null for spot orders."
                },
                "status": {
                  "type": "string"
                },
                "time_in_force": {
                  "type": "string",
                  "description": "Time-in-force tag for spot orders (`\"GTC\"` / `\"POST_ONLY\"` / `\"IOC\"`).\nEmpty string for perp orders, which carry this signal in `order_type`\ninstead. Surfaced separately because the spot engine reports it as a\nfirst-class field on every `OrderEvent`."
                },
                "tp_limit_price": {
                  "type": [
                    "number",
                    "null"
                  ],
                  "format": "double",
                  "description": "Perp TP/SL field. Null for spot orders."
                },
                "tp_trigger_price": {
                  "type": [
                    "number",
                    "null"
                  ],
                  "format": "double",
                  "description": "Perp TP/SL field. Null for spot orders."
                },
                "transaction_version": {
                  "type": "integer",
                  "format": "int64",
                  "minimum": 0
                },
                "trigger_condition": {
                  "type": "string",
                  "description": "Perp trigger condition. Empty for spot orders."
                },
                "unix_ms": {
                  "type": "integer",
                  "format": "int64",
                  "minimum": 0
                }
              }
            },
            "description": "The items in the current page"
          },
          "total_count": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "The total number of items across all pages.\nOptional: history endpoints omit this field to avoid expensive COUNT(*) queries.",
            "minimum": 0
          }
        }
      },
      "PaginatedResponse_PointsLeaderboardEntryDto": {
        "type": "object",
        "required": [
          "items"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "rank",
                "owner",
                "total_amps",
                "realized_pnl",
                "referral_amps",
                "vault_amps",
                "streak_amps",
                "bonus_amps"
              ],
              "properties": {
                "bonus_amps": {
                  "type": "number",
                  "format": "double"
                },
                "owner": {
                  "type": "string"
                },
                "rank": {
                  "type": "integer",
                  "format": "int32",
                  "minimum": 0
                },
                "realized_pnl": {
                  "type": "number",
                  "format": "double"
                },
                "referral_amps": {
                  "type": "number",
                  "format": "double"
                },
                "streak_amps": {
                  "type": "number",
                  "format": "double"
                },
                "total_amps": {
                  "type": "number",
                  "format": "double"
                },
                "vault_amps": {
                  "type": "number",
                  "format": "double"
                }
              }
            },
            "description": "The items in the current page"
          },
          "total_count": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "The total number of items across all pages.\nOptional: history endpoints omit this field to avoid expensive COUNT(*) queries.",
            "minimum": 0
          }
        }
      },
      "PaginatedResponse_TradeDto": {
        "type": "object",
        "required": [
          "items"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "asset_type",
                "account",
                "market",
                "action",
                "source",
                "trade_id",
                "size",
                "price",
                "is_profit",
                "realized_pnl_amount",
                "realized_funding_amount",
                "is_rebate",
                "fee_amount",
                "order_id",
                "client_order_id",
                "transaction_unix_ms",
                "transaction_version",
                "counter_party_account"
              ],
              "properties": {
                "account": {
                  "type": "string",
                  "description": "User's account address",
                  "example": "0x1234567890abcdef1234567890abcdef12345678"
                },
                "action": {
                  "type": "string",
                  "description": "Trade action type. Perp: position-centric (\"OpenLong\", \"CloseShort\",\n\"Net\", ...). Spot: side from this row's perspective (\"Buy\" / \"Sell\").",
                  "example": "buy"
                },
                "asset_type": {
                  "$ref": "#/components/schemas/AssetType",
                  "description": "Which product this trade belongs to (\"perp\" or \"spot\"). Responses can\nmix products; this per-row tag lets clients demux."
                },
                "client_order_id": {
                  "type": "string",
                  "description": "Client-specified order ID",
                  "example": "client_order_abc"
                },
                "counter_party_account": {
                  "type": "string",
                  "description": "Counter party account on the other leg of the fill. For liquidation /\nADL / delisting fills this is the backstop liquidator. Empty string for\npre-V2 historical trades that did not carry counter party on-chain.",
                  "example": "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210"
                },
                "fee_amount": {
                  "type": "number",
                  "format": "double",
                  "description": "Fee paid by this row's account, normalized. Perp: always in the\ncollateral asset (USDC). Spot: charged in the asset this side\nRECEIVED (protocol + builder fee combined); see `fee_asset`."
                },
                "fee_asset": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "FA metadata address of the asset `fee_amount` is denominated in.\nSpot only (base asset for the buyer, quote for the seller); absent\nfor perp rows, where the fee is implicitly the collateral asset."
                },
                "is_profit": {
                  "type": "boolean",
                  "description": "Whether trade was profitable"
                },
                "is_rebate": {
                  "type": "boolean",
                  "description": "Whether trade received rebate"
                },
                "market": {
                  "type": "string",
                  "description": "Market identifier address",
                  "example": "0xmarket123456789abcdef"
                },
                "order_id": {
                  "type": "string",
                  "description": "Order ID associated with trade",
                  "example": "12345"
                },
                "price": {
                  "type": "number",
                  "format": "double",
                  "description": "Trade price",
                  "example": 50000.25
                },
                "realized_funding_amount": {
                  "type": "number",
                  "format": "double",
                  "description": "Realized funding amount in USDC\n- Negative value: trader PAID funding (e.g., long position with positive funding rate)\n- Positive value: trader RECEIVED funding (e.g., short position with positive funding rate)\n- Zero: no funding accrued",
                  "example": -15.5
                },
                "realized_pnl_amount": {
                  "type": "number",
                  "format": "double",
                  "description": "Realized PnL amount"
                },
                "size": {
                  "type": "number",
                  "format": "double",
                  "description": "Trade size",
                  "example": 100.5
                },
                "source": {
                  "type": "string",
                  "description": "Trade source (e.g., \"OrderFill\", \"MarginCall\", \"BackStopLiquidation\", \"ADL\", \"MarketDelisted\")",
                  "example": "OrderFill"
                },
                "trade_id": {
                  "type": "string",
                  "description": "Trade ID",
                  "example": "3647276"
                },
                "transaction_unix_ms": {
                  "type": "integer",
                  "format": "int64",
                  "description": "Transaction timestamp in milliseconds",
                  "example": 1634567890000
                },
                "transaction_version": {
                  "type": "integer",
                  "format": "int64",
                  "description": "Transaction version",
                  "example": 3647276285,
                  "minimum": 0
                }
              }
            },
            "description": "The items in the current page"
          },
          "total_count": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "The total number of items across all pages.\nOptional: history endpoints omit this field to avoid expensive COUNT(*) queries.",
            "minimum": 0
          }
        }
      },
      "PaginatedResponse_TwapDto": {
        "type": "object",
        "required": [
          "items"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "market",
                "is_buy",
                "order_id",
                "is_reduce_only",
                "start_unix_ms",
                "frequency_s",
                "duration_s",
                "orig_size",
                "remaining_size",
                "status",
                "client_order_id",
                "transaction_unix_ms",
                "transaction_version"
              ],
              "properties": {
                "client_order_id": {
                  "type": "string",
                  "example": "client_order_123"
                },
                "duration_s": {
                  "type": "integer",
                  "format": "int64",
                  "example": 300,
                  "minimum": 0
                },
                "frequency_s": {
                  "type": "integer",
                  "format": "int64",
                  "example": 30,
                  "minimum": 0
                },
                "is_buy": {
                  "type": "boolean",
                  "example": true
                },
                "is_reduce_only": {
                  "type": "boolean"
                },
                "market": {
                  "type": "string",
                  "example": "0xmarket123..."
                },
                "order_id": {
                  "type": "string"
                },
                "orig_size": {
                  "type": "number",
                  "format": "double"
                },
                "remaining_size": {
                  "type": "number",
                  "format": "double"
                },
                "start_unix_ms": {
                  "type": "integer",
                  "format": "int64",
                  "example": 1730841600000
                },
                "status": {
                  "type": "string"
                },
                "transaction_unix_ms": {
                  "type": "integer",
                  "format": "int64"
                },
                "transaction_version": {
                  "type": "integer",
                  "format": "int64",
                  "minimum": 0
                }
              }
            },
            "description": "The items in the current page"
          },
          "total_count": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "The total number of items across all pages.\nOptional: history endpoints omit this field to avoid expensive COUNT(*) queries.",
            "minimum": 0
          }
        }
      },
      "PaginatedResponse_VaultDto": {
        "type": "object",
        "required": [
          "items"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "vault_address",
                "vault_name",
                "vault_share_symbol",
                "status",
                "age_days",
                "num_managers"
              ],
              "properties": {
                "age_days": {
                  "type": "integer",
                  "format": "int64"
                },
                "all_time_return": {
                  "type": [
                    "number",
                    "null"
                  ],
                  "format": "double",
                  "description": "Share-price-based time-weighted return percentage since inception"
                },
                "apr": {
                  "type": [
                    "number",
                    "null"
                  ],
                  "format": "double",
                  "description": "Annualized percentage return (avg daily share-price yield × 365).\nNULL if vault has < 14 days of snapshot data."
                },
                "manager_equity": {
                  "type": [
                    "number",
                    "null"
                  ],
                  "format": "double"
                },
                "manager_stake": {
                  "type": [
                    "number",
                    "null"
                  ],
                  "format": "double"
                },
                "num_managers": {
                  "type": "integer",
                  "format": "int32"
                },
                "status": {
                  "type": "string"
                },
                "tvl": {
                  "type": [
                    "number",
                    "null"
                  ],
                  "format": "double"
                },
                "vault_address": {
                  "type": "string"
                },
                "vault_name": {
                  "type": "string"
                },
                "vault_share_symbol": {
                  "type": "string"
                }
              }
            },
            "description": "The items in the current page"
          },
          "total_count": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "The total number of items across all pages.\nOptional: history endpoints omit this field to avoid expensive COUNT(*) queries.",
            "minimum": 0
          }
        }
      },
      "PaginatedResponse_WithdrawQueueEntryDto": {
        "type": "object",
        "required": [
          "items"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "A single withdrawal queue event (Queued, Processed, or Cancelled).\n\nThe underlying table is an append-log: each state transition is a separate row keyed\nby `event_uid`. Unfiltered queries may return multiple rows for the same `request_id`\n(e.g., a Queued row and a Processed row). Clients should deduplicate by `request_id`,\nkeeping the terminal state (Processed or Cancelled) over Queued.",
              "required": [
                "user",
                "fungible_amount",
                "processed_amount",
                "request_id",
                "status",
                "timestamp_ms",
                "transaction_version"
              ],
              "properties": {
                "cancel_reason": {
                  "oneOf": [
                    {
                      "type": "null"
                    },
                    {
                      "$ref": "#/components/schemas/WithdrawCancelReason",
                      "description": "Reason the withdrawal was cancelled. Only present for Cancelled entries."
                    }
                  ]
                },
                "fungible_amount": {
                  "type": "number",
                  "format": "double",
                  "description": "Requested withdrawal amount, normalized by collateral decimals."
                },
                "market": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "The market address. Absent for non-market (cross-margin) withdrawals."
                },
                "processed_amount": {
                  "type": "number",
                  "format": "double",
                  "description": "Amount actually withdrawn. Equals `fungible_amount` for Processed entries, 0 otherwise."
                },
                "queued_at_ms": {
                  "type": [
                    "integer",
                    "null"
                  ],
                  "format": "int64",
                  "description": "Timestamp when the withdrawal was originally queued. Always present for Queued\nentries. For Processed/Cancelled entries, enriched from the corresponding Queued\nrow. HTTP responses enrich via same-page lookup + DB backfill; WebSocket updates\nonly enrich from the same batch, so this may be absent."
                },
                "recipient": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "The intended recipient address. The on-chain CancelledEvent omits this field,\nso it is enriched from the corresponding Queued row. HTTP responses enrich via\nsame-page lookup + DB backfill; WebSocket updates only enrich from the same batch."
                },
                "request_id": {
                  "type": "string"
                },
                "status": {
                  "$ref": "#/components/schemas/WithdrawQueueStatus"
                },
                "timestamp_ms": {
                  "type": "integer",
                  "format": "int64",
                  "description": "Timestamp of this specific event. For Processed entries this is the settlement\ntime; for Cancelled entries the cancellation time. See `queued_at_ms` for the\noriginal queue time."
                },
                "transaction_version": {
                  "type": "integer",
                  "format": "int64",
                  "minimum": 0
                },
                "user": {
                  "type": "string"
                }
              }
            },
            "description": "The items in the current page"
          },
          "total_count": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "The total number of items across all pages.\nOptional: history endpoints omit this field to avoid expensive COUNT(*) queries.",
            "minimum": 0
          }
        }
      },
      "PointsLeaderboardEntryDto": {
        "type": "object",
        "required": [
          "rank",
          "owner",
          "total_amps",
          "realized_pnl",
          "referral_amps",
          "vault_amps",
          "streak_amps",
          "bonus_amps"
        ],
        "properties": {
          "bonus_amps": {
            "type": "number",
            "format": "double"
          },
          "owner": {
            "type": "string"
          },
          "rank": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "realized_pnl": {
            "type": "number",
            "format": "double"
          },
          "referral_amps": {
            "type": "number",
            "format": "double"
          },
          "streak_amps": {
            "type": "number",
            "format": "double"
          },
          "total_amps": {
            "type": "number",
            "format": "double"
          },
          "vault_amps": {
            "type": "number",
            "format": "double"
          }
        }
      },
      "PointsLeaderboardSortKey": {
        "type": "string",
        "enum": [
          "total_amps",
          "realized_pnl"
        ]
      },
      "PointsLeaderboardTier": {
        "type": "string",
        "description": "Tier filter for points leaderboard",
        "enum": [
          "top20",
          "diamond",
          "doublePlatinum",
          "gold"
        ]
      },
      "PortfolioChartDataType": {
        "type": "string",
        "enum": [
          "pnl",
          "account_value"
        ]
      },
      "PortfolioPointDto": {
        "type": "object",
        "required": [
          "timestamp",
          "data_points"
        ],
        "properties": {
          "data_points": {
            "type": "number",
            "format": "double"
          },
          "spot_pnl": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Spot PnL (unrealized + realized) at this snapshot. A sidecar like\n`spot_value`, so `data_points` stays perp-only and the caller composes\nthe combined cut. `0` for snapshots predating the columns (NULL in\nClickHouse); None for the account_value data_type."
          },
          "spot_value": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Spot holdings value (USD) at this snapshot, from spot_value_snapshots.\nNOT included in `data_points`: `data_points` stays the canonical\nperp Portfolio Value (perp equity + free vault equity) because vault\nNAV, the leaderboard, and the DLP oracle bind to that meaning. The\n\"Perps + Spot\" cut is `data_points + spot_value`, composed by the\ncaller under a distinct name. 0 when no spot value is recorded at\nthis timestamp (including all history before the spot recorder\ndeployed — same JOIN-miss semantics as `vault_equity`); None for\nthe PnL data_type."
          },
          "timestamp": {
            "type": "integer",
            "format": "int64"
          },
          "vault_equity": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Vault equity: user's proportional share of vault NAV(s).\nNone for users with no vault deposits, or for PnL data_type."
          }
        }
      },
      "PositionDto": {
        "type": "object",
        "required": [
          "market",
          "user",
          "size",
          "user_leverage",
          "entry_price",
          "is_isolated",
          "is_deleted",
          "unrealized_funding",
          "estimated_liquidation_price",
          "transaction_version",
          "has_fixed_sized_tpsls"
        ],
        "properties": {
          "entry_price": {
            "type": "number",
            "format": "double"
          },
          "estimated_liquidation_price": {
            "type": "number",
            "format": "double"
          },
          "has_fixed_sized_tpsls": {
            "type": "boolean"
          },
          "is_deleted": {
            "type": "boolean"
          },
          "is_isolated": {
            "type": "boolean"
          },
          "market": {
            "type": "string"
          },
          "size": {
            "type": "number",
            "format": "double"
          },
          "sl_limit_price": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "sl_order_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "sl_trigger_price": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "tp_limit_price": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "tp_order_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "tp_trigger_price": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "transaction_version": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "unrealized_funding": {
            "type": "number",
            "format": "double"
          },
          "user": {
            "type": "string"
          },
          "user_leverage": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          }
        }
      },
      "PredepositRewardsResponse": {
        "type": "object",
        "description": "S0 predeposit rewards response DTO",
        "required": [
          "account",
          "usdc_reward"
        ],
        "properties": {
          "account": {
            "type": "string",
            "description": "User's Aptos address"
          },
          "usdc_reward": {
            "type": "number",
            "format": "double",
            "description": "USDC reward amount for Season 0 predeposit"
          }
        }
      },
      "PriceDto": {
        "type": "object",
        "description": "Perp-only: spot markets deliberately have no price rows — spot has no\noracle, mark price, or funding, and clients derive the mid from the\n`depth` WS topic (top-of-book `best_bid`/`best_ask` ride on every\ndepth update).",
        "required": [
          "market",
          "oracle_px",
          "mark_px",
          "mid_px",
          "funding_rate_bps",
          "is_funding_positive",
          "funding_period_s",
          "transaction_unix_ms",
          "open_interest"
        ],
        "properties": {
          "funding_period_s": {
            "type": "integer",
            "format": "int64",
            "description": "Funding period duration in seconds. 0 = continuous funding, >0 = periodic funding.",
            "minimum": 0
          },
          "funding_rate_bps": {
            "type": "number",
            "format": "double",
            "description": "Hourly funding rate in basis points (1 bps = 0.01%).\nOn-chain value uses RATE_SIZE_MULTIPLIER (1,000,000); divided by 100.0\nto convert to basis points while preserving sub-bps precision."
          },
          "is_funding_positive": {
            "type": "boolean"
          },
          "mark_px": {
            "type": "number",
            "format": "double"
          },
          "market": {
            "type": "string",
            "example": "0xmarket123..."
          },
          "mid_px": {
            "type": "number",
            "format": "double"
          },
          "open_interest": {
            "type": "number",
            "format": "double"
          },
          "oracle_px": {
            "type": "number",
            "format": "double"
          },
          "transaction_unix_ms": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "ProductFeeStateDto": {
        "type": "object",
        "description": "Per-product (perp or spot) fee state: the product's own rate ladder,\nthe user's effective rates at the shared cross-product tier, and the\nproduct's raw (unweighted) volume history.",
        "required": [
          "fee_tier",
          "fee_schedule",
          "user_taker_rate",
          "user_maker_rate",
          "daily_user_volume",
          "total_window_volume_usd",
          "active_referral_discount"
        ],
        "properties": {
          "active_referral_discount": {
            "type": "number",
            "format": "double",
            "description": "Product-specific active referral discount (0.0 for spot — no referral program)"
          },
          "daily_user_volume": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DailyUserVolumeDto"
            },
            "description": "This product's own daily volume history for the fee window — raw USD, NOT weighted"
          },
          "fee_schedule": {
            "$ref": "#/components/schemas/FeeScheduleDto",
            "description": "Rate ladder for THIS product (spot bps differ from perp at every tier)"
          },
          "fee_tier": {
            "type": "integer",
            "format": "int64",
            "description": "This product's fee tier index (0 = base tier). Since `unified_fees_config`\nBOTH products resolve their tier from the same weighted cross-product\nvolume against one shared threshold ladder, so `perp.fee_tier` and\n`spot.fee_tier` are currently always equal. They remain separate fields\nso that a future per-product ladder is not a breaking change; read the\none belonging to the product you are pricing rather than assuming.",
            "minimum": 0
          },
          "total_window_volume_usd": {
            "type": "string",
            "description": "Sum of `daily_user_volume` over the window (USD, whole-dollar integer string)"
          },
          "user_maker_rate": {
            "type": "number",
            "format": "double",
            "description": "Effective maker rate for this product after any product-specific discount"
          },
          "user_taker_rate": {
            "type": "number",
            "format": "double",
            "description": "Effective taker rate for this product after any product-specific discount"
          }
        }
      },
      "ProtectedTrialsResponse": {
        "type": "object",
        "required": [
          "account",
          "active_trials",
          "history",
          "history_total_count"
        ],
        "properties": {
          "account": {
            "type": "string"
          },
          "active_trial": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/TrialDto",
                "description": "Compat slot: the active trial in the requested campaign, or the most\nrecent across campaigns."
              }
            ]
          },
          "active_trials": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TrialDto"
            },
            "description": "All active trials across campaigns."
          },
          "history": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TrialDto"
            }
          },
          "history_total_count": {
            "type": "integer",
            "format": "int32",
            "description": "Total terminal history rows matching the filters across all pages;\nunknown-settle_reason rows are excluded from both the page and this count.",
            "minimum": 0
          }
        }
      },
      "PublicVaultDto": {
        "type": "object",
        "required": [
          "address",
          "name",
          "manager",
          "status",
          "created_at"
        ],
        "properties": {
          "address": {
            "type": "string"
          },
          "all_time_pnl": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "all_time_return": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "apr": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Annualized percentage return (avg daily share-price yield × 365).\nNULL if vault has < 14 days of snapshot data."
          },
          "average_leverage": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "created_at": {
            "type": "integer",
            "format": "int64"
          },
          "depositors": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "lockdown_period_s": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "Lockdown period in seconds. Contributors cannot redeem until this period elapses after deposit.\nCan be 0 (no lockdown) up to 7 days (604800 seconds).",
            "example": 259200,
            "minimum": 0
          },
          "manager": {
            "type": "string"
          },
          "manager_cash_pct": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Manager's current cash position as percentage of total account value (point-in-time, not average)"
          },
          "max_drawdown": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "name": {
            "type": "string"
          },
          "net_deposits": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Net deposits (total contributions - total settled redemptions) in USDC.\nUsed to verify all_time_return and display context (e.g., \"X% return on $Y invested\").",
            "example": 30277044.96
          },
          "past_month_return": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "perp_equity": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "pnl_90d": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "profit_share": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "sharpe_ratio": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "social_links": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            }
          },
          "status": {
            "type": "string"
          },
          "tvl": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "vault_type": {
            "type": [
              "string",
              "null"
            ]
          },
          "volume": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "volume_30d": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "weekly_win_rate_12w": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          }
        }
      },
      "PublicVaultsResponse": {
        "type": "object",
        "required": [
          "items",
          "total_count",
          "total_value_locked",
          "total_volume"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicVaultDto"
            }
          },
          "total_count": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "total_value_locked": {
            "type": "number",
            "format": "double",
            "description": "Total value locked across all filtered vaults"
          },
          "total_volume": {
            "type": "number",
            "format": "double",
            "description": "Total all-time trading volume across all filtered vaults"
          }
        }
      },
      "RecordTransferRequestDto": {
        "type": "object",
        "description": "Request body for POST /api/v1/transfers.\n\nPosted by the web client after a deposit or withdrawal confirms, to capture\nattribution metadata (how/where the user funded) that the chain can't see.\n`transfer_id` is a client-minted UUID used as the dedup key.",
        "required": [
          "account",
          "transfer_id",
          "direction",
          "method",
          "amount"
        ],
        "properties": {
          "account": {
            "type": "string"
          },
          "amount": {
            "type": "number",
            "format": "double"
          },
          "asset": {
            "type": [
              "string",
              "null"
            ]
          },
          "broker": {
            "type": [
              "string",
              "null"
            ]
          },
          "direction": {
            "type": "string",
            "description": "'deposit' | 'withdraw'"
          },
          "method": {
            "type": "string",
            "description": "'direct' | 'mesh' | 'bridge'"
          },
          "origin_chain": {
            "type": [
              "string",
              "null"
            ]
          },
          "transfer_id": {
            "type": "string"
          },
          "tx_hash": {
            "type": [
              "string",
              "null"
            ]
          },
          "wallet_provider": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "RecordTransferResponseDto": {
        "type": "object",
        "required": [
          "success"
        ],
        "properties": {
          "success": {
            "type": "boolean"
          }
        }
      },
      "RedeemReferralRequestDto": {
        "type": "object",
        "description": "Request body for POST /api/v1/referrals/redeem",
        "required": [
          "referral_code",
          "account"
        ],
        "properties": {
          "account": {
            "type": "string",
            "description": "The wallet address redeeming the code (not a subaccount address)"
          },
          "referral_code": {
            "type": "string",
            "description": "The referral code to redeem"
          }
        }
      },
      "RedeemReferralResponseDto": {
        "type": "object",
        "description": "Response for POST /api/v1/referrals/redeem",
        "required": [
          "referral_code",
          "account"
        ],
        "properties": {
          "account": {
            "type": "string",
            "description": "The wallet address that redeemed the code (not a subaccount address)"
          },
          "referral_code": {
            "type": "string",
            "description": "The referral code that was redeemed"
          }
        }
      },
      "ReferralActivityClient": {
        "type": "object",
        "description": "One direct (L1) referral's activity in the window, plus the L2 clients it referred.\n\nLevels are nested rather than interleaved: an L2 client only ever reaches an affiliate\nthrough one of its L1s, so a flat list forces the reader to guess whose downline a row\nbelongs to.",
        "required": [
          "client",
          "level",
          "trades",
          "taker_volume_usd",
          "maker_volume_usd",
          "top_market",
          "commission_usd",
          "traded",
          "sub_clients",
          "sub_client_count"
        ],
        "properties": {
          "client": {
            "type": "string",
            "description": "Full owner address, matching `/affiliates/earnings` — an affiliate already sees\nits own referees unmasked there, so masking only here would be inconsistent."
          },
          "commission_usd": {
            "type": "number",
            "format": "double",
            "description": "Commission this client generated on its own trading, at the L1 rate of each day.\nExcludes what its L2s generated — those carry their own figures."
          },
          "level": {
            "type": "integer",
            "format": "int32",
            "description": "Always 1: this list holds direct referrals, and their L2s hang off `sub_clients`.",
            "minimum": 0
          },
          "maker_volume_usd": {
            "type": "number",
            "format": "double"
          },
          "sub_client_count": {
            "type": "integer",
            "format": "int64",
            "description": "L2 clients that traded in the window, counted before the 25-row cap.",
            "minimum": 0
          },
          "sub_clients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReferralActivitySubClient"
            },
            "description": "This L1's own referred clients that traded in the window, busiest first, capped at\n`sub_client_count`'s first 25 rows."
          },
          "taker_volume_usd": {
            "type": "number",
            "format": "double"
          },
          "top_market": {
            "type": "string",
            "description": "Market carrying the most of this client's volume; empty when unresolved."
          },
          "traded": {
            "type": "boolean",
            "description": "False when this L1 did not trade in the window and is listed only as the parent of\nL2s that did. Its own columns are then zero, which is a different claim from\n\"traded zero volume\" and should not be rendered as a figure."
          },
          "trades": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          }
        }
      },
      "ReferralActivityLevel": {
        "type": "object",
        "description": "Window totals for one referral level.",
        "required": [
          "level",
          "clients",
          "trades",
          "taker_volume_usd",
          "maker_volume_usd",
          "commission_usd"
        ],
        "properties": {
          "clients": {
            "type": "integer",
            "format": "int64",
            "description": "Clients who traded in the window",
            "minimum": 0
          },
          "commission_usd": {
            "type": "number",
            "format": "double",
            "description": "Commission this level generated in the window, at each day's own stamped rate and\npenalty. Zero when the affiliate has no accrual rows — which is the state before the\nledger runs, not a claim that the level earned nothing."
          },
          "level": {
            "type": "integer",
            "format": "int32",
            "description": "1 = direct referral, 2 = sub-affiliate's referral",
            "minimum": 0
          },
          "maker_volume_usd": {
            "type": "number",
            "format": "double"
          },
          "taker_volume_usd": {
            "type": "number",
            "format": "double"
          },
          "trades": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          }
        }
      },
      "ReferralActivityResponse": {
        "type": "object",
        "description": "Referral activity: per-level totals plus a page of direct referrals.",
        "required": [
          "referrer_account",
          "summary",
          "clients",
          "total_count"
        ],
        "properties": {
          "clients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReferralActivityClient"
            },
            "description": "A page of L1 clients, each carrying its own L2s"
          },
          "referrer_account": {
            "type": "string"
          },
          "summary": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReferralActivityLevel"
            },
            "description": "Levels that traded in the window, level 1 first"
          },
          "total_count": {
            "type": "integer",
            "format": "int64",
            "description": "L1 rows the window holds, for pagination. Counts parents, not clients: an L1 that\nonly appears because its L2s traded still occupies a row.",
            "minimum": 0
          }
        }
      },
      "ReferralActivitySubClient": {
        "type": "object",
        "description": "One L2 client's activity, nested under the L1 that referred it.",
        "required": [
          "client",
          "trades",
          "taker_volume_usd",
          "maker_volume_usd",
          "top_market",
          "commission_usd"
        ],
        "properties": {
          "client": {
            "type": "string",
            "description": "Full owner address, matching the L1 rows."
          },
          "commission_usd": {
            "type": "number",
            "format": "double",
            "description": "Commission this client generated, at the L2 override rate of each day."
          },
          "maker_volume_usd": {
            "type": "number",
            "format": "double"
          },
          "taker_volume_usd": {
            "type": "number",
            "format": "double"
          },
          "top_market": {
            "type": "string",
            "description": "Market carrying the most of this client's volume; empty when unresolved."
          },
          "trades": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          }
        }
      },
      "ReferralClient": {
        "type": "object",
        "description": "One referred client.",
        "required": [
          "client",
          "source_code",
          "joined_unix_ms",
          "last_trade_unix_ms",
          "trades",
          "taker_volume_usd",
          "maker_volume_usd",
          "amps_all_time",
          "commission_usd",
          "segment"
        ],
        "properties": {
          "amps_all_time": {
            "type": "number",
            "format": "double",
            "description": "All-time Amps from the canonical audit table, every bucket, post-clawback"
          },
          "client": {
            "type": "string",
            "description": "Full owner address, matching `/affiliates/earnings`"
          },
          "commission_usd": {
            "type": "number",
            "format": "double",
            "description": "Commission this client generated for the affiliate inside the window, at each day's own\nstamped rate and penalty. Excludes anything this client's own referrals generated — that\nis the L2 override and belongs to the sub-affiliates screen."
          },
          "joined_unix_ms": {
            "type": "integer",
            "format": "int64"
          },
          "last_trade_unix_ms": {
            "type": "integer",
            "format": "int64",
            "description": "0 when the client has never traded"
          },
          "maker_volume_usd": {
            "type": "number",
            "format": "double"
          },
          "segment": {
            "$ref": "#/components/schemas/ClientSegment"
          },
          "source_code": {
            "type": "string",
            "description": "Code this client redeemed"
          },
          "taker_volume_usd": {
            "type": "number",
            "format": "double"
          },
          "trades": {
            "type": "integer",
            "format": "int64",
            "description": "Trades inside the requested window",
            "minimum": 0
          }
        }
      },
      "ReferralClientsResponse": {
        "type": "object",
        "required": [
          "referrer_account",
          "segments",
          "clients",
          "total_count"
        ],
        "properties": {
          "clients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReferralClient"
            }
          },
          "referrer_account": {
            "type": "string"
          },
          "segments": {
            "$ref": "#/components/schemas/ClientSegments"
          },
          "total_count": {
            "type": "integer",
            "format": "int64",
            "description": "Clients matching the current filter, for pagination",
            "minimum": 0
          }
        }
      },
      "ReferralCodeSource": {
        "type": "string",
        "description": "How a referral code was created",
        "enum": [
          "admin",
          "auto",
          "reusable",
          "unknown"
        ]
      },
      "ReferralCodeValidationDto": {
        "type": "object",
        "description": "Response for GET /api/v1/referrals/code/{code} — pre-wallet-connect validation",
        "required": [
          "referral_code",
          "is_valid",
          "is_active"
        ],
        "properties": {
          "is_active": {
            "type": "boolean",
            "description": "Whether the code can still accept new referrals"
          },
          "is_valid": {
            "type": "boolean",
            "description": "Whether the code exists"
          },
          "referral_code": {
            "type": "string",
            "description": "The referral code that was checked"
          }
        }
      },
      "ReferralFees": {
        "type": "object",
        "description": "Fee revenue a referrer's network generated over the window.\n\nCarries no commission figure: the rate is not signed off and no accrual ledger exists.\nWhat it does carry is the basis such a figure would be computed from.",
        "required": [
          "net_fees_usd",
          "builder_payouts_usd",
          "commission_basis_usd",
          "days"
        ],
        "properties": {
          "builder_payouts_usd": {
            "type": "number",
            "format": "double",
            "description": "Builder kickbacks owed on those same fills, in USD. Deducted before commission."
          },
          "commission_basis_usd": {
            "type": "number",
            "format": "double",
            "description": "`net_fees_usd - builder_payouts_usd`"
          },
          "days": {
            "type": "integer",
            "format": "int64",
            "description": "The window actually used, after clamping",
            "minimum": 0
          },
          "net_fees_usd": {
            "type": "number",
            "format": "double",
            "description": "Fees the network paid minus rebates it received, in USD. Can go negative on a\nnet-rebated network."
          }
        }
      },
      "ReferralFunnelDay": {
        "type": "object",
        "description": "One UTC day of the referral funnel.",
        "required": [
          "day_start_unix_ms",
          "sign_ups",
          "first_deposits"
        ],
        "properties": {
          "day_start_unix_ms": {
            "type": "integer",
            "format": "int64",
            "description": "UTC midnight of the day"
          },
          "first_deposits": {
            "type": "integer",
            "format": "int64",
            "description": "Referrals whose very first collateral deposit landed on this day",
            "minimum": 0
          },
          "sign_ups": {
            "type": "integer",
            "format": "int64",
            "description": "Referrals that redeemed one of the referrer's codes on this day",
            "minimum": 0
          }
        }
      },
      "ReferralLevel": {
        "type": "string",
        "description": "Referral level in the affiliate tree.",
        "enum": [
          "L1",
          "L2"
        ]
      },
      "ReferredVolumeDay": {
        "type": "object",
        "description": "One UTC day of volume traded by a referrer's network.",
        "required": [
          "day_start_unix_ms",
          "volume_usd",
          "taker_volume_usd",
          "maker_volume_usd",
          "active_referrals"
        ],
        "properties": {
          "active_referrals": {
            "type": "integer",
            "format": "int64",
            "description": "Referred subaccounts that traded on this day",
            "minimum": 0
          },
          "day_start_unix_ms": {
            "type": "integer",
            "format": "int64",
            "description": "UTC midnight of the day"
          },
          "maker_volume_usd": {
            "type": "number",
            "format": "double"
          },
          "taker_volume_usd": {
            "type": "number",
            "format": "double"
          },
          "volume_usd": {
            "type": "number",
            "format": "double",
            "description": "Both-sides notional in USD"
          }
        }
      },
      "ReferrerStatsDto": {
        "type": "object",
        "description": "Referrer statistics — aggregate stats for a referrer account",
        "required": [
          "referrer_account",
          "total_referrals",
          "total_codes_created",
          "is_affiliate",
          "codes",
          "volume_threshold_met"
        ],
        "properties": {
          "codes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of referral codes visible to this referrer.\nNon-affiliate referrers must meet the volume threshold to see their codes."
          },
          "is_affiliate": {
            "type": "boolean",
            "description": "Whether this referrer has any affiliate-designated codes.\nAffiliates always see all their codes regardless of trade volume."
          },
          "referrer_account": {
            "type": "string",
            "description": "The referrer's wallet address"
          },
          "total_codes_created": {
            "type": "integer",
            "format": "int64",
            "description": "Total number of referral codes created by this referrer.\nAlways accurate regardless of code visibility (non-affiliates below the\nvolume threshold will see an empty `codes` array but this still reflects\nthe true count).",
            "minimum": 0
          },
          "total_referrals": {
            "type": "integer",
            "format": "int64",
            "description": "Total number of users referred",
            "minimum": 0
          },
          "volume_threshold_met": {
            "type": "boolean",
            "description": "Whether the account meets the minimum trade volume threshold\nto see non-affiliate referral codes"
          }
        }
      },
      "SecondaryCollateralDto": {
        "type": "object",
        "description": "Secondary (non-USDC) collateral held in cross margin.",
        "required": [
          "asset_type",
          "amount",
          "value_in_usdc",
          "nav_per_unit",
          "haircut_bps",
          "withdrawable_amount"
        ],
        "properties": {
          "amount": {
            "type": "number",
            "format": "double",
            "description": "Raw balance normalized to human units (balance / 10^decimals).",
            "example": 150.0
          },
          "asset_type": {
            "type": "string",
            "description": "On-chain asset type address (e.g., DLP fungible asset address).",
            "example": "0x1234..."
          },
          "haircut_bps": {
            "type": "integer",
            "format": "int64",
            "description": "Haircut applied to the oracle price for margin purposes (in basis points).",
            "example": 500,
            "minimum": 0
          },
          "nav_per_unit": {
            "type": "number",
            "format": "double",
            "description": "NAV per unit in USDC terms (oracle price / 10^collateral_decimals).",
            "example": 1.05
          },
          "value_in_usdc": {
            "type": "number",
            "format": "double",
            "description": "USDC-equivalent value after applying the haircut.\nFormula: amount * (nav_per_unit * (10000 - haircut_bps) / 10000).",
            "example": 142.5
          },
          "withdrawable_amount": {
            "type": "number",
            "format": "double",
            "description": "Maximum amount of this secondary asset that can be withdrawn without\nviolating margin requirements.",
            "example": 100.0
          }
        }
      },
      "SettleReason": {
        "type": "string",
        "description": "Why a trial closed. Chain values 0-5 mirror `protected_trial.move` settle-reason\nconstants; `AdminReset` is synthetic (reset rows only) and is never produced\nby [`SettleReason::parse_chain`]. `SweptAfterStall` (5) marks an organic\nstalled trial drained by the sweep tail with funds intact; `AdminForced`\nmarks admin-origin residual settles.",
        "enum": [
          "ExpiredClean",
          "LiquidatedEmpty",
          "PartialLoss",
          "NeverFilled",
          "AdminForced",
          "SweptAfterStall",
          "AdminReset"
        ]
      },
      "SideFilter": {
        "type": "string",
        "description": "Order side filter: buy or sell. Product-independent: a buy is a bid on\nboth venues, whether or not it opens a perp long.\nFor perp orders, maps to the `is_buy` column; for spot orders, `is_bid`.\nFor perp trades/funding, maps to `action IN ('OpenLong','CloseShort')` (buy)\nor `action IN ('CloseLong','OpenShort')` (sell); for spot trades, to\n`is_taker_bid` resolved against whether the account is the taker or maker.",
        "enum": [
          "buy",
          "sell"
        ]
      },
      "SortDir": {
        "type": "string",
        "enum": [
          "ASC",
          "DESC"
        ]
      },
      "SpotAssetContextDto": {
        "type": "object",
        "description": "24h stats + current price snapshot for one spot market — the spot\ncounterpart of [`crate::asset_context::AssetContextDto`], with a\nsubset-shaped schema: shared-core price/volume fields plus spot extras\n(asset addresses, decimals); no perp fields (funding/OI/mark do not\nexist for spot), no null-because-inapplicable.",
        "required": [
          "market_addr",
          "name",
          "ticker_id",
          "base_asset_addr",
          "quote_asset_addr",
          "base_decimals",
          "quote_decimals",
          "volume_24h_base",
          "volume_24h_quote",
          "timestamp_unix_ms"
        ],
        "properties": {
          "base_asset_addr": {
            "type": "string",
            "description": "Fungible-asset metadata addresses (\"contract addresses\")."
          },
          "base_decimals": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "high_24h": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "last_price": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Most recent fill price in the last 24h; null if no trade in the window."
          },
          "low_24h": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "market_addr": {
            "type": "string",
            "example": "0xmarket123..."
          },
          "mid": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "(best_bid + best_ask) / 2 from the live book; null unless both sides\nhave resting liquidity."
          },
          "name": {
            "type": "string",
            "description": "Canonical market name, e.g. \"APT/USDC\"."
          },
          "prev_day_price": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Price of the last trade at or before now-24h (bounded 7d lookback);\nnull for markets that never traded before the boundary. 24h change =\n(last_price - prev_day_price) / prev_day_price, client-derived."
          },
          "quote_asset_addr": {
            "type": "string"
          },
          "quote_decimals": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "ticker_id": {
            "type": "string",
            "description": "Display ticker string derived from the spot market name. This is\nresponse metadata; use `market_addr` for requests."
          },
          "timestamp_unix_ms": {
            "type": "integer",
            "format": "int64",
            "description": "Server timestamp the snapshot was computed at (unix ms)."
          },
          "volume_24h_base": {
            "type": "number",
            "format": "double",
            "description": "Base units traded in the last 24h, human-readable."
          },
          "volume_24h_quote": {
            "type": "number",
            "format": "double",
            "description": "Quote units traded in the last 24h, human-readable."
          }
        }
      },
      "SpotInFlightOrderDto": {
        "type": "object",
        "required": [
          "market_addr",
          "order_id",
          "is_bid",
          "reserved_asset",
          "reserved_amount",
          "reserved_usd_value"
        ],
        "properties": {
          "is_bid": {
            "type": "boolean",
            "example": true
          },
          "market_addr": {
            "type": "string",
            "example": "0x26f1dd..."
          },
          "order_id": {
            "type": "string",
            "description": "Numeric on-chain order id for regular orders. Bulk-order ladders are\nfolded into ONE aggregate entry per (market, side) whose `order_id` is\nthe literal string `\"bulk\"` ([`BULK_AGGREGATE_ORDER_ID`]); clients\nmust not parse it as a number or use it for cancellation.",
            "example": "1234"
          },
          "reserved_amount": {
            "type": "number",
            "format": "double",
            "description": "Reserved amount in human units.",
            "example": 500.0
          },
          "reserved_asset": {
            "type": "string",
            "description": "FA metadata address for the reserved asset (quote for bids, base for asks)."
          },
          "reserved_usd_value": {
            "type": "number",
            "format": "double",
            "description": "USDC-equivalent value at current mark.",
            "example": 500.0
          }
        }
      },
      "SpotMetricsDto": {
        "type": "object",
        "description": "Aggregate spot trading metrics for a subaccount, summed across all assets.\nFees are split per side using the on-chain settlement's re-keying (for a\ntaker bid, `base_fee` is the taker's fee and `quote_fee` the maker's;\nreversed on asks — see `spot_fees_manager::deduct_and_collect`). Realized\nPnL uses lifetime-weighted-average cost basis and is exact when the user\nonly accumulates + fully liquidates each position; small drift otherwise\n(see `spot_account_asset_stats_latest.sql`).",
        "required": [
          "cumulative_volume_usd",
          "cumulative_taker_fees_usd",
          "cumulative_maker_fees_usd",
          "cumulative_realized_pnl_usd"
        ],
        "properties": {
          "cumulative_maker_fees_usd": {
            "type": "number",
            "format": "double",
            "description": "Cumulative fees paid on fills where this account was the maker, USD.",
            "example": 4.1
          },
          "cumulative_realized_pnl_usd": {
            "type": "number",
            "format": "double",
            "description": "Cumulative realized PnL from spot sells, USD, GROSS of fees (they render\nbeside this in their own row). Weighted-average basis, prorated to the\nshare of units sold that had a known cost.",
            "example": 142.55
          },
          "cumulative_taker_fees_usd": {
            "type": "number",
            "format": "double",
            "description": "Cumulative fees paid on fills where this account was the taker, USD.",
            "example": 12.29
          },
          "cumulative_volume_usd": {
            "type": "number",
            "format": "double",
            "description": "Cumulative spot volume traded (both taker and maker sides), USD.",
            "example": 24580.1
          }
        }
      },
      "SpotOverviewDto": {
        "type": "object",
        "description": "Per-subaccount spot inventory + open-order reservations.",
        "required": [
          "positions",
          "total_usd",
          "in_flight_orders",
          "total_unrealized_pnl_usd"
        ],
        "properties": {
          "in_flight_orders": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SpotInFlightOrderDto"
            },
            "description": "One row per open spot order for this subaccount. `reserved_asset` is the\nside that the user must have paid to enter the order (USDC for bids, base\nfor asks). USD-equivalent computed at current mark."
          },
          "metrics": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/SpotMetricsDto",
                "description": "Aggregate spot trading metrics for this subaccount: volume, fees, and\nrealized PnL summed across all spot markets. `None` when the subaccount\nhas never traded spot (or the stats MV hasn't materialized yet)."
              }
            ]
          },
          "positions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SpotPositionDto"
            },
            "description": "Assets held in this subaccount's PFS (base assets + USDC). Each row is\none asset held; balance × mark_price = usd_value. Mark resolution per\nmarket follows the shared spot rule (all_spot_mids / asset_contexts /\nspot_value_snapshots): mid of a TWO-SIDED book, else last trade price,\nelse 0. USDC is marked 1.0 by definition."
          },
          "total_unrealized_pnl_usd": {
            "type": "number",
            "format": "double",
            "description": "Unrealized PnL across everything the subaccount controls: PFS holdings\nplus base escrowed behind resting orders. Not the sum of\n`positions[].unrealized_pnl_usd`, which is PFS-only.\n\nBid escrow, PFS USDC, and units with no on-book cost all contribute 0.",
            "example": 4.75
          },
          "total_usd": {
            "type": "number",
            "format": "double",
            "description": "USDC-equivalent value of every position + reserved amount in open spot orders.",
            "example": 872.3
          }
        }
      },
      "SpotPositionDto": {
        "type": "object",
        "required": [
          "asset_addr",
          "asset_symbol",
          "amount",
          "usd_value",
          "entry_notional_usd",
          "unrealized_pnl_usd"
        ],
        "properties": {
          "amount": {
            "type": "number",
            "format": "double",
            "description": "Balance normalized to human units (raw_balance / 10^decimals).",
            "example": 10.0
          },
          "asset_addr": {
            "type": "string",
            "description": "FA metadata address for the held asset.",
            "example": "0x000000000000000000000000000000000000000000000000000000000000000a"
          },
          "asset_symbol": {
            "type": "string",
            "description": "Human-readable symbol from the spot market (e.g., \"APT\"). Best-effort from\n`spot_markets` metadata; empty when the asset isn't currently a base of any\nregistered market.",
            "example": "APT"
          },
          "entry_notional_usd": {
            "type": "number",
            "format": "double",
            "description": "Weighted-average cost of the units in this position that were actually\nBOUGHT. Analogue of Hyperliquid `spotClearinghouseState.entryNtl`.\n`0.0` when the asset carries no on-book fills (e.g. an external FA\ntransfer) — the stats MV only sees fills.\n\nCovers `amount` only when the account still holds no more than it\nbought. Beyond that the excess arrived by transfer at an unrecorded\nprice, and the costed pool is shared with base escrowed behind resting\nasks, so this is the PFS share of it.",
            "example": 82.4
          },
          "unrealized_pnl_usd": {
            "type": "number",
            "format": "double",
            "description": "Unrealized PnL on the costed units only. Negative when mark < avg cost.\n\nNOT `usd_value - entry_notional_usd`: `usd_value` marks every held unit\nwhile this covers only the ones with a known cost. The two agree only\nfor a fully-costed position.",
            "example": 4.75
          },
          "usd_value": {
            "type": "number",
            "format": "double",
            "description": "amount × current mark price.",
            "example": 87.15
          }
        }
      },
      "SubAffiliate": {
        "type": "object",
        "description": "One direct referral who went on to refer others.",
        "required": [
          "sub_affiliate",
          "joined_unix_ms",
          "l2_clients",
          "network_volume_usd",
          "override_usd"
        ],
        "properties": {
          "joined_unix_ms": {
            "type": "integer",
            "format": "int64",
            "description": "When this sub-affiliate redeemed the referrer's code"
          },
          "l2_clients": {
            "type": "integer",
            "format": "int64",
            "description": "Distinct clients this sub-affiliate has referred",
            "minimum": 0
          },
          "network_volume_usd": {
            "type": "number",
            "format": "double",
            "description": "Both-sides notional those clients traded inside the window"
          },
          "override_usd": {
            "type": "number",
            "format": "double",
            "description": "The L2 override this sub-affiliate's downline generated, at each day's own rate and\npenalty. Zero when the accrual ledger has no rows — the state before it runs, not a\nclaim that the downline earned nothing."
          },
          "sub_affiliate": {
            "type": "string",
            "description": "Full owner address, matching `/affiliates/earnings`"
          }
        }
      },
      "SubAffiliatesResponse": {
        "type": "object",
        "required": [
          "referrer_account",
          "summary",
          "sub_affiliates",
          "total_count"
        ],
        "properties": {
          "referrer_account": {
            "type": "string"
          },
          "sub_affiliates": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SubAffiliate"
            }
          },
          "summary": {
            "$ref": "#/components/schemas/SubAffiliatesSummary"
          },
          "total_count": {
            "type": "integer",
            "format": "int64",
            "description": "Sub-affiliates in total, for pagination",
            "minimum": 0
          }
        }
      },
      "SubAffiliatesSummary": {
        "type": "object",
        "description": "Totals across every sub-affiliate, independent of the page.",
        "required": [
          "sub_affiliates",
          "l2_clients",
          "network_volume_usd",
          "override_usd"
        ],
        "properties": {
          "l2_clients": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "network_volume_usd": {
            "type": "number",
            "format": "double"
          },
          "override_usd": {
            "type": "number",
            "format": "double",
            "description": "The L2 override this sub-affiliate's downline generated, at each day's own rate and\npenalty. Zero when the accrual ledger has no rows — the state before it runs, not a\nclaim that the downline earned nothing."
          },
          "sub_affiliates": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          }
        }
      },
      "SubaccountDto": {
        "type": "object",
        "required": [
          "subaccount_address",
          "primary_account_address",
          "is_primary",
          "is_active"
        ],
        "properties": {
          "custom_label": {
            "type": [
              "string",
              "null"
            ],
            "example": "My Subaccount"
          },
          "is_active": {
            "type": "boolean"
          },
          "is_primary": {
            "type": "boolean",
            "example": true
          },
          "primary_account_address": {
            "type": "string",
            "example": "0x123..."
          },
          "subaccount_address": {
            "type": "string",
            "example": "0x123..."
          }
        }
      },
      "SubaccountHz": {
        "type": "object",
        "description": "Per-subaccount Hz breakdown",
        "required": [
          "account",
          "total_amps"
        ],
        "properties": {
          "account": {
            "type": "string",
            "description": "Subaccount address"
          },
          "total_amps": {
            "type": "number",
            "format": "double",
            "description": "Total Hz earned by this subaccount"
          }
        }
      },
      "SubaccountPoints": {
        "type": "object",
        "description": "Per-subaccount points breakdown",
        "required": [
          "account",
          "points"
        ],
        "properties": {
          "account": {
            "type": "string",
            "description": "Account address"
          },
          "points": {
            "type": "number",
            "format": "double",
            "description": "Trading points for this subaccount"
          }
        }
      },
      "TierInfoDto": {
        "type": "object",
        "description": "Tier info response for a user",
        "required": [
          "owner",
          "total_amps",
          "tiers"
        ],
        "properties": {
          "current_tier": {
            "type": [
              "string",
              "null"
            ],
            "description": "User's current tier (null if below gold)"
          },
          "owner": {
            "type": "string",
            "description": "Owner address"
          },
          "rank": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "User's rank (null if not on leaderboard)",
            "minimum": 0
          },
          "tiers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TierThresholdDto"
            },
            "description": "All tier thresholds with progress"
          },
          "total_amps": {
            "type": "number",
            "format": "double",
            "description": "User's total amps"
          }
        }
      },
      "TierThresholdDto": {
        "type": "object",
        "description": "Individual tier threshold with progress",
        "required": [
          "name",
          "hz_threshold",
          "progress"
        ],
        "properties": {
          "hz_threshold": {
            "type": "number",
            "format": "double",
            "description": "Amps value needed to reach this tier"
          },
          "name": {
            "type": "string",
            "description": "Tier name: \"gold\", \"doublePlatinum\", or \"diamond\""
          },
          "progress": {
            "type": "integer",
            "format": "int32",
            "description": "User's progress toward this tier (0-100)",
            "minimum": 0
          }
        }
      },
      "TimeRange": {
        "type": "string",
        "enum": [
          "24h",
          "7d",
          "30d",
          "90d",
          "all"
        ]
      },
      "TradeDto": {
        "type": "object",
        "required": [
          "asset_type",
          "account",
          "market",
          "action",
          "source",
          "trade_id",
          "size",
          "price",
          "is_profit",
          "realized_pnl_amount",
          "realized_funding_amount",
          "is_rebate",
          "fee_amount",
          "order_id",
          "client_order_id",
          "transaction_unix_ms",
          "transaction_version",
          "counter_party_account"
        ],
        "properties": {
          "account": {
            "type": "string",
            "description": "User's account address",
            "example": "0x1234567890abcdef1234567890abcdef12345678"
          },
          "action": {
            "type": "string",
            "description": "Trade action type. Perp: position-centric (\"OpenLong\", \"CloseShort\",\n\"Net\", ...). Spot: side from this row's perspective (\"Buy\" / \"Sell\").",
            "example": "buy"
          },
          "asset_type": {
            "$ref": "#/components/schemas/AssetType",
            "description": "Which product this trade belongs to (\"perp\" or \"spot\"). Responses can\nmix products; this per-row tag lets clients demux."
          },
          "client_order_id": {
            "type": "string",
            "description": "Client-specified order ID",
            "example": "client_order_abc"
          },
          "counter_party_account": {
            "type": "string",
            "description": "Counter party account on the other leg of the fill. For liquidation /\nADL / delisting fills this is the backstop liquidator. Empty string for\npre-V2 historical trades that did not carry counter party on-chain.",
            "example": "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210"
          },
          "fee_amount": {
            "type": "number",
            "format": "double",
            "description": "Fee paid by this row's account, normalized. Perp: always in the\ncollateral asset (USDC). Spot: charged in the asset this side\nRECEIVED (protocol + builder fee combined); see `fee_asset`."
          },
          "fee_asset": {
            "type": [
              "string",
              "null"
            ],
            "description": "FA metadata address of the asset `fee_amount` is denominated in.\nSpot only (base asset for the buyer, quote for the seller); absent\nfor perp rows, where the fee is implicitly the collateral asset."
          },
          "is_profit": {
            "type": "boolean",
            "description": "Whether trade was profitable"
          },
          "is_rebate": {
            "type": "boolean",
            "description": "Whether trade received rebate"
          },
          "market": {
            "type": "string",
            "description": "Market identifier address",
            "example": "0xmarket123456789abcdef"
          },
          "order_id": {
            "type": "string",
            "description": "Order ID associated with trade",
            "example": "12345"
          },
          "price": {
            "type": "number",
            "format": "double",
            "description": "Trade price",
            "example": 50000.25
          },
          "realized_funding_amount": {
            "type": "number",
            "format": "double",
            "description": "Realized funding amount in USDC\n- Negative value: trader PAID funding (e.g., long position with positive funding rate)\n- Positive value: trader RECEIVED funding (e.g., short position with positive funding rate)\n- Zero: no funding accrued",
            "example": -15.5
          },
          "realized_pnl_amount": {
            "type": "number",
            "format": "double",
            "description": "Realized PnL amount"
          },
          "size": {
            "type": "number",
            "format": "double",
            "description": "Trade size",
            "example": 100.5
          },
          "source": {
            "type": "string",
            "description": "Trade source (e.g., \"OrderFill\", \"MarginCall\", \"BackStopLiquidation\", \"ADL\", \"MarketDelisted\")",
            "example": "OrderFill"
          },
          "trade_id": {
            "type": "string",
            "description": "Trade ID",
            "example": "3647276"
          },
          "transaction_unix_ms": {
            "type": "integer",
            "format": "int64",
            "description": "Transaction timestamp in milliseconds",
            "example": 1634567890000
          },
          "transaction_version": {
            "type": "integer",
            "format": "int64",
            "description": "Transaction version",
            "example": 3647276285,
            "minimum": 0
          }
        }
      },
      "TradeSide": {
        "type": "string",
        "description": "Trial direction. Maps from on-chain `side_is_buy: bool`.",
        "enum": [
          "Buy",
          "Sell"
        ]
      },
      "TrialDto": {
        "type": "object",
        "description": "A protected trial. Presence rules: open-sourced fields are absent only on\ndegraded WS reset rows (enrichment miss); `size` is always emitted, null on\nunknown market; mark_at_close appears on organic closes only; the remaining\nterminal fields appear on closed/reset rows only.",
        "required": [
          "trial_id",
          "user",
          "campaign_addr",
          "status"
        ],
        "properties": {
          "campaign_addr": {
            "type": "string"
          },
          "close_stalled": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Active trial parked in `Closing` with a residual position after a\nsettle IOC couldn't fully close. `None` = not evaluated (history rows,\nWS path, old backend); `Some(true)` = stalled."
          },
          "closed_at_ms": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64"
          },
          "closed_by": {
            "type": [
              "string",
              "null"
            ]
          },
          "expires_at_ms": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64"
          },
          "leverage_at_open": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "minimum": 0
          },
          "mark_at_close": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "minimum": 0
          },
          "mark_at_close_usd": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "mark_at_open": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "minimum": 0
          },
          "mark_at_open_usd": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "market": {
            "type": [
              "string",
              "null"
            ]
          },
          "opened_at_ms": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64"
          },
          "prior_status": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/TrialPriorStatus"
              }
            ]
          },
          "protected_amount": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "minimum": 0
          },
          "protected_amount_usd": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "settle_reason": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/SettleReason"
              }
            ]
          },
          "side": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/TradeSide"
              }
            ]
          },
          "size": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Normalized size; null when the market is unknown. Always present (not skipped)."
          },
          "status": {
            "$ref": "#/components/schemas/TrialStatus"
          },
          "trial_id": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "trial_subaccount": {
            "type": [
              "string",
              "null"
            ]
          },
          "user": {
            "type": "string"
          },
          "user_payout": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "minimum": 0
          },
          "user_payout_usd": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "vault_returned": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "minimum": 0
          },
          "vault_returned_usd": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          }
        }
      },
      "TrialPriorStatus": {
        "type": "string",
        "description": "Status a trial held before an admin reset. Resets are only allowed from\nOpening(0)/Open(1), both of which the wire collapses to `Active`.",
        "enum": [
          "Active"
        ]
      },
      "TrialStatus": {
        "type": "string",
        "description": "`Active` collapses on-chain Opening/Open/Closing; terminal states come from\nthe closed/reset events.",
        "enum": [
          "Active",
          "Settled",
          "SettledLiquidated"
        ]
      },
      "TwapDto": {
        "type": "object",
        "required": [
          "market",
          "is_buy",
          "order_id",
          "is_reduce_only",
          "start_unix_ms",
          "frequency_s",
          "duration_s",
          "orig_size",
          "remaining_size",
          "status",
          "client_order_id",
          "transaction_unix_ms",
          "transaction_version"
        ],
        "properties": {
          "client_order_id": {
            "type": "string",
            "example": "client_order_123"
          },
          "duration_s": {
            "type": "integer",
            "format": "int64",
            "example": 300,
            "minimum": 0
          },
          "frequency_s": {
            "type": "integer",
            "format": "int64",
            "example": 30,
            "minimum": 0
          },
          "is_buy": {
            "type": "boolean",
            "example": true
          },
          "is_reduce_only": {
            "type": "boolean"
          },
          "market": {
            "type": "string",
            "example": "0xmarket123..."
          },
          "order_id": {
            "type": "string"
          },
          "orig_size": {
            "type": "number",
            "format": "double"
          },
          "remaining_size": {
            "type": "number",
            "format": "double"
          },
          "start_unix_ms": {
            "type": "integer",
            "format": "int64",
            "example": 1730841600000
          },
          "status": {
            "type": "string"
          },
          "transaction_unix_ms": {
            "type": "integer",
            "format": "int64"
          },
          "transaction_version": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          }
        }
      },
      "TypeBreakdown": {
        "type": "object",
        "required": [
          "campaign_type",
          "lifetime_earned",
          "ready_to_claim",
          "total_claimed"
        ],
        "properties": {
          "campaign_type": {
            "$ref": "#/components/schemas/CampaignType"
          },
          "lifetime_earned": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "ready_to_claim": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "total_claimed": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          }
        }
      },
      "UserCampaigns": {
        "type": "object",
        "description": "`ready_to_claim` excludes claims outside their claim window at fetch time.",
        "required": [
          "lifetime_earned",
          "ready_to_claim",
          "total_claimed",
          "breakdown_by_type",
          "claims",
          "total_claims",
          "year_to_date",
          "weekly_wow_bps",
          "weekly_breakdown"
        ],
        "properties": {
          "breakdown_by_type": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TypeBreakdown"
            }
          },
          "claims": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserClaim"
            }
          },
          "lifetime_earned": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "ready_to_claim": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "total_claimed": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "total_claims": {
            "type": "integer",
            "format": "int32",
            "description": "Pre-pagination count of `claims`.",
            "minimum": 0
          },
          "weekly_breakdown": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WeeklyEarning"
            }
          },
          "weekly_wow_bps": {
            "type": "integer",
            "format": "int32",
            "description": "Cumulative WoW: this_week_claims / (total_claimed − this_week_claims), in bps.\nSaturates at u32::MAX. 0 when prior cumulative is zero.",
            "minimum": 0
          },
          "year_to_date": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          }
        }
      },
      "UserClaim": {
        "type": "object",
        "description": "Metadata fields are inlined (not flattened) so utoipa generates a flat schema\nthat matches the wire format.",
        "required": [
          "campaign_id",
          "campaign_type",
          "status",
          "title",
          "reward_asset",
          "start_ts_sec",
          "end_ts_sec",
          "claim_start_ts_sec",
          "claim_end_ts_sec",
          "total_funded",
          "has_allocation",
          "claimable_amount",
          "claimed_amount",
          "ready_to_claim"
        ],
        "properties": {
          "campaign_id": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "campaign_type": {
            "$ref": "#/components/schemas/CampaignType"
          },
          "claim_end_ts_sec": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "claim_start_ts_sec": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "claim_tx_hash": {
            "type": [
              "string",
              "null"
            ],
            "description": "Tx hash from the same argMax row as `claimed_at_ts_sec`."
          },
          "claimable_amount": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "claimed_amount": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "claimed_at_ts_sec": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "Latest claim's timestamp (argMax by event_uid).",
            "minimum": 0
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "end_ts_sec": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "has_allocation": {
            "type": "boolean"
          },
          "ready_to_claim": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "reward_asset": {
            "type": "string"
          },
          "start_ts_sec": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "status": {
            "$ref": "#/components/schemas/CampaignStatus"
          },
          "title": {
            "type": "string"
          },
          "total_funded": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          }
        }
      },
      "UserFeesDto": {
        "type": "object",
        "description": "Response for `GET /api/v1/user_fee_rates?account=<address>`.\n\nReturns the user's current fee tier, effective rates (after referral discount),\nthe full fee schedule, and their fee-window daily volume history.\n\nTier semantics mirror on-chain: BOTH products key off the same weighted\ncross-product volume\n`perp_volume x volume_weights.perp + spot_volume x volume_weights.spot`\nagainst one shared threshold ladder (`unified_fees_config`), and differ\nonly in their rate ladders. Each product block carries its own `fee_tier`,\nwhich are equal in practice but kept separate so a future per-product\nladder does not become a breaking change.\nThe top-level fields (`fee_tier`, `daily_user_volume`, `fee_schedule`,\n`user_taker_rate`, `user_maker_rate`, `active_referral_discount`) remain\nPERP-ONLY for backward compatibility; new consumers should read\n`perp` / `spot` explicitly.",
        "required": [
          "account",
          "daily_user_volume",
          "fee_schedule",
          "user_taker_rate",
          "user_maker_rate",
          "fee_tier",
          "active_referral_discount",
          "perp",
          "spot",
          "weighted_volume_usd",
          "volume_weights"
        ],
        "properties": {
          "account": {
            "type": "string",
            "description": "The queried account address"
          },
          "active_referral_discount": {
            "type": "number",
            "format": "double",
            "description": "DEPRECATED, use `perp.active_referral_discount`. Active PERP referral\ndiscount fraction."
          },
          "daily_user_volume": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DailyUserVolumeDto"
            },
            "description": "DEPRECATED, use `perp.daily_user_volume`. Daily PERP volume breakdown\nfor the current on-chain fee window (ascending date order). Serialized\nverbatim twice, so this is the largest single item of duplicated payload."
          },
          "fee_schedule": {
            "$ref": "#/components/schemas/FeeScheduleDto",
            "description": "DEPRECATED, use `perp.fee_schedule`. PERP fee schedule."
          },
          "fee_tier": {
            "type": "integer",
            "format": "int64",
            "description": "DEPRECATED, use `perp.fee_tier`. PERP fee tier index (0 = base tier).",
            "minimum": 0
          },
          "perp": {
            "$ref": "#/components/schemas/ProductFeeStateDto",
            "description": "Perp-side fee state (tier, rates, ladder, raw volume history)"
          },
          "spot": {
            "$ref": "#/components/schemas/ProductFeeStateDto",
            "description": "Spot-side fee state (tier, rates, ladder, raw volume history)"
          },
          "user_maker_rate": {
            "type": "number",
            "format": "double",
            "description": "DEPRECATED, use `perp.user_maker_rate`. User's effective PERP maker rate."
          },
          "user_taker_rate": {
            "type": "number",
            "format": "double",
            "description": "DEPRECATED, use `perp.user_taker_rate`. User's effective PERP taker rate."
          },
          "volume_weights": {
            "$ref": "#/components/schemas/VolumeWeightsDto",
            "description": "The multipliers used to compute `weighted_volume_usd`"
          },
          "weighted_volume_usd": {
            "type": "string",
            "description": "Weighted cross-product volume driving BOTH `perp.fee_tier` and\n`spot.fee_tier` (USD, whole-dollar integer string)"
          }
        }
      },
      "UserFundDto": {
        "type": "object",
        "required": [
          "movement_type",
          "amount",
          "balance_after",
          "timestamp",
          "transaction_version"
        ],
        "properties": {
          "amount": {
            "type": "number",
            "format": "double",
            "example": 1000.0
          },
          "balance_after": {
            "type": "number",
            "format": "double",
            "example": 5000.0
          },
          "movement_type": {
            "$ref": "#/components/schemas/FundMovementType"
          },
          "timestamp": {
            "type": "integer",
            "format": "int64",
            "example": 1703318400000
          },
          "transaction_version": {
            "type": "integer",
            "format": "int64",
            "example": 12345678,
            "minimum": 0
          }
        }
      },
      "UserFundHistoryResponse": {
        "type": "object",
        "required": [
          "funds",
          "total"
        ],
        "properties": {
          "funds": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserFundDto"
            }
          },
          "total": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          }
        }
      },
      "UserReferralInfo": {
        "type": "object",
        "description": "User referral information",
        "required": [
          "account",
          "referrer_account",
          "referral_code",
          "is_affiliate_referral",
          "referred_at_ms"
        ],
        "properties": {
          "account": {
            "type": "string",
            "description": "The referred user's wallet address (not a subaccount address)"
          },
          "is_affiliate_referral": {
            "type": "boolean"
          },
          "referral_code": {
            "type": "string"
          },
          "referred_at_ms": {
            "type": "integer",
            "format": "int64"
          },
          "referrer_account": {
            "type": "string",
            "description": "The referrer's wallet address"
          }
        }
      },
      "VaultDeposit": {
        "type": "object",
        "required": [
          "amount_usdc",
          "shares_received",
          "timestamp_ms"
        ],
        "properties": {
          "amount_usdc": {
            "type": "number",
            "format": "double"
          },
          "shares_received": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "timestamp_ms": {
            "type": "integer",
            "format": "int64"
          },
          "unlock_timestamp_ms": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "Exact unlock time in milliseconds. None = no lockup (never returns Some(0)).\nFrontend derives: is_locked = unlock_timestamp_ms.is_some() && unlock_timestamp_ms > now()"
          }
        }
      },
      "VaultDto": {
        "type": "object",
        "required": [
          "vault_address",
          "vault_name",
          "vault_share_symbol",
          "status",
          "age_days",
          "num_managers"
        ],
        "properties": {
          "age_days": {
            "type": "integer",
            "format": "int64"
          },
          "all_time_return": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Share-price-based time-weighted return percentage since inception"
          },
          "apr": {
            "type": [
              "number",
              "null"
            ],
            "format": "double",
            "description": "Annualized percentage return (avg daily share-price yield × 365).\nNULL if vault has < 14 days of snapshot data."
          },
          "manager_equity": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "manager_stake": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "num_managers": {
            "type": "integer",
            "format": "int32"
          },
          "status": {
            "type": "string"
          },
          "tvl": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "vault_address": {
            "type": "string"
          },
          "vault_name": {
            "type": "string"
          },
          "vault_share_symbol": {
            "type": "string"
          }
        }
      },
      "VaultSortKey": {
        "type": "string",
        "description": "Sort keys for vault listing\n\nDefines the available fields that can be used to sort vaults in the /vaults endpoint.",
        "enum": [
          "tvl",
          "age",
          "pnl",
          "sharpe_ratio",
          "weekly_win_rate",
          "max_drawdown",
          "apr"
        ]
      },
      "VaultStatus": {
        "type": "string",
        "enum": [
          "created",
          "active",
          "inactive"
        ]
      },
      "VaultWithdrawal": {
        "type": "object",
        "required": [
          "shares_redeemed",
          "timestamp_ms",
          "status"
        ],
        "properties": {
          "amount_usdc": {
            "type": [
              "number",
              "null"
            ],
            "format": "double"
          },
          "shares_redeemed": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "status": {
            "type": "string"
          },
          "timestamp_ms": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "VipTierDto": {
        "type": "object",
        "description": "A single VIP (volume-based) fee tier.\nUsers must have at least `volume_threshold` USD in on-chain fee-window volume to qualify (inclusive, matches on-chain logic).",
        "required": [
          "volume_threshold",
          "taker",
          "maker"
        ],
        "properties": {
          "maker": {
            "type": "number",
            "format": "double",
            "description": "Maker fee rate at this tier (decimal number, e.g. 0.000120)"
          },
          "taker": {
            "type": "number",
            "format": "double",
            "description": "Taker fee rate at this tier (decimal number, e.g. 0.000400)"
          },
          "volume_threshold": {
            "type": "string",
            "description": "Minimum fee-window USD volume (inclusive) to reach this tier — matches on-chain `>=` comparison"
          }
        }
      },
      "VolumeWeightsDto": {
        "type": "object",
        "description": "Cross-product volume multipliers used to compute the unified fee tier.\nMirrors on-chain `CrossProductVolumeWeights` (100 == 1.0x).",
        "required": [
          "perp",
          "spot"
        ],
        "properties": {
          "perp": {
            "type": "number",
            "format": "double",
            "description": "Perp volume multiplier (e.g. 1.0)",
            "example": 1.0
          },
          "spot": {
            "type": "number",
            "format": "double",
            "description": "Spot volume multiplier (e.g. 4.0)",
            "example": 4.0
          }
        }
      },
      "WeeklyEarning": {
        "type": "object",
        "required": [
          "week_start_ts_sec",
          "reward_amount"
        ],
        "properties": {
          "reward_amount": {
            "type": "integer",
            "format": "int64",
            "description": "Units follow the campaign's `reward_asset`.",
            "minimum": 0
          },
          "week_start_ts_sec": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          }
        }
      },
      "WithdrawCancelReason": {
        "oneOf": [
          {
            "type": "string",
            "enum": [
              "CancelledByUser"
            ]
          },
          {
            "type": "string",
            "enum": [
              "InsufficientWithdrawableBalance"
            ]
          },
          {
            "type": "string",
            "enum": [
              "DepositCheckFailed"
            ]
          },
          {
            "type": "object",
            "required": [
              "Unknown"
            ],
            "properties": {
              "Unknown": {
                "type": "string"
              }
            }
          }
        ],
        "description": "Cancel reason for a withdrawal request.\n\nSerializes as a flat string for all variants (including Unknown)."
      },
      "WithdrawQueueEntryDto": {
        "type": "object",
        "description": "A single withdrawal queue event (Queued, Processed, or Cancelled).\n\nThe underlying table is an append-log: each state transition is a separate row keyed\nby `event_uid`. Unfiltered queries may return multiple rows for the same `request_id`\n(e.g., a Queued row and a Processed row). Clients should deduplicate by `request_id`,\nkeeping the terminal state (Processed or Cancelled) over Queued.",
        "required": [
          "user",
          "fungible_amount",
          "processed_amount",
          "request_id",
          "status",
          "timestamp_ms",
          "transaction_version"
        ],
        "properties": {
          "cancel_reason": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/WithdrawCancelReason",
                "description": "Reason the withdrawal was cancelled. Only present for Cancelled entries."
              }
            ]
          },
          "fungible_amount": {
            "type": "number",
            "format": "double",
            "description": "Requested withdrawal amount, normalized by collateral decimals."
          },
          "market": {
            "type": [
              "string",
              "null"
            ],
            "description": "The market address. Absent for non-market (cross-margin) withdrawals."
          },
          "processed_amount": {
            "type": "number",
            "format": "double",
            "description": "Amount actually withdrawn. Equals `fungible_amount` for Processed entries, 0 otherwise."
          },
          "queued_at_ms": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "Timestamp when the withdrawal was originally queued. Always present for Queued\nentries. For Processed/Cancelled entries, enriched from the corresponding Queued\nrow. HTTP responses enrich via same-page lookup + DB backfill; WebSocket updates\nonly enrich from the same batch, so this may be absent."
          },
          "recipient": {
            "type": [
              "string",
              "null"
            ],
            "description": "The intended recipient address. The on-chain CancelledEvent omits this field,\nso it is enriched from the corresponding Queued row. HTTP responses enrich via\nsame-page lookup + DB backfill; WebSocket updates only enrich from the same batch."
          },
          "request_id": {
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/WithdrawQueueStatus"
          },
          "timestamp_ms": {
            "type": "integer",
            "format": "int64",
            "description": "Timestamp of this specific event. For Processed entries this is the settlement\ntime; for Cancelled entries the cancellation time. See `queued_at_ms` for the\noriginal queue time."
          },
          "transaction_version": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "user": {
            "type": "string"
          }
        }
      },
      "WithdrawQueueStatus": {
        "type": "string",
        "enum": [
          "Queued",
          "Processed",
          "Cancelled"
        ]
      },
      "u128": {
        "type": "integer",
        "minimum": 0
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Bearer token from Geomi. See [Authentication](/api-reference/rest/authentication) for setup instructions."
      }
    }
  },
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Market Data",
      "description": "Market information and real-time data endpoints"
    },
    {
      "name": "User",
      "description": "User information and account management"
    },
    {
      "name": "Account",
      "description": "Account-specific endpoints and data"
    },
    {
      "name": "Trades",
      "description": "Trading operations and history"
    },
    {
      "name": "Positions",
      "description": "User position management"
    },
    {
      "name": "Orders",
      "description": "Order management and history"
    },
    {
      "name": "TWAP",
      "description": "Time-weighted average price orders"
    },
    {
      "name": "Bulk Orders",
      "description": "Bulk order management"
    },
    {
      "name": "Vaults",
      "description": "Vault operations and management"
    },
    {
      "name": "Analytics",
      "description": "Analytics and performance metrics"
    },
    {
      "name": "Points",
      "description": "Points-related account metrics"
    },
    {
      "name": "Trading Points",
      "description": "Trading points endpoints"
    },
    {
      "name": "Trading Hz",
      "description": "Trading Hz endpoints"
    },
    {
      "name": "Tier",
      "description": "Tier information endpoints"
    },
    {
      "name": "Streaks",
      "description": "User streak tracking endpoints"
    },
    {
      "name": "Predeposit Rewards",
      "description": "Season 0 predeposit USDC rewards"
    },
    {
      "name": "Referrals",
      "description": "Referral code management and tracking"
    },
    {
      "name": "Affiliates",
      "description": "Affiliate code and earnings endpoints"
    },
    {
      "name": "Campaigns",
      "description": "On-chain reward campaign endpoints"
    }
  ]
}