Surf Hyperliquid API

The Hyperliquid API from Surf — 9 operation(s) for hyperliquid.

OpenAPI Specification

surf-hyperliquid-api-openapi.yml Raw ↑
openapi: 3.1.0
info:
  contact:
    email: backend@cybertinolab.com
    name: Cyber team
  description: "Surf data API gateway providing typed endpoints for crypto market data, project analytics, social signals, on-chain queries, and more. All endpoints use credit-based billing with per-request rate limiting.\n\n## Parameter Naming Conventions\n\nAll endpoints follow a standardized naming scheme. Use these canonical names when calling the API.\n\n### Asset Identification\n\n| Param | Type | Description | Example |\n|-------|------|-------------|---------|\n| `symbol` | string | Uppercase ticker symbol(s), comma-separated | `BTC`, `ETH,SOL` |\n| `q` | string | Free-text search keyword | `bitcoin` |\n| `id` | string | Surf entity UUID for direct lookup | `550e8400-...` |\n| `address` | string | On-chain contract or wallet address. Also accepts ENS names (e.g. `vitalik.eth`) which resolve automatically. | `0xdead...`, `vitalik.eth` |\n\n### Time & Aggregation\n\n| Param | Type | Description | Example |\n|-------|------|-------------|---------|\n| `time_range` | string or int | Lookback window | `7d`, `30d`, `365d`, `max` |\n| `interval` | string | Candlestick / indicator interval | `1h`, `1d`, `1w` |\n| `granularity` | string | Data aggregation granularity | `day`, `block`, `hour` |\n\n### Filtering & Sorting\n\n| Param | Type | Description | Example |\n|-------|------|-------------|---------|\n| `chain` | string | Blockchain name (canonical long-form only) | `ethereum`, `solana`, `base` |\n| `currency` | string | Quote currency | `usd`, `eur`, `btc` |\n| `metric` | string | Metric name (endpoint-specific enum) | `nupl`, `tvl` |\n| `type` | string | Category selector (endpoint-specific enum) | `us-btc-spot` |\n| `sort` | string | Sort direction | `asc`, `desc` |\n\n### Pagination\n\nAll list endpoints support:\n- `limit` (int, default: 20, max: 100) — results per page\n- `offset` (int, default: 0) — pagination offset\n\n### Supported Chains\n\nUse canonical long-form names only. Short aliases (eth, sol, matic, etc.) are **not accepted**.\n\n| Chain | Value |\n|-------|-------|\n| Ethereum | `ethereum` |\n| Polygon | `polygon` |\n| BNB Chain | `bsc` |\n| Solana | `solana` |\n| Avalanche | `avalanche` |\n| Arbitrum | `arbitrum` |\n| Optimism | `optimism` |\n| Fantom | `fantom` |\n| Base | `base` |\n| Linea | `linea` |\n| Cyber | `cyber` |\n\nNot all chains are available on every endpoint. Check each endpoint's `chain` enum for supported values.\n\n## Authentication\n\nAll data endpoints require a Bearer token in the `Authorization` header:\n\n```\nAuthorization: Bearer <API_KEY>\n```\n\n## Error Responses\n\nAll endpoints return errors in a consistent format:\n\n```json\n{\n  \"error\": {\n    \"code\": \"FORBIDDEN\",\n    \"message\": \"insufficient credits\"\n  }\n}\n```\n\n| HTTP Status | Meaning |\n|-------------|---------|\n| `400` | Bad request — invalid or missing parameters |\n| `401` | Unauthorized — missing or invalid API key |\n| `404` | Not found — the requested entity does not exist |\n| `422` | Validation error — parameter value is out of range or invalid |\n| `429` | Rate limited — too many requests, retry after the indicated interval |\n| `502` | Upstream error — a data source is temporarily unavailable |\n\n## Credits\n\nEach API call costs a certain number of credits. The cost is returned in every response under `meta.credits_used`. Check your remaining balance via `GET /v1/me/credit-balance`.\n"
  title: Hermod DEX Hyperliquid API
  version: sha-80d3407
servers:
- url: /
tags:
- name: Hyperliquid
paths:
  /gateway/v1/hyperliquid/account:
    get:
      description: 'Returns a wallet''s full portfolio across perps, spot, vaults, and staking in one call, with a perp+vault equity roll-up (`total_value_usd` is the total-equity figure a dashboard header should show, vs the perp-only equity on `/performance` and `/positions`). This is the source for spot balances.


        This is a point-in-time snapshot, not a time series; its perp block duplicates the margin summary from `/hyperliquid/positions` (this endpoint adds spot/vault/staking so it stands alone as a full-portfolio call). Sections are fetched independently: if one fails, that section is omitted (not null) and the failure is named in `errors[]`. The call returns 200 when at least one section succeeds, and 502 only if all four fail. Spot balances are token-denominated and staking is in HYPE.'
      operationId: hyperliquid-account
      parameters:
      - description: 'Wallet address: a 0x EVM address or an ENS name (e.g. vitalik.eth). Solana addresses are not supported.'
        explode: false
        in: query
        name: address
        required: true
        schema:
          description: 'Wallet address: a 0x EVM address or an ENS name (e.g. vitalik.eth). Solana addresses are not supported.'
          type: string
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DataObjectResponseHyperliquidAccount'
          description: OK
        default:
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DataAPIError'
          description: Error
      security:
      - AccessToken: []
      summary: Account Portfolio
      tags:
      - Hyperliquid
  /gateway/v1/hyperliquid/fills:
    get:
      description: 'Returns a wallet''s individual fills (fill-level executions), newest first by default, with realized PnL, fees, and direction (`crossed`=true marks a taker fill that took liquidity). For closed round-trip trades (one row per open→close position, with per-trade P&L incl. funding), use `/hyperliquid/trades` instead — funding is NOT attributable at fill level.


        Default `order=desc` is a recent-capped window (no `offset`): up to `limit` of the most-recent fills; page back by setting `to` to the oldest `time` you received (or `to_ms`+`to_fill_id` for millisecond-exact paging). For COMPLETE history with no cap, use `order=asc` with `from` and follow `meta.next_cursor`. `symbol` filters to one market (applied client-side, so with `order=desc` it only filters the recent window — pair with `from`/`to` to reach older history).'
      operationId: hyperliquid-fills
      parameters:
      - description: 'Wallet address: a 0x EVM address or an ENS name (e.g. vitalik.eth). Solana addresses are not supported.'
        explode: false
        in: query
        name: address
        required: true
        schema:
          description: 'Wallet address: a 0x EVM address or an ENS name (e.g. vitalik.eth). Solana addresses are not supported.'
          type: string
      - description: 'Window start (Unix seconds or a date). With the default order=desc, results cover the window forward from this point and are capped at ~2000 of the earliest fills in range (narrow the range to see the most-recent fills). With order=asc this is the start of a complete-history walk: follow meta.next_cursor to page through every fill in the window with no cap.'
        explode: false
        in: query
        name: from
        schema:
          description: 'Window start (Unix seconds or a date). With the default order=desc, results cover the window forward from this point and are capped at ~2000 of the earliest fills in range (narrow the range to see the most-recent fills). With order=asc this is the start of a complete-history walk: follow meta.next_cursor to page through every fill in the window with no cap.'
          examples:
          - '2026-03-01'
          type: string
      - description: Window end (Unix seconds or a date), inclusive. Defaults to now. With order=desc, page back within the most-recent results by setting this to the oldest time you received (prefer to_ms for millisecond precision); with order=asc it bounds the walk.
        explode: false
        in: query
        name: to
        schema:
          description: Window end (Unix seconds or a date), inclusive. Defaults to now. With order=desc, page back within the most-recent results by setting this to the oldest time you received (prefer to_ms for millisecond precision); with order=asc it bounds the walk.
          examples:
          - '2026-03-01'
          type: string
      - description: 'Window end in Unix milliseconds, for millisecond-precise desc paging: pass the time_ms of the oldest fill you received to fetch the next page. On its own the boundary is exclusive (fills AT to_ms are dropped), so when more than limit fills share one millisecond the remainder is skipped — pair it with to_fill_id to page losslessly through a boundary millisecond. Takes precedence over to (which is ignored when to_ms is set). Like to, it pages within the recent (~2000-fill) window. desc-only: rejected with order=asc (use cursor instead).'
        explode: false
        in: query
        name: to_ms
        schema:
          description: 'Window end in Unix milliseconds, for millisecond-precise desc paging: pass the time_ms of the oldest fill you received to fetch the next page. On its own the boundary is exclusive (fills AT to_ms are dropped), so when more than limit fills share one millisecond the remainder is skipped — pair it with to_fill_id to page losslessly through a boundary millisecond. Takes precedence over to (which is ignored when to_ms is set). Like to, it pages within the recent (~2000-fill) window. desc-only: rejected with order=asc (use cursor instead).'
          format: int64
          minimum: 0
          type: integer
      - description: 'Cursor tiebreak for to_ms: pass the fill_id of the oldest fill you received alongside its time_ms as to_ms. The next page then resumes strictly after that (time_ms, fill_id) pair — fills at the boundary millisecond with a lower fill_id are included instead of skipped, so paging never loses fills that share a millisecond. Requires to_ms; desc-only. Equivalent to following meta.next_cursor, which encodes the same position. An empty page can mean the window is exhausted (set from to reach older history), not that no older fills exist.'
        explode: false
        in: query
        name: to_fill_id
        schema:
          description: 'Cursor tiebreak for to_ms: pass the fill_id of the oldest fill you received alongside its time_ms as to_ms. The next page then resumes strictly after that (time_ms, fill_id) pair — fills at the boundary millisecond with a lower fill_id are included instead of skipped, so paging never loses fills that share a millisecond. Requires to_ms; desc-only. Equivalent to following meta.next_cursor, which encodes the same position. An empty page can mean the window is exhausted (set from to reach older history), not that no older fills exist.'
          type: string
      - description: 'desc (default): newest first — the recent feed, or the earliest-anchored ~2000-fill slice when from is set. asc: oldest first, a complete-history walk from from (required) up to to — each page links the next via meta.next_cursor with no result cap, the reliable mode for full trade-history or PnL reconstruction.'
        explode: false
        in: query
        name: order
        schema:
          default: desc
          description: 'desc (default): newest first — the recent feed, or the earliest-anchored ~2000-fill slice when from is set. asc: oldest first, a complete-history walk from from (required) up to to — each page links the next via meta.next_cursor with no result cap, the reliable mode for full trade-history or PnL reconstruction.'
          enum:
          - desc
          - asc
          type: string
      - description: Opaque continuation token from a previous response's meta.next_cursor. It encodes the paging direction, position, and window, so pass it with only symbol and limit — combining it with from, to, to_ms, or to_fill_id is rejected with 400.
        explode: false
        in: query
        name: cursor
        schema:
          description: Opaque continuation token from a previous response's meta.next_cursor. It encodes the paging direction, position, and window, so pass it with only symbol and limit — combining it with from, to, to_ms, or to_fill_id is rejected with 400.
          type: string
      - description: 'Filter to one market (exact match, e.g. xyz:GOLD). Applied client-side: with order=desc it filters after the recent cap (pair it with from/to so older fills are not missed); with order=asc the cursor walk scans past non-matching fills, so a page may return fewer than limit items (or none) while meta.next_cursor still advances.'
        explode: false
        in: query
        name: symbol
        schema:
          description: 'Filter to one market (exact match, e.g. xyz:GOLD). Applied client-side: with order=desc it filters after the recent cap (pair it with from/to so older fills are not missed); with order=asc the cursor walk scans past non-matching fills, so a page may return fewer than limit items (or none) while meta.next_cursor still advances.'
          type: string
      - description: Page size (1-100).
        explode: false
        in: query
        name: limit
        schema:
          default: 20
          description: Page size (1-100).
          format: int64
          maximum: 100
          minimum: 1
          type: integer
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CursorDataResponseHyperliquidFill'
          description: OK
        default:
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DataAPIError'
          description: Error
      security:
      - AccessToken: []
      summary: Fills
      tags:
      - Hyperliquid
  /gateway/v1/hyperliquid/leaderboard:
    get:
      description: 'Returns traders ranked by a chosen performance metric (PnL by default), with quality filters to exclude bots and brand-new accounts. Each row carries `rank` (1-based, offset-adjusted position in this response''s ordering).


        **Metric basis — does NOT reconcile with `/performance`:** the leaderboard is built on the upstream Hydromancer trade model, whose `total_pnl` is funding-INCLUSIVE over an all-markets trade universe, while `/hyperliquid/performance`/`/trades`/`/trades/aggregate` are funding-EXCLUDED over our episode warehouse. A leaderboard PnL and the same trader''s `/performance` net can differ severalfold — do not display them side-by-side as the same number.


        **Ranking:** `sort_by` (`total_pnl`, `win_rate`, `volume_traded`) over a `time_range` window (`1d`, `7d`, `30d`, `90d`, `all`). Always sorted descending.


        **Filters:** `min_trades` (defaults to 5; pass `0` for the full population), `min_days_active`, `min_account_age_days`, `min_human_score`, and `dex` (`main_dex` or omit for the NATIVE market only — note `/trades/aggregate` omits to ALL markets — or a builder market: `xyz`, `flx`, `vntl`, `hyna`, `km`, `abcd`, `cash`, `para`, `mkts`).


        Paginated with `limit`/`offset`; `meta.total` is the exact count matching your filters.'
      operationId: hyperliquid-leaderboard
      parameters:
      - description: Window to rank over. Default all (data starts 2025-08-01).
        explode: false
        in: query
        name: time_range
        schema:
          default: all
          description: Window to rank over. Default all (data starts 2025-08-01).
          enum:
          - 1d
          - 7d
          - 30d
          - 90d
          - all
          type: string
      - description: Rank by this metric. Always sorted descending.
        explode: false
        in: query
        name: sort_by
        schema:
          default: total_pnl
          description: Rank by this metric. Always sorted descending.
          enum:
          - total_pnl
          - win_rate
          - volume_traded
          type: string
      - description: Only traders with at least this many trades. Defaults to 5; pass 0 for the full population.
        explode: false
        in: query
        name: min_trades
        schema:
          default: 5
          description: Only traders with at least this many trades. Defaults to 5; pass 0 for the full population.
          format: int64
          minimum: 0
          type: integer
      - description: Only traders active at least this many days (0 = no filter).
        explode: false
        in: query
        name: min_days_active
        schema:
          default: 0
          description: Only traders active at least this many days (0 = no filter).
          format: int64
          minimum: 0
          type: integer
      - description: Only accounts at least this old, in days (0 = no filter).
        explode: false
        in: query
        name: min_account_age_days
        schema:
          default: 0
          description: Only accounts at least this old, in days (0 = no filter).
          format: int64
          minimum: 0
          type: integer
      - description: Only traders scoring at least this, 0-100 (0 = no filter).
        explode: false
        in: query
        name: min_human_score
        schema:
          default: 0
          description: Only traders scoring at least this, 0-100 (0 = no filter).
          format: int64
          maximum: 100
          minimum: 0
          type: integer
      - description: 'Market to rank within: main_dex (or omit) for the native market ONLY, or a builder market — one of: xyz, flx, vntl, hyna, km, abcd, cash, para, mkts. NOTE: the omit default differs from /trades/aggregate, where omitting dex aggregates across ALL markets.'
        explode: false
        in: query
        name: dex
        schema:
          description: 'Market to rank within: main_dex (or omit) for the native market ONLY, or a builder market — one of: xyz, flx, vntl, hyna, km, abcd, cash, para, mkts. NOTE: the omit default differs from /trades/aggregate, where omitting dex aggregates across ALL markets.'
          enum:
          - main_dex
          - xyz
          - flx
          - vntl
          - hyna
          - km
          - abcd
          - cash
          - para
          - mkts
          type: string
      - description: Results per page (1-100).
        explode: false
        in: query
        name: limit
        schema:
          default: 20
          description: Results per page (1-100).
          format: int64
          maximum: 100
          minimum: 1
          type: integer
      - description: Results to skip.
        explode: false
        in: query
        name: offset
        schema:
          default: 0
          description: Results to skip.
          format: int64
          minimum: 0
          type: integer
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DataResponseHyperliquidTrader'
          description: OK
        default:
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DataAPIError'
          description: Error
      security:
      - AccessToken: []
      summary: Trader Leaderboard
      tags:
      - Hyperliquid
  /gateway/v1/hyperliquid/orders:
    get:
      description: 'Returns a wallet''s live resting orders (`open` — stops, take-profits, limits, with trigger type) plus its recent terminal orders (`historical` — filled / canceled / rejected). Use `open` for "is a stop set right now?" and `historical` for the set-then-cancelled timeline. Order `side` is in trade terms (`buy`/`sell`), not position terms — a sell stop protects a long; join to `/hyperliquid/positions` by `symbol`.


        Sections are truncated to `open_limit` (default 500) / `historical_limit` (default 200) — `open_total`/`historical_total` carry the pre-truncation counts. Both sections mix PERP and SPOT orders — check `market_type`: spot orders carry raw spot-pair-index symbols (`@107`) that never join to `/positions`, `/trades`, or `/fills` (perp-only surfaces); filter `market_type=perp` for a perp working-orders panel.


        `historical` is **one row per order at its final status**, newest first: the upstream feed is a status-transition stream (an order appears as `open`, then `filled`/`canceled`), so we collapse it to the latest status per order id and drop still-`open` orders (those are in the `open` section) — a passthrough would double-count ids and mislabel status. Status values pass through Hyperliquid''s raw camelCase vocabulary: `filled`, `canceled`, plus reject variants like `iocCancelRejected`, `badAloPxRejected`, `selfTradeCanceled`, `insufficientSpotBalanceRejected` — treat any status other than `filled`/`canceled` as a rejection bucket. Derived from the most-recent ~2000 status updates.


        The two sections fetch independently: a failed section is named in `errors[]` and the call still returns 200 (502 only if both fail).'
      operationId: hyperliquid-orders
      parameters:
      - description: 'Wallet address: a 0x EVM address or an ENS name (e.g. vitalik.eth). Solana addresses are not supported.'
        explode: false
        in: query
        name: address
        required: true
        schema:
          description: 'Wallet address: a 0x EVM address or an ENS name (e.g. vitalik.eth). Solana addresses are not supported.'
          type: string
      - description: Max open orders returned (market makers can hold 1500+; open_total reports the pre-truncation count).
        explode: false
        in: query
        name: open_limit
        schema:
          default: 500
          description: Max open orders returned (market makers can hold 1500+; open_total reports the pre-truncation count).
          format: int64
          maximum: 2000
          minimum: 1
          type: integer
      - description: Max terminal orders returned, newest first (the upstream feed holds ~1000 post-collapse; historical_total reports the pre-truncation count).
        explode: false
        in: query
        name: historical_limit
        schema:
          default: 200
          description: Max terminal orders returned, newest first (the upstream feed holds ~1000 post-collapse; historical_total reports the pre-truncation count).
          format: int64
          maximum: 2000
          minimum: 1
          type: integer
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DataObjectResponseHyperliquidOrders'
          description: OK
        default:
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DataAPIError'
          description: Error
      security:
      - AccessToken: []
      summary: Open & Recent Orders
      tags:
      - Hyperliquid
  /gateway/v1/hyperliquid/performance:
    get:
      description: 'Returns the connected user''s lifetime trading-performance summary — the dashboard header: re-rolled realized performance (win rate, profit factor, gross/net PnL — **funding-excluded**, net = gross − fees), the live position snapshot, and account value.


        This is a lifetime, point-in-time summary: it takes NO `from`/`to` window (use `/hyperliquid/trades` for windowed, paginated closed trades) and carries NO trade list. `account_value` is the live **perp clearinghouse** equity only — NOT total portfolio; for total equity incl. spot/vault use `/hyperliquid/account` (`total_value_usd`). Sections degrade independently: a failed section is named in `errors[]` and the call still returns 200. A genuinely flat perp account returns `account_value` 0 with no `errors[]`; the field is omitted only when the snapshot section degraded (which also adds an `errors[]` entry) — so detect degradation via `errors[]`, not a 0 value.'
      operationId: hyperliquid-performance
      parameters:
      - description: 'Wallet address: a 0x EVM address or an ENS name (e.g. vitalik.eth). Solana addresses are not supported.'
        explode: false
        in: query
        name: address
        required: true
        schema:
          description: 'Wallet address: a 0x EVM address or an ENS name (e.g. vitalik.eth). Solana addresses are not supported.'
          type: string
      - description: NOT SUPPORTED on /performance — returns 400 if set. The lifetime summary always spans ALL markets; market scoping lives on /trades/aggregate (dex=...).
        explode: false
        in: query
        name: dex
        schema:
          description: NOT SUPPORTED on /performance — returns 400 if set. The lifetime summary always spans ALL markets; market scoping lives on /trades/aggregate (dex=...).
          type: string
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DataObjectResponseHyperliquidPerformanceView'
          description: OK
        default:
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DataAPIError'
          description: Error
      security:
      - AccessToken: []
      summary: Trading Performance
      tags:
      - Hyperliquid
  /gateway/v1/hyperliquid/positions:
    get:
      description: 'Returns a wallet''s open perpetual positions with its cross-margin summary and derived risk (leverage, unrealized PnL, ROE, liquidation price, margin ratio, distance-to-liquidation).


        `liquidation_price` (and `distance_to_liquidation`) can be null even on a leveraged position — Hyperliquid returns none for cross positions whose spot collateral backstops them; in that case use the account-level `margin_ratio` (the account liquidates as it approaches 1.0) for proximity. `account_value` here is perp clearinghouse equity, not total portfolio (see `/hyperliquid/account`). Positions are sorted by position value (largest first). `dex` scopes to a builder market; omit (or `main_dex`) for the native market.'
      operationId: hyperliquid-positions
      parameters:
      - description: 'Wallet address: a 0x EVM address or an ENS name (e.g. vitalik.eth). Solana addresses are not supported.'
        explode: false
        in: query
        name: address
        required: true
        schema:
          description: 'Wallet address: a 0x EVM address or an ENS name (e.g. vitalik.eth). Solana addresses are not supported.'
          type: string
      - description: 'Market scope: omit (or main_dex) for the native market, or a builder market — one of: xyz, flx, vntl, hyna, km, abcd, cash, para, mkts.'
        explode: false
        in: query
        name: dex
        schema:
          description: 'Market scope: omit (or main_dex) for the native market, or a builder market — one of: xyz, flx, vntl, hyna, km, abcd, cash, para, mkts.'
          enum:
          - main_dex
          - xyz
          - flx
          - vntl
          - hyna
          - km
          - abcd
          - cash
          - para
          - mkts
          type: string
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DataObjectResponseHyperliquidPositions'
          description: OK
        default:
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DataAPIError'
          description: Error
      security:
      - AccessToken: []
      summary: Open Positions
      tags:
      - Hyperliquid
  /gateway/v1/hyperliquid/trader/stats:
    get:
      deprecated: true
      description: '**Deprecated — use `/hyperliquid/performance`.** This proxies Hydromancer''s own trade-summary, which measures a DIFFERENT trade universe than our warehouse: its `total_pnl` is realized **plus funding** (after fees + funding) over Hydromancer''s all-markets trade model, while `/hyperliquid/performance` is **funding-excluded** realized P&L over our `episodes` (closed round-trips). Because the trade definition, market scope, and funding treatment all differ, the two diverge on trade count, volume, fees, AND PnL — they do NOT reconcile and must never be shown together (the gap is structural, not merely the wallet''s net funding). Retained only for backward compatibility.


        Returns one wallet''s aggregate trading performance: PnL, win/loss rate, volume, fees, funding, active days, and a human-likeness score. The `from`/`to` window is **unreliable** on this endpoint — the upstream summary does not consistently scope volume / trades / fees / traded_pairs to the window (a narrow window can report lifetime-scale volume and pair counts alongside zero trades); for windowed figures use `/hyperliquid/trades` or `/hyperliquid/fills`. `dex` limits to one market.'
      operationId: hyperliquid-trader-stats
      parameters:
      - description: 'Wallet address: a 0x EVM address or an ENS name (e.g. vitalik.eth). Solana addresses are not supported.'
        explode: false
        in: query
        name: address
        required: true
        schema:
          description: 'Wallet address: a 0x EVM address or an ENS name (e.g. vitalik.eth). Solana addresses are not supported.'
          type: string
      - description: Window start (Unix seconds or a date). Omit for lifetime.
        explode: false
        in: query
        name: from
        schema:
          description: Window start (Unix seconds or a date). Omit for lifetime.
          examples:
          - '2026-03-01'
          type: string
      - description: Window end (Unix seconds or a date). Defaults to now.
        explode: false
        in: query
        name: to
        schema:
          description: Window end (Unix seconds or a date). Defaults to now.
          examples:
          - '2026-03-01'
          type: string
      - description: 'Market scope: main_dex for the native market only, or omit to aggregate across all markets; or a builder market — one of: xyz, flx, vntl, hyna, km, abcd, cash, para, mkts.'
        explode: false
        in: query
        name: dex
        schema:
          description: 'Market scope: main_dex for the native market only, or omit to aggregate across all markets; or a builder market — one of: xyz, flx, vntl, hyna, km, abcd, cash, para, mkts.'
          enum:
          - main_dex
          - xyz
          - flx
          - vntl
          - hyna
          - km
          - abcd
          - cash
          - para
          - mkts
          type: string
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DataObjectResponseHyperliquidTraderStats'
          description: OK
        default:
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DataAPIError'
          description: Error
      security:
      - AccessToken: []
      summary: Trader Stats (deprecated → /hyperliquid/performance)
      tags:
      - Hyperliquid
  /gateway/v1/hyperliquid/trades:
    get:
      description: 'Returns a wallet''s closed round-trip trades — one row per open→close position lifecycle, with realized per-trade P&L (gross, net = gross − fees, fees, and `funding_pnl` as a **separate** field that net EXCLUDES), entry/exit price, size, and hold time. Newest close first. This is the journal / calendar / attribution source; for fill-level executions use `/hyperliquid/fills` instead.


        Returns EVERY closed trade in the window — it does NOT filter by symbol or direction (a `symbol`/`direction` query param is ignored, not applied); for per-symbol / per-direction rollups use `/hyperliquid/trades/aggregate`, or `/hyperliquid/fills` for symbol-scoped fills. `funding_pnl` is 0 for warehouse rows and populated only on the live tail, so a funding-inclusive total is incomplete before the watermark.


        Cursor-paged over the full history (warehouse + a live gap-fill for the most recent days): follow `meta.next_cursor` to page back. The cursor is a complete continuation token (it encodes the window + position), so pass it with only `address` and `limit` — combining it with `from`/`to` is rejected. `from`/`to` (Unix seconds or a date) bound the window on the first page. A wallet with an extremely large live (post-warehouse) trade history may require a `from`/`to` window.'
      operationId: hyperliquid-trades
      parameters:
      - description: 'Wallet address: a 0x EVM address or an ENS name (e.g. vit

# --- truncated at 32 KB (84 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/surf/refs/heads/main/openapi/surf-hyperliquid-api-openapi.yml