# Hydromancer - the Hyperliquid Data Layer

Hydromancer is data infrastructure for Hyperliquid. We provide real-time APIs, WebSocket streams, and analytics — so you can ship unique features faster with better data.

{% hint style="info" %}
**TL;DR**: our data infrastructure delivers data faster than Hyperliquid native API, with much broader endpoint coverage accounting for frequently encountered builder usecases. 100+ teams on Hyperliquid use our tech stack.
{% endhint %}

### Who builds on Hydromancer

Hydromancer stack is optimized for demanding teams requiring granular data, low latency real-time streams, and better developer experience.

<details>

<summary>🛠 <strong>App builders</strong></summary>

You're building a trading interface, portfolio tracker, analytics dashboard, or DeFi product on Hyperliquid. You need real-time data that's fast, reliable, and easy to integrate.

**Why Hydromancer:**

* **Unique endpoints** — We've rebuilt and extended the schema with endpoints that don't exist natively, so you write less code and ship faster. Based on a feedback of 30+ builders.
* **Real-time data** — WebSocket streams for orderbooks, trades, account updates, and more — all at lower latency than native Hyperliquid connections.

</details>

<details>

<summary><strong>🧪 HIP-3 or HIP-4 deployers</strong></summary>

You are deploying markets on HIP-3 or HIP-4 and need to monitor your markets' liquidity, user activity, and show the traction of your DEX to the wider audience.

**Why Hydromancer:**

* **Granular data and metrics** - liquidity metrics with sub-second granularity, real-time market maker tracking, and chain replay capabilities.
* **Purpose-built infrastructure** - our product offering is shaped by deployer requirements and designed to drive impact to your HIP-3 DEX performance. Battle-tested, mission-critical features.

</details>

<details>

<summary><strong>⚡ Market Makers &#x26; Quantitative Firms</strong></summary>

You need the fastest possible view of what's happening on Hyperliquid — orderbook updates, trades, liquidations, all of it.

**Why Hydromancer:**

* **Faster than native** — Our orderbook streaming is faster than what Hyperliquid provides natively.
* **Full market streaming** — Subscribe to orderbook-only feeds or everything happening on Hyperliquid, depending on your needs.

</details>

#### Supporting the ecosystem

Building a public good? Just getting started as an app builder? We provide access to Hydromancer infrastructure for public goods and early-stage teams. Free until you start generating revenue through your builder code.

Learn more at [Hydromancer for early-stage teams](/readme/hydromancer-for-early-stage-teams).

### **Why teams choose Hydromancer**

{% columns %}
{% column %}
**Faster data streaming**

Our infrastructure is optimized for real-time data streaming. Fills, orderbooks, orders - you get everything faster with Hydromancer.
{% endcolumn %}

{% column %}
**Unique endpoints**

Our schema includes endpoints that don't exist on Hyperliquid natively, built from feedback across 30+ production teams.
{% endcolumn %}

{% column %}
**No rate limits**

We eliminate the need to run your own infrastructure. No rate limits, no node management, no infra pain. Just data.
{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}
**Complete historical data**

We provide complete Hyperliquid historical data for backtesting, research, and analytics pipelines.
{% endcolumn %}

{% column %}
**Reliable and responsive**

We are always online helping builders ship. If something breaks or you need a custom endpoint, we move fast.
{% endcolumn %}

{% column %}
**Hyperliquid expertise**

Hyperliquid is our sole focus and we are the first to support new features rolled out on Hyperliquid.
{% endcolumn %}
{% endcolumns %}

### **Pricing**

<table><thead><tr><th>Starter</th><th>Growth</th><th width="187">Scale</th><th>Enterprise</th></tr></thead><tbody><tr><td>$<strong>300</strong> per month</td><td>$<strong>1200</strong> per month</td><td>$<strong>2500</strong> per month</td><td><strong>Custom pricing</strong></td></tr><tr><td><strong>500k</strong> tokens</td><td>3m tokens</td><td>15m tokens</td><td>Unlimited API calls</td></tr><tr><td><strong>$60</strong> per 100k tokens overage</td><td>$25 per 100k tokens overage</td><td>$10 per 100k tokens overage</td><td>Unlimited addresses monitoring</td></tr><tr><td>For recently launched apps</td><td>Best plan for scaling teams</td><td>For data-rich, large apps</td><td></td></tr><tr><td>Testnet APIs</td><td>Testnet APIs</td><td>Testnet APIs</td><td></td></tr><tr><td><strong>10</strong> orderbook streams</td><td><strong>50</strong> orderbook streams</td><td><strong>100</strong> orderbook streams</td><td></td></tr></tbody></table>


# REST API

API service for querying user state information from Hyperliquid. All endpoints require Bearer token authentication.

### Authentication

All API requests must include an authorization header with a Bearer token.

```
Authorization: Bearer YOUR_API_KEY
```

### Mainnet URL

```url
https://api.hydromancer.xyz
```

### Testnet URL

{% hint style="warning" %}
Everything is the same except when its described in the docs of the specific endpoint
{% endhint %}

```url
https://api-testnet.hydromancer.xyz
```

### Base Endpoint

```
POST /info
```

All requests use the same endpoint with different `type` values to specify the operation.<br>

### Error responses

<details>

<summary>Error responses</summary>

400 Bad Request

```
{
  "error": "Invalid Ethereum address: 0xinvalid"
}
```

401 Unauthorized

```
{
  "error": "Invalid API key"
}
```

502 Bad Gateway

```
{
  "error": "Timeout error"
}
```

500 Internal Server Error

```
{
  "error": "An internal error occurred"
}
```

</details>


# Rate limits and user limits

#### Rest APIs

Aggregated weight limit per minute:

| Starter | Growth | Scale  |
| ------- | ------ | ------ |
| 5000    | 20,000 | 50,000 |

Where all requests have a default weight of 2 points except for the following:

| Endpoint                                       | Weight     | Notes                                                                                                                   |
| ---------------------------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------- |
| `userPnlSummary`                               | 20         |                                                                                                                         |
| `userPnlLeaderboard`                           | 20         |                                                                                                                         |
| `userCompletedTrades`                          | 20         |                                                                                                                         |
| `userCompletedTradesByTime`                    | 20         |                                                                                                                         |
| `userFills`                                    | 10         |                                                                                                                         |
| `userFillsByTime`                              | 10         |                                                                                                                         |
| `userTwapSliceFills`                           | 10         |                                                                                                                         |
| `userTwapSummaries`                            | 10         |                                                                                                                         |
| `userTwapStatusesByTime`                       | 20         |                                                                                                                         |
| `userLeverageUpdatesByTime`                    | 20         |                                                                                                                         |
| `userIsolatedMarginUpdatesByTime`              | 20         |                                                                                                                         |
| `historicalOrders`                             | 10         |                                                                                                                         |
| `userFunding`                                  | 10         |                                                                                                                         |
| `userNonFundingLedgerUpdates`                  | 10         |                                                                                                                         |
| `marketLiquidity`                              | 10         |                                                                                                                         |
| `perpPriceHistoryByTime`                       | 10         |                                                                                                                         |
| `allPerpMetas`                                 | 10         | Full universe and margin tables across all perp DEXes.                                                                  |
| `builderFills`                                 | 5          |                                                                                                                         |
| `builderFillsByTime`                           | 5          |                                                                                                                         |
| `builderApprovedFillsByTime`                   | 100        | Joins the approval index against `fills`.                                                                               |
| `builderApprovedFundingByTime`                 | 100        | Joins the approval index against `funding_events`; a full page touches a granule per user, so it is priced accordingly. |
| `builderApprovedNonFundingLedgerUpdatesByTime` | 100        | Joins the approval index against `ledger_events`; priced like the funding sibling.                                      |
| `builderOrdersByTime`                          | 5          |                                                                                                                         |
| `fundingHistory`                               | 5          |                                                                                                                         |
| `liquidationHistoryByTime`                     | 5          |                                                                                                                         |
| `portfolioState`                               | 5          |                                                                                                                         |
| `apiUsage`                                     | 5          |                                                                                                                         |
| `batchClearinghouseStates`                     | 2 per user | Max 100 points. Up to 1000 users (100 with `ALL_DEXES`). Cost multiplied by number of dexes with `ALL_DEXES`.           |
| `batchPortfolioStates`                         | 3 per user | Max 200 points. Up to 500 users (100 with `ALL_DEXES`). Cost multiplied by number of dexes with `ALL_DEXES`.            |

The [**market data**](/readme/rest-api/market-data) **endpoints** (snapshots, l4Book) have their own rate limit and can be called 5 times per 10 minutes. `l4Book` allows 10 requests per 5 minutes.


# User position data

#### **Retrieving user's&#x20;**<mark style="background-color:green;">**perpetual accounts**</mark>**&#x20;summary**

{% content-ref url="/pages/8GtMwfBKVkjt1oF8NO2J" %}
[clearinghouseState](/readme/rest-api/user-position-data/clearinghousestate)
{% endcontent-ref %}

#### **Retrieving multiple users'&#x20;**<mark style="background-color:green;">**perpetual accounts**</mark>**&#x20;summary**

{% content-ref url="/pages/QoZnodKzgRSvYcIl0ycA" %}
[batchClearinghouseStates](/readme/rest-api/user-position-data/batchclearinghousestates)
{% endcontent-ref %}

#### **Retrieving user's asset data and leverage settings**

Includes available trade size, leverage on a given asset, and mark price.

{% content-ref url="/pages/y1C2hZW72aGfl9UyJrsQ" %}
[activeAssetData](/readme/rest-api/user-position-data/activeassetdata)
{% endcontent-ref %}

#### **Retrieving user's&#x20;**<mark style="background-color:orange;">**spot**</mark>**&#x20;summary**

{% content-ref url="/pages/UhcfGYdqlEc3AuwVuhNB" %}
[spotclearinghouseState](/readme/rest-api/user-position-data/spotclearinghousestate)
{% endcontent-ref %}

#### **Retrieving user's account abstraction mode**

{% content-ref url="/pages/inHz3xpIMzCp2VGWeIuK" %}
[userAbstraction](/readme/rest-api/user-position-data/userabstraction)
{% endcontent-ref %}

#### **Retrieving user's full portfolio state (perp + spot + abstraction mode)**

{% content-ref url="/pages/NkGZmiqskyXzzFxtk6Ws" %}
[portfolioState](/readme/rest-api/user-position-data/portfoliostate)
{% endcontent-ref %}

#### **Retrieving multiple users' full portfolio states (perp + spot + abstraction mode)**

{% content-ref url="/pages/gcgNOVuR9YI3Rk9lgt8z" %}
[batchPortfolioStates](/readme/rest-api/user-position-data/batchportfoliostates)
{% endcontent-ref %}

#### **Retrieve web data**

{% content-ref url="/pages/HG2Lubojmc9FYNAtKwJI" %}
[webData2](/readme/rest-api/user-position-data/webdata2)
{% endcontent-ref %}


# clearinghouseState

Get the complete clearinghouse state for a single user.

Get the complete clearinghouse state for a single user.

## POST Request

| Field  | Type   | Description                                                                                                                                                      |
| ------ | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type` | string | Must be `"clearinghouseState"`                                                                                                                                   |
| `user` | string | Ethereum address (0x-prefixed, 42 characters)                                                                                                                    |
| `dex`  | string | Perp DEX name. Defaults to empty string (native DEX). Use `"ALL_DEXES"` to fetch clearinghouse state across all dexes (native + all HIP-3 dexes) in one request. |

### Usage

If ALL\_DEXES is not passed one call will consume 1 point.

When passing ALL\_DEXES as dex the points consumed is the number of dexes that are operational. Therefore, you should be mindful about if you really need to this.

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "clearinghouseState",
    "user": "0x0000000000000000000000000000000000000000"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'clearinghouseState',
        'user': '0x0000000000000000000000000000000000000000'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'clearinghouseState',
        user: '0x0000000000000000000000000000000000000000'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

<details>

<summary>Response</summary>

```json
{
  "marginSummary": {
    "accountValue": "50000.00",
    "totalMarginUsed": "10000.00",
    "totalNtlPos": "25000.00",
    "totalRawUsd": "45000.00",
    "withdrawable": "15000.00"
  },
  "crossMarginSummary": {
    "accountValue": "50000.00",
    "totalMarginUsed": "10000.00",
    "totalNtlPos": "25000.00",
    "totalRawUsd": "45000.00",
    "withdrawable": "15000.00"
  },
  "assetPositions": [
    {
      "position": {
        "coin": "BTC",
        "entryPx": "45000.00",
        "leverage": {
          "type": "cross",
          "value": 5
        },
        "liquidationPx": "40000.00",
        "marginUsed": "5000.00",
        "maxTradeSzs": ["100000.00", "100000.00"],
        "positionValue": "50000.00",
        "returnOnEquity": "0.10",
        "szi": "1.0",
        "unrealizedPnl": "500.00"
      },
      "type": "oneWay"
    }
  ],
  "time": 1234567890123
}
```

</details>

<details>

<summary>Response ALL_DEXES</summary>

```json
{
    "native": {
      "marginSummary": {
        "accountValue": "50000.00",
        "totalMarginUsed": "10000.00",
        "totalNtlPos": "25000.00",
        "totalRawUsd": "45000.00",
        "withdrawable": "15000.00"
      },
      "crossMarginSummary": {
        "accountValue": "50000.00",
        "totalMarginUsed": "10000.00",
        "totalNtlPos": "25000.00",
        "totalRawUsd": "45000.00",
        "withdrawable": "15000.00"
      },
      "assetPositions": [],
      "time": 1234567890123
    },
    "xyz": {
      "marginSummary": {
        "accountValue": "10000.00",
        "totalMarginUsed": "2000.00",
        "totalNtlPos": "5000.00",
        "totalRawUsd": "9000.00",
        "withdrawable": "3000.00"
      },
      "crossMarginSummary": {
        "accountValue": "10000.00",
        "totalMarginUsed": "2000.00",
        "totalNtlPos": "5000.00",
        "totalRawUsd": "9000.00",
        "withdrawable": "3000.00"
      },
      "assetPositions": [],
      "time": 1234567890123
    }, 
    ....
  }
```

</details>


# batchClearinghouseStates

Get clearinghouse states for multiple users in a single request.

Get clearinghouse states for multiple users in a single request.

{% hint style="info" %}
💧**New endpoint - this endpoint is not a part of original Hyperliquid API and is added by us for builder convenience.**
{% endhint %}

## POST Request

<table><thead><tr><th width="163.06915283203125">Field</th><th width="135.80908203125">Type</th><th width="471.56585693359375">Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"batchClearinghouseStates"</code></td></tr><tr><td><code>users</code></td><td>array</td><td>Array of Ethereum addresses</td></tr><tr><td><code>dex</code></td><td>string</td><td>Perp DEX name. Defaults to empty string (native DEX). Use <code>"ALL_DEXES"</code> to fetch clearinghouse state across all dexes (native + all HIP-3 dexes) in one request.</td></tr></tbody></table>

### Limits

You can query 1000 users at once. Note that with the ALL\_DEXES field passed that limit is 100 users.

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "batchClearinghouseStates",
    "users": [
      "0x0000000000000000000000000000000000000001",
      "0x0000000000000000000000000000000000000002"
    ]
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'batchClearinghouseStates',
        'users': [
            '0x0000000000000000000000000000000000000001',
            '0x0000000000000000000000000000000000000002'
        ]
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'batchClearinghouseStates',
        users: [
            '0x0000000000000000000000000000000000000001',
            '0x0000000000000000000000000000000000000002'
        ]
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field                                        | Type   | Description                                                                            |
| -------------------------------------------- | ------ | -------------------------------------------------------------------------------------- |
| `successful_states`                          | array  | Array of `[address, clearinghouseState]` tuples                                        |
| `successful_states[n][0]`                    | string | User address                                                                           |
| `successful_states[n][1].marginSummary`      | object | Margin summary (accountValue, totalMarginUsed, totalNtlPos, totalRawUsd, withdrawable) |
| `successful_states[n][1].crossMarginSummary` | object | Cross margin summary (same fields as marginSummary)                                    |
| `successful_states[n][1].assetPositions`     | array  | Array of position objects                                                              |
| `successful_states[n][1].time`               | int    | Timestamp in milliseconds                                                              |
| `failed_wallets`                             | array  | Array of addresses that failed to fetch                                                |

<details>

<summary>Response</summary>

```json
{
  "successful_states": [
    [
      "0x0000000000000000000000000000000000000001",
      {
        "marginSummary": {
          "accountValue": "50000.00",
          "totalMarginUsed": "10000.00",
          "totalNtlPos": "25000.00",
          "totalRawUsd": "45000.00",
          "withdrawable": "15000.00"
        },
        "crossMarginSummary": {
          "accountValue": "50000.00",
          "totalMarginUsed": "10000.00",
          "totalNtlPos": "25000.00",
          "totalRawUsd": "45000.00",
          "withdrawable": "15000.00"
        },
        "assetPositions": [
          {
            "position": {
              "coin": "BTC",
              "entryPx": "45000.00",
              "leverage": {
                "type": "cross",
                "value": 5
              },
              "liquidationPx": "40000.00",
              "marginUsed": "5000.00",
              "maxTradeSzs": ["100000.00", "100000.00"],
              "positionValue": "50000.00",
              "returnOnEquity": "0.10",
              "szi": "1.0",
              "unrealizedPnl": "500.00"
            },
            "type": "oneWay"
          }
        ],
        "time": 1234567890123
      }
    ]
  ],
  "failed_wallets": [
    "0x0000000000000000000000000000000000000003"
  ]
}
```

</details>

<details>

<summary>Response ALL_DEXES</summary>

```json
{
    "successful_states": [
      [
        "0x0000000000000000000000000000000000000001",
        {
          "native": {
            "marginSummary": {
              "accountValue": "50000.00",
              "totalMarginUsed": "10000.00",
              "totalNtlPos": "25000.00",
              "totalRawUsd": "45000.00",
              "withdrawable": "15000.00"
            },
            "crossMarginSummary": {
              "accountValue": "50000.00",
              "totalMarginUsed": "10000.00",
              "totalNtlPos": "25000.00",
              "totalRawUsd": "45000.00",
              "withdrawable": "15000.00"
            },
            "assetPositions": [],
            "time": 1234567890123
          },
          "xyz": {
            "marginSummary": {
              "accountValue": "10000.00",
              "totalMarginUsed": "2000.00",
              "totalNtlPos": "5000.00",
              "totalRawUsd": "9000.00",
              "withdrawable": "3000.00"
            },
            "crossMarginSummary": {
              "accountValue": "10000.00",
              "totalMarginUsed": "2000.00",
              "totalNtlPos": "5000.00",
              "totalRawUsd": "9000.00",
              "withdrawable": "3000.00"
            },
            "assetPositions": [],
            "time": 1234567890123
          },
          ..
        }
      ]
    ],
    "failed_wallets": []
  }
```

</details>


# portfolioState

Get clearinghouse state, spot clearinghouse state, and account abstraction mode for a single user in one request.

Get clearinghouse state, spot clearinghouse state, and account abstraction mode for a single user in one request.

{% hint style="info" %}

#### New endpoint - this endpoint is not a part of original Hyperliquid API and is added by us for builder convenience.

{% endhint %}

## POST Request

| Field  | Type   | Description                                                                                                                                                         |
| ------ | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type` | string | Must be `"portfolioState"`                                                                                                                                          |
| `user` | string | Ethereum address (0x-prefixed, 42 characters)                                                                                                                       |
| `dex`  | string | (Optional) Perp DEX name. Omit for native DEX (default). Use `"ALL_DEXES"` to fetch clearinghouse state across all dexes (native + all HIP-3 dexes) in one request. |

### Usage

This endpoint combines three calls into one:

* `clearinghouseState` - perp positions and margin
* `spotClearinghouseState` - spot balances
* `userAbstraction` - account abstraction mode

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "portfolioState",
    "user": "0x0000000000000000000000000000000000000000"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'portfolioState',
        'user': '0x0000000000000000000000000000000000000000'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'portfolioState',
        user: '0x0000000000000000000000000000000000000000'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field                                         | Type   | Description                                                                        |
| --------------------------------------------- | ------ | ---------------------------------------------------------------------------------- |
| `clearinghouseState`                          | object | Perp clearinghouse state (marginSummary, crossMarginSummary, assetPositions, time) |
| `spotClearinghouseState`                      | object | Spot clearinghouse state containing balances array                                 |
| `spotClearinghouseState.balances[n].coin`     | string | Coin symbol                                                                        |
| `spotClearinghouseState.balances[n].token`    | int    | Token index                                                                        |
| `spotClearinghouseState.balances[n].total`    | string | Total balance                                                                      |
| `spotClearinghouseState.balances[n].hold`     | string | Amount on hold                                                                     |
| `spotClearinghouseState.balances[n].entryNtl` | string | Entry notional                                                                     |
| `userAbstraction`                             | string | Account abstraction mode (see values below)                                        |

<details>

<summary>Response</summary>

```json
{
  "clearinghouseState": {
    "marginSummary": {..},
    "crossMarginSummary": {..},
    "assetPositions": [..],
    "time": 1234567890123
  },
  "spotClearinghouseState": {
    "balances": [
      {
        "coin": "USDC",
        "token": 0,
        "total": "0.02221591",
        "hold": "0.0",
        "entryNtl": "0.0"
      }
    ]
  },
  "userAbstraction": "unifiedAccount"
}
```

</details>

<details>

<summary>Response ALL_DEXES</summary>

```json
{
  "clearinghouseState": {
    "native": {
      "marginSummary": {..},
      "crossMarginSummary": {..},
      "assetPositions": [..],
      "time": 1234567890123
    },
    "xyz": {
      "marginSummary": {..},
      "crossMarginSummary": {..},
      "assetPositions": [..],
      "time": 1234567890123
    }
  },
  "spotClearinghouseState": {
    "balances": [
      {
        "coin": "USDC",
        "token": 0,
        "total": "0.02221591",
        "hold": "0.0",
        "entryNtl": "0.0"
      }
    ]
  },
  "userAbstraction": "unifiedAccount"
}
```

</details>

<details>

<summary>userAbstraction values</summary>

The user's account abstraction mode. Possible values:

| Value               | Description                                                                                                   |
| ------------------- | ------------------------------------------------------------------------------------------------------------- |
| `"unifiedAccount"`  | Unified account mode - single balance per asset across all DEXes, all cross margin positions share collateral |
| `"portfolioMargin"` | Portfolio margin mode - single portfolio unifying eligible assets with borrowing/LTV                          |
| `"disabled"`        | Abstraction disabled - separate perp and spot balances                                                        |
| `"default"`         | Default mode                                                                                                  |
| `"dexAbstraction"`  | DEX abstraction mode (legacy, being discontinued)                                                             |

</details>


# batchPortfolioStates

Get clearinghouse states for perp and spot of multiple users in a single request.

Get clearinghouse states for perp and spot of multiple users in a single request.

{% hint style="info" %}

#### 💧New endpoint - this endpoint is not a part of original Hyperliquid API and is added by us for builder convenience.

{% endhint %}

## POST Request

<table><thead><tr><th width="163.06915283203125">Field</th><th width="135.80908203125">Type</th><th width="471.56585693359375">Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"batchPortfolioStates"</code></td></tr><tr><td><code>users</code></td><td>array</td><td>Array of Ethereum addresses</td></tr><tr><td><code>dex</code></td><td>string</td><td>(Optional) Perp DEX name. Omit for native DEX (default). Use a specific dex name (e.g., <code>"xyz"</code>) to fetch that dex only, or <code>"ALL_DEXES"</code> to fetch clearinghouse state across all dexes (native + all HIP-3 dexes) in one request.</td></tr></tbody></table>

### Limits

You can query 500 users at once. Note that with the ALL\_DEXES field passed that limit is 100 users.

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "batchPortfolioStates",
    "users": [
      "0x0000000000000000000000000000000000000001",
      "0x0000000000000000000000000000000000000002"
    ]
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'batchPortfolioStates',
        'users': [
            '0x0000000000000000000000000000000000000001',
            '0x0000000000000000000000000000000000000002'
        ]
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'batchPortfolioStates',
        users: [
            '0x0000000000000000000000000000000000000001',
            '0x0000000000000000000000000000000000000002'
        ]
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field                                            | Type   | Description                                                                        |
| ------------------------------------------------ | ------ | ---------------------------------------------------------------------------------- |
| `successful_states`                              | array  | Array of `[address, portfolioState]` tuples                                        |
| `successful_states[n][0]`                        | string | User address                                                                       |
| `successful_states[n][1].clearinghouseState`     | object | Perp clearinghouse state (marginSummary, crossMarginSummary, assetPositions, time) |
| `successful_states[n][1].spotClearinghouseState` | object | Spot clearinghouse state containing balances array                                 |
| `successful_states[n][1].userAbstraction`        | string | Account abstraction mode                                                           |
| `failed_wallets`                                 | array  | Array of addresses that failed to fetch                                            |

<details>

<summary>Response</summary>

```json
{
  "successful_states": [
    [
      "0x0000000000000000000000000000000000000001",
      {
        "clearinghouseState": {
          "marginSummary": {..},
          "crossMarginSummary": {..},
          "assetPositions": [..],
          "time": 1234567890123
        },
        "spotClearinghouseState": {
          "balances": [
            {
              "coin": "USDC",
              "token": 0,
              "total": "0.02221591",
              "hold": "0.0",
              "entryNtl": "0.0"
            }
          ]
        },
        "userAbstraction": "unifiedAccount"
      }
    ]
  ],
  "failed_wallets": [
    "0x0000000000000000000000000000000000000003"
  ]
}
```

</details>

<details>

<summary>Response ALL_DEXES</summary>

```json
{
  "successful_states": [
    [
      "0x0000000000000000000000000000000000000001",
      {
        "clearinghouseState": {
          "native": {
            "marginSummary": {..},
            "crossMarginSummary": {..},
            "assetPositions": [..],
            "time": 1234567890123
          },
          "xyz": {
            "marginSummary": {..},
            "crossMarginSummary": {..},
            "assetPositions": [..],
            "time": 1234567890123
          }
        },
        "spotClearinghouseState": {
          "balances": [
            {
              "coin": "USDC",
              "token": 0,
              "total": "0.02221591",
              "hold": "0.0",
              "entryNtl": "0.0"
            }
          ]
        },
        "userAbstraction": "unifiedAccount"
      }
    ]
  ],
  "failed_wallets": []
}
```

</details>

<details>

<summary>userAbstraction values</summary>

The user's account abstraction mode. Possible values:

| Value               | Description                                                                                                   |
| ------------------- | ------------------------------------------------------------------------------------------------------------- |
| `"unifiedAccount"`  | Unified account mode - single balance per asset across all DEXes, all cross margin positions share collateral |
| `"portfolioMargin"` | Portfolio margin mode - single portfolio unifying eligible assets with borrowing/LTV                          |
| `"disabled"`        | Abstraction disabled - separate perp and spot balances                                                        |
| `"default"`         | Default mode                                                                                                  |
| `"dexAbstraction"`  | DEX abstraction mode (legacy, being discontinued)                                                             |

</details>


# activeAssetData

Get asset data for a specific user and coin.

## POST Request

<table><thead><tr><th width="115.50848388671875">Field</th><th width="177.66351318359375">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"activeAssetData"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr><tr><td><code>coin</code></td><td>string</td><td>symbol e.g. "BTC"</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "activeAssetData",
    "user": "0x0000000000000000000000000000000000000000",
    "coin": "BTC"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'activeAssetData',
        'user': '0x0000000000000000000000000000000000000000',
        'coin': 'BTC'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'activeAssetData',
        user: '0x0000000000000000000000000000000000000000',
        coin: 'BTC'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field              | Type           | Description                               |
| ------------------ | -------------- | ----------------------------------------- |
| `user`             | string         | User address                              |
| `coin`             | string         | Coin symbol                               |
| `leverage.type`    | string         | Leverage type (`"cross"` or `"isolated"`) |
| `leverage.value`   | int            | Leverage value                            |
| `leverage.rawUsd`  | string \| null | Raw USD margin (only present if isolated) |
| `maxTradeSzs`      | array          | Maximum trade sizes `[long, short]`       |
| `availableToTrade` | array          | Available to trade `[long, short]`        |
| `markPx`           | string         | Current mark price                        |

<details>

<summary>Response</summary>

```json
{
  "user": "0x0000000000000000000000000000000000000000",
  "coin": "BTC",
  "leverage": {
    "type": "cross", // "cross" or "isolated"
    "value": 5,
    "rawUsd": null // Only present if isolated
  },
  "maxTradeSzs": ["100000.00", "100000.00"],
  "availableToTrade": ["50000.00", "50000.00"],
  "markPx": "45000.00"
}
```

</details>


# spotclearinghouseState

Get the spot clearinghouse state for a single user.

Get the spot clearinghouse state for a single user.

## POST Request

<table><thead><tr><th width="161.9998779296875">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"spotClearinghouseState"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "spotClearinghouseState",
    "user": "0x0000000000000000000000000000000000000000"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'spotClearinghouseState',
        'user': '0x0000000000000000000000000000000000000000'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'spotClearinghouseState',
        user: '0x0000000000000000000000000000000000000000'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field                  | Type   | Description                   |
| ---------------------- | ------ | ----------------------------- |
| `balances`             | array  | Array of spot balance objects |
| `balances[n].coin`     | string | Coin symbol                   |
| `balances[n].token`    | int    | Token index                   |
| `balances[n].total`    | string | Total balance                 |
| `balances[n].hold`     | string | Amount on hold                |
| `balances[n].entryNtl` | string | Entry notional                |

<details>

<summary>Response</summary>

```json
{
  "balances": [
    {
      "coin": "USDC",
      "token": 0,
      "total": "0.02221591",
      "hold": "0.0",
      "entryNtl": "0.0"
    }
  ]
}
```

</details>


# userAbstraction

Get the account abstraction mode for a user.

## POST Request

| Field  | Type   | Description                                   |
| ------ | ------ | --------------------------------------------- |
| `type` | string | Must be `"userAbstraction"`                   |
| `user` | string | Ethereum address (0x-prefixed, 42 characters) |

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "userAbstraction",
    "user": "0x0000000000000000000000000000000000000000"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'userAbstraction',
        'user': '0x0000000000000000000000000000000000000000'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'userAbstraction',
        user: '0x0000000000000000000000000000000000000000'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

<details>

<summary>Response</summary>

Returns a string indicating the user's account abstraction mode:

```json
"unifiedAccount"
```

Possible values:

| Value             | Description                                       |
| ----------------- | ------------------------------------------------- |
| `unifiedAccount`  | Unified account mode                              |
| `portfolioMargin` | Portfolio margin mode                             |
| `disabled`        | Abstraction disabled                              |
| `default`         | Default mode                                      |
| `dexAbstraction`  | DEX abstraction mode (legacy, being discontinued) |

</details>


# userDexAbstraction

Returns whether per-DEX abstraction is enabled for a user. This is the per-DEX counterpart to [userAbstraction](/readme/rest-api/user-position-data/userabstraction).

<table><thead><tr><th width="115">Field</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"userDexAbstraction"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>User Ethereum address (required)</td></tr></tbody></table>

## Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "userDexAbstraction",
    "user": "0xd38809cc442fe4f10937c5988d2b723a15a89e5b"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'userDexAbstraction',
        'user': '0xd38809cc442fe4f10937c5988d2b723a15a89e5b'
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'userDexAbstraction',
    user: '0xd38809cc442fe4f10937c5988d2b723a15a89e5b'
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field  | Type | Description                                                              |
| ------ | ---- | ------------------------------------------------------------------------ |
| (root) | bool | `true` if per-DEX abstraction is enabled for the user, otherwise `false` |

<details>

<summary>Response</summary>

```json
false
```

</details>


# webData2

Get aggregated web data including clearinghouse state, metadata, and market info.

{% hint style="info" %}
This is a composite endpoint returning clearinghouse state, open orders, metadata, asset contexts, and more.
{% endhint %}

## POST Request

<table><thead><tr><th width="161.9998779296875">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"webData2"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "webData2",
    "user": "0x0000000000000000000000000000000000000000"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'webData2',
        'user': '0x0000000000000000000000000000000000000000'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'webData2',
        user: '0x0000000000000000000000000000000000000000'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field                                           | Type    | Description                                                                                            |
| ----------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------ |
| `clearinghouseState`                            | object  | User's clearinghouse state (margin summary, positions, etc.)                                           |
| `clearinghouseState.marginSummary`              | object  | Margin summary with `accountValue`, `totalNtlPos`, `totalRawUsd`, `totalMarginUsed`                    |
| `clearinghouseState.crossMarginSummary`         | object  | Cross margin summary (same fields as marginSummary)                                                    |
| `clearinghouseState.crossMaintenanceMarginUsed` | string  | Cross maintenance margin used                                                                          |
| `clearinghouseState.withdrawable`               | string  | Withdrawable amount                                                                                    |
| `clearinghouseState.assetPositions`             | array   | List of asset positions                                                                                |
| `clearinghouseState.time`                       | int     | Timestamp (ms)                                                                                         |
| `leadingVaults`                                 | array   | Leading vaults for the user                                                                            |
| `totalVaultEquity`                              | string  | Total vault equity                                                                                     |
| `openOrders`                                    | array   | Open orders                                                                                            |
| `agentAddress`                                  | string? | Agent address (null if none)                                                                           |
| `agentValidUntil`                               | int?    | Agent validity timestamp (null if none)                                                                |
| `cumLedger`                                     | string  | Cumulative ledger value                                                                                |
| `meta`                                          | object  | Metadata including universe and margin tables                                                          |
| `meta.universe`                                 | array   | List of perp assets with `szDecimals`, `name`, `maxLeverage`, `marginTableId`, `isDelisted` (optional) |
| `meta.marginTables`                             | array   | Margin table definitions with tiers                                                                    |
| `meta.collateralToken`                          | int     | Collateral token index                                                                                 |
| `assetCtxs`                                     | array   | Asset contexts                                                                                         |
| `serverTime`                                    | int     | Server timestamp (ms)                                                                                  |
| `isVault`                                       | boolean | Whether the user is a vault                                                                            |
| `user`                                          | string  | User address                                                                                           |
| `twapStates`                                    | array   | Active TWAP order states                                                                               |
| `perpsAtOpenInterestCap`                        | array   | List of perp symbols at open interest cap                                                              |

<details>

<summary>Response (truncated)</summary>

```json
{
    "clearinghouseState": {
        "marginSummary": {
            "accountValue": "0.0",
            "totalNtlPos": "0.0",
            "totalRawUsd": "0.0",
            "totalMarginUsed": "0.0"
        },
        "crossMarginSummary": {
            "accountValue": "0.0",
            "totalNtlPos": "0.0",
            "totalRawUsd": "0.0",
            "totalMarginUsed": "0.0"
        },
        "crossMaintenanceMarginUsed": "0.0",
        "withdrawable": "0.0",
        "assetPositions": [],
        "time": 1773660497365
    },
    "leadingVaults": [],
    "totalVaultEquity": "0.0",
    "openOrders": [],
    "agentAddress": null,
    "agentValidUntil": null,
    "cumLedger": "0.0",
    "meta": {
        "universe": [
            {
                "szDecimals": 5,
                "name": "BTC",
                "maxLeverage": 40,
                "marginTableId": 56
            }
        ],
        "marginTables": [
            [
                56,
                {
                    "description": "tiered 40x",
                    "marginTiers": [
                        {
                            "lowerBound": "0.0",
                            "maxLeverage": 40
                        },
                        {
                            "lowerBound": "150000000.0",
                            "maxLeverage": 20
                        }
                    ]
                }
            ]
        ],
        "collateralToken": 0
    },
    "assetCtxs": [],
    "serverTime": 1773660497365,
    "isVault": false,
    "user": "0x0000000000000000000000000000000000000000",
    "twapStates": [],
    "perpsAtOpenInterestCap": [
        "CANTO",
        "FTM",
        "JELLY"
    ]
}
```

</details>


# Asset data

#### **Retrieve all mid prices**

{% content-ref url="/pages/9Quxbk8so9q5YSybRt0H" %}
[allMids](/readme/rest-api/asset-data/allmids)
{% endcontent-ref %}

#### **Retrieve an asset's context**

{% content-ref url="/pages/PFRXOlobbsHKq5ZnrzmU" %}
[assetContext](/readme/rest-api/asset-data/assetcontext)
{% endcontent-ref %}

#### **Retrieve oracle price history**

{% content-ref url="/pages/6MW8hZ4sTczfafLiPgdv" %}
[oraclePriceHistory](/readme/rest-api/asset-data/oraclepricehistory)
{% endcontent-ref %}

#### **Retrieve oracle price history&#x20;*****within a specified time range***

{% content-ref url="/pages/S1y1KcqVizlYI1KdFqwa" %}
[oraclePriceHistoryByTime](/readme/rest-api/asset-data/oraclepricehistorybytime)
{% endcontent-ref %}

#### **Retrieve accepted mark and oracle prices&#x20;*****within a specified time range***

{% content-ref url="/pages/D8MOnPwnelkv61IjEQKL" %}
[perpPriceHistoryByTime](/readme/rest-api/asset-data/perppricehistorybytime)
{% endcontent-ref %}


# assetContext

Get the asset context (mid-, mark- and oracle price for example) of one or more symbols.

## Single coin

Request

<table><thead><tr><th width="115.50848388671875">Field</th><th width="177.66351318359375">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"</code>assetContext<code>"</code></td></tr><tr><td><code>coin</code></td><td>string</td><td>symbol e.g. "BTC" or with dex prefix "xyz:XYZ100"</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "assetContext",
    "coin": "BTC"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'assetContext',
        'coin': 'BTC'
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)

print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post('https://api.hydromancer.xyz/info', {
    type: 'assetContext',
    coin: 'BTC'
}, {
    headers: {
        'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
        'Content-Type': 'application/json'
    }
});

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

<details>

<summary>Response</summary>

```json
{
  "oraclePx": "96500.50",
  "markPx": "96485.25",
  "midPx": "96490.50",
  "impactPxs": [ "96490", "96491" ],
  "openInterest": "25401.1214",
  "dayNtlVlm": "1643278247.97882",
  "dayBaseVlm": "26703.40439"
}
```

</details>

{% hint style="warning" %}
If the coin is not found (all prices are unavailable), the endpoint returns `HTTP 404 Not Found`.
{% endhint %}

***

## Multiple coins

Query up to 20 coins in a single request. Use `coins` instead of `coin`.

<table><thead><tr><th width="115.50848388671875">Field</th><th width="177.66351318359375">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"assetContext"</code></td></tr><tr><td><code>coins</code></td><td>string[]</td><td>Array of symbols, max 20. e.g. <code>["BTC", "ETH"]</code></td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "assetContext",
    "coins": ["BTC", "ETH", "SOL"]
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'assetContext',
        'coins': ['BTC', 'ETH', 'SOL']
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)

print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post('https://api.hydromancer.xyz/info', {
    type: 'assetContext',
    coins: ['BTC', 'ETH', 'SOL']
}, {
    headers: {
        'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
        'Content-Type': 'application/json'
    }
});

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

<details>

<summary>Response</summary>

```json
{
  "BTC": {
    "oraclePx": "96500.50",
    "markPx": "96485.25",
    "midPx": "96490.50",
    "impactPxs": [ "96490", "96491" ],
    "openInterest": "25401.1214",
    "dayNtlVlm": "1643278247.97882",
    "dayBaseVlm": "26703.40439"
  },
  "ETH": {
    "oraclePx": "3450.10",
    "markPx": "3448.75",
    "midPx": "3449.50",
    "impactPxs": [ "3449", "3450" ],
    "openInterest": "192841.521",
    "dayNtlVlm": "543210987.65432",
    "dayBaseVlm": "157234.21098"
  },
  "SOL": null
}
```

</details>

{% hint style="info" %}
Coins that are not found return `null` in the response map instead of causing a 404.
{% endhint %}

***

## Response Fields

| Field          | Type    | Description                                                                                                                                                                                                                                                               |
| -------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `oraclePx`     | string? | Oracle price (null if not available)                                                                                                                                                                                                                                      |
| `markPx`       | string? | Mark price (null if not available)                                                                                                                                                                                                                                        |
| `midPx`        | string? | Mid price (null if not available)                                                                                                                                                                                                                                         |
| `impactPxs`    | array?  | Avg execution price to trade impact notional (20k$ BTC/ETH, 6k$ other coins) on the bid and ask (null if not available)                                                                                                                                                   |
| `openInterest` | string? | Number of outstanding contracts (null if not available)                                                                                                                                                                                                                   |
| `dayNtlVlm`    | string? | 24-hour notional volume — sum of price × size over the trailing 24 hours. `"0.0"` for an untraded perp; null for a coin absent from the context store, or briefly after a service restart while the 24h window re-seeds (last-known values are preserved where available) |
| `dayBaseVlm`   | string? | 24-hour base volume — sum of size over the trailing 24 hours. `"0.0"` for an untraded perp; null for a coin absent from the context store, or briefly after a service restart while the 24h window re-seeds (last-known values are preserved where available)             |


# oraclePriceHistory

Returns the most recent oracle price updates for a coin in descending order (newest first).

<table><thead><tr><th width="115.50848388671875">Field</th><th width="177.66351318359375">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"</code>oraclePriceHistory<code>"</code></td></tr><tr><td><code>coin</code></td><td>string</td><td>symbol e.g. "BTC" or with dex prefix "xyz:XYZ100"</td></tr><tr><td><code>limit</code></td><td>int</td><td>max 2000</td></tr><tr><td><code>dex</code></td><td>string</td><td>DEX identifier e.g. "hyna", "xyz" (optional, returns all if omitted)</td></tr></tbody></table>

Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "oraclePriceHistory",
    "coin": "BTC",
    "limit": 100
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import json
import os

import requests

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'oraclePriceHistory',
        'coin': 'BTC',
        'limit': 100
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)

print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'oraclePriceHistory',
    coin: 'BTC',
    limit: 100
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field       | Type    | Description                                                                                                                      |
| ----------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `time`      | int     | Unix timestamp in milliseconds                                                                                                   |
| `dex`       | string  | DEX source (e.g. `"hyna"`)                                                                                                       |
| `coin`      | string  | Coin symbol                                                                                                                      |
| `oraclePx`  | string? | Oracle price (null if not available)                                                                                             |
| `markPx`    | string? | Mark price (null if not available)                                                                                               |
| `markPx2`   | string? | Secondary mark price, only relevant for some HIP-3 dexes (available from 12 Jan 2026, null for earlier data or non-HIP-3 assets) |
| `extPerpPx` | string? | External perp price (null if not available)                                                                                      |

<details>

<summary>Response</summary>

```json
[ 
    { 
        "time": 1765641295024, 
        "dex": "hyna", 
        "coin": "hyna:BTC", 
        "oraclePx": "90090.00",
        "markPx": "90063.00",
        "markPx2": "90061.50",
        "extPerpPx": "90055.85"
    },
    {
        "time": 1765641292010,
        "dex": "hyna",
        "coin": "hyna:BTC",
        "oraclePx": "90090.00",
        "markPx": "90063.00",
        "markPx2": "90061.50",
        "extPerpPx": "90055.85" 
    } 
]
```

</details>


# oraclePriceHistoryByTime

Returns oracle price updates for a coin within a time range in ascending order (oldest first).

{% hint style="info" %}
For HIP-3 dexes this endpoint returns the prices the dex deployer **submitted** in its `setOracle` action (`markPx` / `markPx2` are the mark-price inputs). The prices the network **accepted** for the round — the ones used for margining and liquidation — are served by [perpPriceHistoryByTime](/readme/rest-api/asset-data/perppricehistorybytime). For the native dex the two endpoints agree.
{% endhint %}

<table><thead><tr><th width="115.50848388671875">Field</th><th width="177.66351318359375">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"oraclePriceHistoryByTime"</code></td></tr><tr><td><code>coin</code></td><td>string</td><td>symbol e.g. "BTC" or with dex prefix "xyz:XYZ100"</td></tr><tr><td><code>startTime</code></td><td>int</td><td>ms unix timestamp</td></tr><tr><td><code>endTime</code></td><td>int</td><td>ms unix timestamp (optional)</td></tr><tr><td><code>limit</code></td><td>int</td><td>max 2000</td></tr><tr><td><code>dex</code></td><td>string</td><td>DEX identifier e.g. "hyna", "xyz" (optional, returns all if omitted)</td></tr></tbody></table>

Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
-H "Authorization: Bearer $HYDROMANCER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
      "type": "oraclePriceHistoryByTime",
      "coin": "BTC",
      "startTime": 1765641292010,
      "endTime": 1765641295024
    }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
 'https://api.hydromancer.xyz/info',
 json={
        'type': 'oraclePriceHistoryByTime',
        'coin': 'BTC',
        'startTime': 1765641292010,
        'endTime': 1765641295024
 },
 headers={
          'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
          'Content-Type': 'application/json'
      }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'oraclePriceHistoryByTime',
    coin: 'BTC',
    limit: 100,
    startTime: 1765641292010,
    endTime: 1765641295024
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field       | Type    | Description                                                                                      |
| ----------- | ------- | ------------------------------------------------------------------------------------------------ |
| `time`      | int     | Timestamp (ms)                                                                                   |
| `dex`       | string  | DEX identifier                                                                                   |
| `coin`      | string  | Trading pair                                                                                     |
| `oraclePx`  | string? | Oracle price                                                                                     |
| `markPx`    | string? | Mark price (first input)                                                                         |
| `markPx2`   | string? | Mark price (second input) — added from 2026-01-12, only present if hip3 dex pushes 2 mark prices |
| `extPerpPx` | string? | External perp price                                                                              |

<details>

<summary>Response (HIP-3 dex with 2 mark prices)</summary>

```json
[
  {
    "time": 1767965552339,
    "dex": "xyz",
    "coin": "xyz:XYZ100",
    "oraclePx": "25546.00",
    "markPx": "25546.00",
    "markPx2": "25545.00",
    "extPerpPx": "25546.00"
  },
  {
    "time": 1767965555526,
    "dex": "xyz",
    "coin": "xyz:XYZ100",
    "oraclePx": "25555.00",
    "markPx": "25555.00",
    "markPx2": "25554.00",
    "extPerpPx": "25555.00"
  }
]
```

</details>

<details>

<summary>Response (HIP-3 dex with 1 mark price)</summary>

```json
[
  {
    "time": 1767965617506,
    "dex": "hyna",
    "coin": "hyna:BTC",
    "oraclePx": "90527.00",
    "markPx": "90508.27",
    "extPerpPx": "90473.25"
  },
  {
    "time": 1767965620725,
    "dex": "hyna",
    "coin": "hyna:BTC",
    "oraclePx": "90528.00",
    "markPx": "90502.00",
    "extPerpPx": "90473.25"
  }
]
```

</details>


# perpPriceHistoryByTime

Returns the accepted oracle and mark prices of a perp within a time range

Rows are in ascending order (oldest first), one per oracle round (roughly every 3 seconds per dex). These are the prices the exchange actually uses for margining and liquidation, on every dex including HIP-3. For HIP-3 they are the values the network **accepted** for the round, not what the dex deployer submitted in its `setOracle` action — use [oraclePriceHistoryByTime](/readme/rest-api/asset-data/oraclepricehistorybytime) for the raw submission. For the native Hyperliquid dex both endpoints return the same validator round.

<table><thead><tr><th width="115.50848388671875">Field</th><th width="177.66351318359375">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"perpPriceHistoryByTime"</code></td></tr><tr><td><code>coin</code></td><td>string</td><td>symbol e.g. "BTC" or with dex prefix "xyz:XYZ100"</td></tr><tr><td><code>coins</code></td><td>string[]</td><td>batch form: 1–20 symbols. Returns an object keyed by coin instead of a flat array. Use <em>either</em> <code>coin</code> or <code>coins</code>.</td></tr><tr><td><code>startTime</code></td><td>int</td><td>ms unix timestamp</td></tr><tr><td><code>endTime</code></td><td>int</td><td>ms unix timestamp (optional)</td></tr><tr><td><code>limit</code></td><td>int</td><td>max 2000 (default 2000)</td></tr><tr><td><code>dex</code></td><td>string</td><td>DEX identifier e.g. "hyna", "xyz"; "main_dex" for the native dex (optional, returns all if omitted)</td></tr></tbody></table>

Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
-H "Authorization: Bearer $HYDROMANCER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
      "type": "perpPriceHistoryByTime",
      "coin": "xyz:AAOI",
      "startTime": 1787528956000,
      "endTime": 1787528966000
    }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
 'https://api.hydromancer.xyz/info',
 json={
        'type': 'perpPriceHistoryByTime',
        'coin': 'xyz:AAOI',
        'startTime': 1787528956000,
        'endTime': 1787528966000
 },
 headers={
          'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
          'Content-Type': 'application/json'
      }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'perpPriceHistoryByTime',
    coin: 'xyz:AAOI',
    limit: 100,
    startTime: 1787528956000,
    endTime: 1787528966000
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Batch (multiple coins)

Pass `coins` (an array of 1–20 symbols) instead of `coin` to fetch several markets over the same time range in one request. `startTime`, `endTime` and `dex` apply to every coin. `limit` is **per coin, max 100** in the batch form (default 100) — so a 20-coin batch returns at most \~2000 rows; use the single-coin form for a wider window on one market. The response is an **object keyed by coin**, each value the same row array as the single-coin form; a requested coin with no data maps to an empty array.

This is served by a single ClickHouse query (`coin` is the table's leading sort key), so it is cheaper than looping the single-coin request. Billing is **1 token per coin** (a single-coin request is 1 token), and the rate-limit cost scales with the number of coins.

```bash
curl -X POST https://api.hydromancer.xyz/info \
-H "Authorization: Bearer $HYDROMANCER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
      "type": "perpPriceHistoryByTime",
      "coins": ["BTC", "xyz:GOLD"],
      "startTime": 1787528956000,
      "endTime": 1787528966000
    }'
```

```json
{
  "BTC": [ { "time": 1787528958000, "blockNumber": 1130393728, "dex": "hyperliquid", "coin": "BTC", "oraclePx": "...", "markPx": "..." } ],
  "xyz:GOLD": [ { "time": 1787528958000, "blockNumber": 1130393728, "dex": "xyz", "coin": "xyz:GOLD", "oraclePx": "...", "markPx": "...", "updateClass": "Normal" } ]
}
```

## Response Fields

| Field         | Type    | Description                                                                                                                                                                                                                                                                |
| ------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `time`        | int     | Block timestamp of the oracle round (ms)                                                                                                                                                                                                                                   |
| `blockNumber` | int     | Height of the block that committed the round — joins to `userFillsByTime` / block-level data                                                                                                                                                                               |
| `dex`         | string  | DEX identifier (`"hyperliquid"` for the native dex)                                                                                                                                                                                                                        |
| `coin`        | string  | Trading pair                                                                                                                                                                                                                                                               |
| `oraclePx`    | string? | Accepted oracle price. Omitted when the round carried no oracle slot for the asset: delisted native assets kept a frozen `markPx` with no oracle until 2026-06-13 (they drop out entirely after that), and the natively-priced HYPE/PURR miss the slot in \~2 rounds a day |
| `markPx`      | string  | Accepted mark price — the value used for margining, liquidations and funding. Always present                                                                                                                                                                               |
| `extPerpPx`   | string? | External perp reference price; omitted for assets without one                                                                                                                                                                                                              |
| `updateClass` | string? | HIP-3 only: how the network sourced the round as reported by the node (`"Deployer"`, `"Fallback"`, `"Normal"`). Omitted for the native dex                                                                                                                                 |

When a block commits more than one oracle round for the same dex, the last round is returned.

Accepted HIP-3 rounds are available from 2026-02-24; native rounds from 2025-08-01.

<details>

<summary>Response (HIP-3 dex)</summary>

```json
[
  {
    "time": 1787528956211,
    "blockNumber": 1130393728,
    "dex": "xyz",
    "coin": "xyz:AAOI",
    "oraclePx": "106.88",
    "markPx": "106.97",
    "extPerpPx": "106.88",
    "updateClass": "Deployer"
  },
  {
    "time": 1787528959402,
    "blockNumber": 1130393772,
    "dex": "xyz",
    "coin": "xyz:AAOI",
    "oraclePx": "106.88",
    "markPx": "106.96",
    "extPerpPx": "106.88",
    "updateClass": "Deployer"
  }
]
```

</details>

<details>

<summary>Response (native dex)</summary>

```json
[
  {
    "time": 1787528956211,
    "blockNumber": 1130393728,
    "dex": "hyperliquid",
    "coin": "BTC",
    "oraclePx": "108712.00",
    "markPx": "108708.40",
    "extPerpPx": "108709.50"
  },
  {
    "time": 1787528959402,
    "blockNumber": 1130393772,
    "dex": "hyperliquid",
    "coin": "BTC",
    "oraclePx": "108715.00",
    "markPx": "108711.10",
    "extPerpPx": "108712.00"
  }
]
```

</details>


# allMids

Get the mid prices of all perp assets

Request

<table><thead><tr><th width="115.50848388671875">Field</th><th width="177.66351318359375">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"</code>allMids<code>"</code></td></tr><tr><td><code>dex</code></td><td>string</td><td><strong>optional</strong> will default to the first dex, can set to ALL_DEXS for all mids of all dexes</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "allMids",
    "dex": ""
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'allMids',
        'dex': ''
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)

print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post('https://api.hydromancer.xyz/info', {
    type: 'allMids',
    dex: ''
}, {
    headers: {
        'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
        'Content-Type': 'application/json'
    }
});

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response Fields

Returns a JSON object where each key is a coin symbol and the value is the mid price as a string.

| Field    | Type   | Description                  |
| -------- | ------ | ---------------------------- |
| `{coin}` | string | Mid price for the given coin |

{% hint style="warning" %}
Currently only returns perp mid prices, not spot mid prices.
{% endhint %}

<details>

<summary>Response</summary>

```json
{
  "BTC": "96500.50",
  "ETH": "3000.21",
  ....
}
```

</details>


# User order data

#### **Retrieving user's open orders**

{% content-ref url="/pages/PX3ZGFCRu29iq0QLMzBH" %}
[openOrders](/readme/rest-api/user-order-data/openorders)
{% endcontent-ref %}

#### **Retrieving user's open orders&#x20;*****with additional frontend information***

Additional frontend information includes order trigger condition, reduceOnly toggle, whether the order is TP/SL, and more.

{% content-ref url="/pages/y00Nntqs5kDT0faEcEfS" %}
[frontendOpenOrders](/readme/rest-api/user-order-data/frontendopenorders)
{% endcontent-ref %}


# openOrders

Returns the open orders for a user.

<table><thead><tr><th width="115">Field</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"openOrders"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr></tbody></table>

## Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "openOrders",
    "user": "0x0000000000000000000000000000000000000000"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'openOrders',
        'user': '0x0000000000000000000000000000000000000000'
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'openOrders',
    user: '0x0000000000000000000000000000000000000000'
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field       | Type   | Description                   |
| ----------- | ------ | ----------------------------- |
| `coin`      | string | Asset symbol                  |
| `limitPx`   | string | Limit price                   |
| `oid`       | int    | Order ID                      |
| `side`      | string | `"A"` (sell) or `"B"` (buy)   |
| `sz`        | string | Order size                    |
| `timestamp` | int    | Order creation timestamp (ms) |

<details>

<summary>Response</summary>

```json
[
  {
    "coin": "BTC",
    "limitPx": "29792.0",
    "oid": 91490942,
    "side": "A",
    "sz": "0.0",
    "timestamp": 1681247412573
  }
]
```

</details>


# frontendOpenOrders

Returns open orders for a user with additional frontend display information such as order type and trigger details.

<table><thead><tr><th width="115">Field</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"frontendOpenOrders"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr><tr><td><code>dex</code></td><td>string</td><td>Perp DEX name (optional). Defaults to empty string for first perp DEX. Spot open orders are only included with the first perp DEX.</td></tr></tbody></table>

## Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "frontendOpenOrders",
    "user": "0x0000000000000000000000000000000000000000"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'frontendOpenOrders',
        'user': '0x0000000000000000000000000000000000000000'
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'frontendOpenOrders',
    user: '0x0000000000000000000000000000000000000000'
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field              | Type    | Description                                                                                                 |
| ------------------ | ------- | ----------------------------------------------------------------------------------------------------------- |
| `coin`             | string  | Asset symbol                                                                                                |
| `isPositionTpsl`   | boolean | Whether this is a position TP/SL order                                                                      |
| `isTrigger`        | boolean | Whether this is a trigger order                                                                             |
| `limitPx`          | string  | Limit price                                                                                                 |
| `oid`              | int     | Order ID                                                                                                    |
| `orderType`        | string  | Order type (e.g. `"Limit"`, `"Stop Market"`, `"Stop Limit"`, `"Take Profit Market"`, `"Take Profit Limit"`) |
| `origSz`           | string  | Original order size                                                                                         |
| `reduceOnly`       | boolean | Whether this is a reduce-only order                                                                         |
| `side`             | string  | `"A"` (sell) or `"B"` (buy)                                                                                 |
| `sz`               | string  | Remaining order size                                                                                        |
| `timestamp`        | int     | Order creation timestamp (ms)                                                                               |
| `triggerCondition` | string  | Trigger condition (e.g. `"N/A"`, `"tp"`, `"sl"`)                                                            |
| `triggerPx`        | string  | Trigger price for stop/take-profit orders                                                                   |

<details>

<summary>Response</summary>

```json
[
  {
    "coin": "BTC",
    "isPositionTpsl": false,
    "isTrigger": false,
    "limitPx": "29792.0",
    "oid": 91490942,
    "orderType": "Limit",
    "origSz": "5.0",
    "reduceOnly": false,
    "side": "A",
    "sz": "5.0",
    "timestamp": 1681247412573,
    "triggerCondition": "N/A",
    "triggerPx": "0.0"
  }
]
```

</details>


# Historical data

#### **Retrieve user's fills**

{% content-ref url="/pages/muw60fyzOPMLNXeSTVz0" %}
[userFills](/readme/rest-api/historical-data/userfills)
{% endcontent-ref %}

#### **Retrieve user's fills&#x20;*****within a specified time range***

{% content-ref url="/pages/W2wpRuaejvD5incn0BWJ" %}
[userFillsByTime](/readme/rest-api/historical-data/userfillsbytime)
{% endcontent-ref %}

#### **Retrieve user's TWAP slice fills**

{% content-ref url="/pages/9Dxfo3NAp2w7gYN2uNPD" %}
[userTwapSliceFills](/readme/rest-api/historical-data/usertwapslicefills)
{% endcontent-ref %}

#### **Retrieve user's funding history**

{% content-ref url="/pages/t649jcP3T2VGqnaso3Um" %}
[userFunding](/readme/rest-api/historical-data/userfunding)
{% endcontent-ref %}

#### **Retrieve user's non funding ledger history**

{% content-ref url="/pages/TqhO5Je4abcjOtl7CZ9I" %}
[userNonFundingLedgerUpdates](/readme/rest-api/historical-data/usernonfundingledgerupdates)
{% endcontent-ref %}

#### **Retrieve builder fills**

{% content-ref url="/pages/wrrR1FBA1VbuSIiXhK5s" %}
[builderFills](/readme/rest-api/historical-data/builderfills)
{% endcontent-ref %}

#### **Retrieve builder fills&#x20;*****within a specified time range***

{% content-ref url="/pages/9lX2OKs6p2nbICBIvsS1" %}
[builderFillsByTime](/readme/rest-api/historical-data/builderfillsbytime)
{% endcontent-ref %}

#### **Retrieve user's TWAP summaries**

{% content-ref url="/pages/ULg4Sz33rgOCBov2W8nL" %}
[userTwapSummaries](/readme/rest-api/historical-data/usertwapsummaries)
{% endcontent-ref %}

#### **Retrieve funding history for a coin**

{% content-ref url="/pages/OhWTqinAKt9QjIeFvPQs" %}
[fundingHistory](/readme/rest-api/historical-data/fundinghistory)
{% endcontent-ref %}

#### **Retrieve user's historical orders**

{% content-ref url="/pages/iP8Ei3ysTQ55vR96J3zk" %}
[historicalOrders](/readme/rest-api/historical-data/historicalorders)
{% endcontent-ref %}

#### **Look up a single order's latest status by oid or cloid**

{% content-ref url="/pages/hEpzMvitd31e8aQgnTr2" %}
[orderStatusByOid](/readme/rest-api/historical-data/orderstatusbyoid)
{% endcontent-ref %}

#### **Retrieve builder orders&#x20;*****within a specified time range***

{% content-ref url="/pages/1lJ9uUhXeofM3wg0jF3K" %}
[builderOrdersByTime](/readme/rest-api/historical-data/builderordersbytime)
{% endcontent-ref %}

#### **Retrieve user's leverage change history**

{% content-ref url="/pages/4QJrvNc4JEHfnTB5dm0n" %}
[userLeverageUpdatesByTime](/readme/rest-api/historical-data/userleverageupdatesbytime)
{% endcontent-ref %}

#### **Retrieve user's isolated margin update history**

{% content-ref url="/pages/mQXNUN1Wen96CGQxHy9F" %}
[userIsolatedMarginUpdatesByTime](/readme/rest-api/historical-data/userisolatedmarginupdatesbytime)
{% endcontent-ref %}


# userFills

Get the 2000 latest fills of a certain user. Includes twap fills.

Get the latest fills of a certain user. Includes twap fills.

{% hint style="info" %}
**All data fully available from 28-07-2025. We have performed a full backfill of all fills the HL native API offered, meaning that we have full historical data for most traders except for some very high volume addresses. TWAP fills are included from 02-08-2025.**
{% endhint %}

## POST Request

<table><thead><tr><th width="161.9998779296875">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"userFills"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr><tr><td><code>builder</code></td><td>string</td><td>Filter to fills routed through this builder address (0x-prefixed, 42 characters). Omit (or send <code>null</code>) for no filtering. A malformed, empty or non-string value is a <code>400</code> rather than a silently unfiltered result (optional)</td></tr><tr><td><code>aggregateByTime</code></td><td>boolean</td><td><code>true</code> or <code>false</code> false by default (optional)</td></tr><tr><td><code>dex</code></td><td>string</td><td>i.e. "xyz" or "main_dex" or dont pass for no filtering (optional)</td></tr><tr><td><code>limit</code></td><td>integer</td><td>Max results to return, default 2000 (optional)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "userFills",
    "user": "0x0000000000000000000000000000000000000000"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'userFills',
        'user': '0x0000000000000000000000000000000000000000'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'userFills',
        user: '0x0000000000000000000000000000000000000000'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field           | Type    | Description                                     |
| --------------- | ------- | ----------------------------------------------- |
| `coin`          | string  | Asset symbol                                    |
| `px`            | string  | Fill price                                      |
| `sz`            | string  | Fill size                                       |
| `side`          | string  | `"A"` (sell) or `"B"` (buy)                     |
| `time`          | int     | Fill timestamp (ms)                             |
| `startPosition` | string  | Position size before the fill                   |
| `dir`           | string  | Direction (e.g. `"Open Long"`, `"Close Short"`) |
| `closedPnl`     | string  | Closed PnL from this fill                       |
| `hash`          | string  | Transaction hash                                |
| `oid`           | int     | Order ID                                        |
| `crossed`       | boolean | Whether the order crossed the spread            |
| `fee`           | string  | Fee amount                                      |
| `tid`           | int     | Trade ID                                        |
| `cloid`         | string? | Client order ID (optional)                      |
| `builderFee`    | string? | Builder fee (optional)                          |
| `deployerFee`   | string? | Deployer fee (optional, HIP-3 fills only)       |
| `priorityGas`   | string? | Priority gas fee in HYPE (optional)             |
| `feeToken`      | string  | Fee token (e.g. `"USDC"`)                       |
| `builder`       | string? | Builder address (optional)                      |
| `twapId`        | int?    | TWAP order ID (null if not a TWAP fill)         |
| `txIndex`       | int     | Transaction index                               |

<details>

<summary>Response</summary>

```json
[
  {
    "coin": "BTC",
    "px": "45000.00",
    "sz": "0.5",
    "side": "B",
    "time": 1234567890123,
    "startPosition": "1.0",
    "dir": "Open Long",
    "closedPnl": "0.00",
    "hash": "0x1234567890abcdef",
    "oid": 123456,
    "crossed": false,
    "fee": "22.50",
    "tid": 789012,
    "cloid": "client-123",
    "builderFee": "0.10",
    "deployerFee": "0.05",
    "priorityGas": null,
    "feeToken": "USDC",
    "builder": "0x...",
    "twapId": 123456,
    "txIndex": 12
  }
]
```

</details>


# userFillsByTime

Get trading fills for a single user within a time range. Includes twap fills.

Get trading fills for a single user within a time range. Includes twap fills.

{% hint style="info" %}
**All data fully available from 28-07-2025. We have performed a full backfill of all fills the HL native API offered, meaning that we have full historical data for most traders except for some very high volume addresses. TWAP fills are included from 02-08-2025.**
{% endhint %}

## POST Request

<table><thead><tr><th width="161.9998779296875">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"userFillsByTime"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr><tr><td><code>startTime</code></td><td>integer</td><td>Earliest fill time to include (Unix ms, inclusive). Skipped when <code>cursor</code> is used. Either <code>startTime</code> or <code>cursor</code> must be supplied</td></tr><tr><td><code>endTime</code></td><td>integer</td><td>Latest fill time to include (Unix ms, inclusive). Default: now (optional)</td></tr><tr><td><code>cursor</code></td><td>string</td><td>Composite of <code>time</code> and <code>txIndex</code> with <code>"_"</code> separator (e.g. <code>"1234567890000_23"</code>). Take from the <strong>last record</strong> of the previous response (optional)</td></tr><tr><td><code>builder</code></td><td>string</td><td>Filter to fills routed through this builder address (0x-prefixed, 42 characters). Omit (or send <code>null</code>) for no filtering. A malformed, empty or non-string value is a <code>400</code> rather than a silently unfiltered result (optional)</td></tr><tr><td><code>aggregateByTime</code></td><td>boolean</td><td><code>true</code> or <code>false</code>, <code>false</code> by default (optional)</td></tr><tr><td><code>dex</code></td><td>string</td><td>i.e. <code>"xyz"</code> or <code>"main_dex"</code>, or omit for no filtering (optional)</td></tr><tr><td><code>limit</code></td><td>integer</td><td>Max results to return, default 2000 (optional)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "userFillsByTime",
    "user": "0x0000000000000000000000000000000000000000",
    "startTime": 1234567890000,
    "endTime": 1234567900000,
    "cursor": "1234567890000_23"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'userFillsByTime',
        'user': '0x0000000000000000000000000000000000000000',
        'startTime': 1234567890000,
        'endTime': 1234567900000,
        'cursor': '1234567890000_12'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'userFillsByTime',
        user: '0x0000000000000000000000000000000000000000',
        startTime: 1234567890000,
        endTime: 1234567900000,
        cursor: '1234567890000_12'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field           | Type    | Description                                                     |
| --------------- | ------- | --------------------------------------------------------------- |
| `coin`          | string  | Asset symbol                                                    |
| `px`            | string  | Fill price                                                      |
| `sz`            | string  | Fill size                                                       |
| `side`          | string  | `"A"` (sell) or `"B"` (buy)                                     |
| `time`          | int     | Fill timestamp (ms)                                             |
| `startPosition` | string  | Position size before the fill                                   |
| `dir`           | string  | Direction (e.g. `"Open Long"`, `"Close Short"`, `"Settlement"`) |
| `closedPnl`     | string  | Closed PnL from this fill                                       |
| `hash`          | string  | Transaction hash                                                |
| `oid`           | int     | Order ID                                                        |
| `crossed`       | boolean | Whether the order crossed the spread                            |
| `fee`           | string  | Fee amount                                                      |
| `tid`           | int     | Trade ID                                                        |
| `cloid`         | string? | Client order ID (optional)                                      |
| `builderFee`    | string? | Builder fee (optional)                                          |
| `deployerFee`   | string? | Deployer fee (optional, HIP-3 fills only)                       |
| `priorityGas`   | string? | Priority gas fee in HYPE (optional)                             |
| `feeToken`      | string  | Fee token (e.g. `"USDC"`)                                       |
| `twapId`        | int?    | TWAP order ID (null if not a TWAP fill)                         |
| `txIndex`       | int     | Transaction index                                               |

<details>

<summary>Response</summary>

```json
[
  {
    "coin": "hyna:LIT",
    "px": "3.38",
    "sz": "306.0635",
    "side": "A",
    "time": 1766411264116,
    "startPosition": "306.0635",
    "dir": "Settlement",
    "closedPnl": "0.00",
    "hash": "0xe9700f27f4c60944eae90431e255630202d5000d8fc928168d38ba7ab3c9e32f",
    "oid": 276429539434,
    "crossed": false,
    "fee": "0.00",
    "tid": 587851719766407,
    "feeToken": "USDE",
    "twapId": null,
    "txIndex": 1
  }
]
```

</details>


# userTwapSliceFills

Get the 2000 most recent TWAP slice fills for a user.

{% hint style="info" %}
**All data fully available from 28-07-2025. We have performed a full backfill of all fills the HL native API offered, meaning that we have full historical data for most traders except for some very high volume addresses. TWAP fills are included from 02-08-2025.**
{% endhint %}

Returns fills that were executed as part of a TWAP (Time-Weighted Average Price) order. Each fill is an individual "slice" of the TWAP execution. Only fills with a non-null `twapId` are returned.

## POST Request

<table><thead><tr><th width="161.9998779296875">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"userTwapSliceFills"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "userTwapSliceFills",
    "user": "0x0000000000000000000000000000000000000000"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'userTwapSliceFills',
        'user': '0x0000000000000000000000000000000000000000'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'userTwapSliceFills',
        user: '0x0000000000000000000000000000000000000000'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field           | Type    | Description                                            |
| --------------- | ------- | ------------------------------------------------------ |
| `coin`          | string  | Asset symbol                                           |
| `px`            | string  | Fill price                                             |
| `sz`            | string  | Fill size                                              |
| `side`          | string  | `"A"` (sell) or `"B"` (buy)                            |
| `time`          | int     | Fill timestamp (ms)                                    |
| `startPosition` | string  | Position size before the fill                          |
| `dir`           | string  | Direction (e.g. `"Open Long"`, `"Open Short"`)         |
| `closedPnl`     | string  | Closed PnL from this fill                              |
| `hash`          | string  | Transaction hash (always `0x000...000` for TWAP fills) |
| `oid`           | int     | Order ID                                               |
| `crossed`       | boolean | Whether the order crossed the spread                   |
| `fee`           | string  | Fee amount                                             |
| `tid`           | int     | Trade ID                                               |
| `cloid`         | string? | Client order ID (optional)                             |
| `builderFee`    | string? | Builder fee (optional)                                 |
| `deployerFee`   | string? | Deployer fee (optional, HIP-3 fills only)              |
| `feeToken`      | string  | Fee token (e.g. `"USDC"`)                              |
| `twapId`        | int     | TWAP order ID                                          |
| `txIndex`       | int     | Transaction index                                      |

<details>

<summary>Response</summary>

```json
[
{
"coin": "BTC",
"px": "67950.00",
"sz": "0.00108",
"side": "A",
"time": 1772096268036,
"startPosition": "-1.78931",
"dir": "Open Short",
"closedPnl": "0.00",
"hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"oid": 330647838320,
"crossed": true,
"fee": "0.033023",
"tid": 792432692404914,
"feeToken": "USDC",
"twapId": 1628419,
"txIndex": 12
}
]
```

</details>

<details>

<summary>Notes</summary>

* Returns at most 2000 most recent TWAP slice fills, ordered by time descending
* TWAP fills always have a hash of `0x000...000`
* The `twapId` field identifies which TWAP order the slice belongs to — multiple fills can share the same `twapId`
* Unlike Hyperliquid's native endpoint which wraps fills as `{ "fill": {...}, "twapId": N }`, Hydromancer returns fills in the same flat format as `userFills`

</details>


# userTwapSummaries

Get aggregated TWAP order summaries for a user.

{% hint style="info" %}
**All data fully available from 28-07-2025. We have performed a full backfill of all fills the HL native API offered, meaning that we have full historical data for most traders except for some very high volume addresses. TWAP fills are included from 02-08-2025.**
{% endhint %}

{% hint style="info" %}
💧New endpoint - this endpoint is not a part of original Hyperliquid API and is added by us for builder convenience.
{% endhint %}

Returns one summary per TWAP order for a user, aggregating all slice fills that share the same `twapId`. Includes the volume-weighted average price, total size, total fees, total closed PnL, number of slices, and the time range of execution.

## POST Request

<table><thead><tr><th width="161.9998779296875">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"userTwapSummaries"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "userTwapSummaries",
    "user": "0x0000000000000000000000000000000000000000"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'userTwapSummaries',
        'user': '0x0000000000000000000000000000000000000000'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'userTwapSummaries',
        user: '0x0000000000000000000000000000000000000000'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

<details>

<summary>Response</summary>

{% hint style="warning" %}
**Number formatting:** Numeric fields (`avgPx`, `sz`, `fee`, `closedPnl`) are emitted in normalized form — trailing zeros are stripped and the decimal point is dropped for integers (e.g. `"0.054"` not `"0.05400"`, `"0"` not `"0.00"`). Compare values numerically, not by string equality.
{% endhint %}

```json
[
{
"user": "0x0000000000000000000000000000000000000000",
"twapId": 1628419,
"coin": "BTC",
"side": "A",
"avgPx": "67832.45",
"sz": "0.054",
"fee": "1.65115",
"closedPnl": "0",
"nSlices": 50,
"firstFillTime": 1772092668036,
"lastFillTime": 1772096268036
}
]
```

</details>

<details>

<summary>Response Fields</summary>

| Field           | Type   | Description                                          |
| --------------- | ------ | ---------------------------------------------------- |
| `user`          | string | User address                                         |
| `twapId`        | number | TWAP order identifier                                |
| `coin`          | string | Asset symbol (e.g. `"BTC"`)                          |
| `side`          | string | `"B"` for buy, `"A"` for sell                        |
| `avgPx`         | string | Volume-weighted average fill price across all slices |
| `sz`            | string | Total size filled across all slices                  |
| `fee`           | string | Total fees paid across all slices                    |
| `closedPnl`     | string | Total closed PnL across all slices                   |
| `nSlices`       | number | Number of individual slice fills executed            |
| `firstFillTime` | number | Timestamp (ms) of the first slice fill               |
| `lastFillTime`  | number | Timestamp (ms) of the last slice fill                |

</details>

<details>

<summary>Notes</summary>

* Returns at most 500 most recent TWAP summaries, ordered by last fill time descending
* Each summary aggregates all slice fills that share the same `twapId` — use `userTwapSliceFills` to get the individual fills
* `avgPx` is the volume-weighted average price: `sum(px * sz) / sum(sz)` across all slices
* Summaries update incrementally as new TWAP slices are executed

</details>


# userTwapStatusesByTime

Paginate a user's TWAP order status events by time, oldest-first.

Returns TWAP status events for a user with `time` ≥ `startTime` (or after a `cursor`), ordered **oldest-first** by `time` then `tx_index`.

For pagination: pass `startTime` for the first page, then on each subsequent page pass the `cursor` `"{time}_{tx_index}"` built from the **last record** of the previous response. When `cursor` is supplied, `startTime` is ignored and the boundary record is excluded from the next page (no duplicates).

`dex` is optional. Omit to return statuses from every perp DEX. Set to `"main_dex"` for the native Hyperliquid dex, or to a HIP-3 dex name (e.g. `"xyz"`) to scope to that dex.

**note: TWAP status events are retained for \~24h on the server, so this endpoint can return at most one day of history.**

## POST Request

<table><thead><tr><th width="161.9998779296875">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"userTwapStatusesByTime"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr><tr><td><code>startTime</code></td><td>integer</td><td>Earliest <code>time</code> to include (Unix ms, inclusive). Skipped when <code>cursor</code> is used. Either <code>startTime</code> or <code>cursor</code> must be supplied</td></tr><tr><td><code>endTime</code></td><td>integer</td><td>Latest <code>time</code> to include (Unix ms, inclusive). Default: now (optional)</td></tr><tr><td><code>cursor</code></td><td>string</td><td>Composite of <code>time</code> and <code>tx_index</code> with <code>"_"</code> separator (e.g. <code>"1734571490123_12"</code>). Take from the <strong>last record</strong> of the previous response (optional)</td></tr><tr><td><code>limit</code></td><td>integer</td><td>Max results to return. Default 100, max 500 (optional)</td></tr><tr><td><code>dex</code></td><td>string</td><td>Scope to a single perp DEX. <code>"main_dex"</code> for the native Hyperliquid dex, or a HIP-3 dex name (e.g. <code>"xyz"</code>). Omit for all dexes (optional)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
# First page
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "userTwapStatusesByTime",
    "user": "0x0000000000000000000000000000000000000000",
    "startTime": 0,
    "limit": 100
  }'

# Next page — cursor built from the last record of the previous response
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "userTwapStatusesByTime",
    "user": "0x0000000000000000000000000000000000000000",
    "cursor": "1734571490123_12",
    "limit": 100
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

url = 'https://api.hydromancer.xyz/info'
headers = {
    'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
    'Content-Type': 'application/json',
}
user = '0x0000000000000000000000000000000000000000'
limit = 500

params = {'type': 'userTwapStatusesByTime', 'user': user, 'startTime': 0, 'limit': limit}
while True:
    page = requests.post(url, json=params, headers=headers).json()
    if not page:
        break
    for status in page:
        ...  # process status event
    if len(page) < limit:
        break
    last = page[-1]
    params = {
        'type': 'userTwapStatusesByTime',
        'user': user,
        'cursor': f"{last['time']}_{last['tx_index']}",
        'limit': limit,
    }
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const url = 'https://api.hydromancer.xyz/info';
const headers = {
    'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
    'Content-Type': 'application/json',
};
const user = '0x0000000000000000000000000000000000000000';
const limit = 500;

let params = { type: 'userTwapStatusesByTime', user, startTime: 0, limit };
while (true) {
    const { data: page } = await axios.post(url, params, { headers });
    if (!page.length) break;
    for (const status of page) { /* process status event */ }
    if (page.length < limit) break;
    const last = page[page.length - 1];
    params = {
        type: 'userTwapStatusesByTime',
        user,
        cursor: `${last.time}_${last.tx_index}`,
        limit,
    };
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

JSON array of TWAP status records, ordered **oldest-first** by `time` then `tx_index`.

| Field            | Type    | Description                                                                                                                                                           |
| ---------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `time`           | int     | Block time when the status was emitted (Unix ms) — **first half of the next-page `cursor`**                                                                           |
| `block_number`   | int     | L1 block number containing the status update                                                                                                                          |
| `tx_index`       | int     | Transaction index within the block — **second half of the next-page `cursor`**                                                                                        |
| `twap_id`        | int     | TWAP order identifier (matches `twap_id` on `userTwapSliceFills` / `userTwapSummaries`)                                                                               |
| `user`           | string  | Ethereum address                                                                                                                                                      |
| `coin`           | string  | Asset symbol                                                                                                                                                          |
| `side`           | string  | `"B"` (buy) or `"A"` (sell)                                                                                                                                           |
| `sz`             | string  | Total intended TWAP size, in contracts                                                                                                                                |
| `executed_sz`    | string  | Cumulative executed size at the time of this status, in contracts                                                                                                     |
| `executed_ntl`   | string  | Cumulative executed notional at the time of this status (USDC)                                                                                                        |
| `minutes`        | int     | TWAP duration, in minutes                                                                                                                                             |
| `reduce_only`    | boolean | `true` if the TWAP order is reduce-only                                                                                                                               |
| `randomize`      | boolean | `true` if slice timing is randomized                                                                                                                                  |
| `twap_timestamp` | int     | TWAP order timestamp (Unix ms) as recorded by the protocol                                                                                                            |
| `status`         | string  | Lifecycle status string (`"activated"`, `"finished"`, `"terminated"`, `"stopped"`, `"waitingForTrigger"`) or — when `is_error` is `true` — the protocol error message |
| `is_error`       | boolean | `true` if `status` carries an error message rather than a normal lifecycle string                                                                                     |
| `stop_px`        | string  | Stop price attached to the TWAP, or `null` if none                                                                                                                    |
| `trigger_px`     | string  | Trigger price for a trigger TWAP (`"waitingForTrigger"`), or `null` if none                                                                                           |
| `trigger_above`  | boolean | For trigger TWAPs: `true` = activates when mark price rises above `trigger_px`, `false` = below. `null` if no trigger                                                 |


# builderFills

Get the 2000 latest fills submitted by a builder.

{% hint style="info" %}
**Data available from 28-07-2025**
{% endhint %}

## POST Request

<table><thead><tr><th width="161.9998779296875">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"builderFills"</code></td></tr><tr><td><code>builder</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr><tr><td><code>limit</code></td><td>integer</td><td>Max results to return, default and max 2000 (optional)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "builderFills",
    "builder": "0x0000000000000000000000000000000000000000"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'builderFills',
        'builder': '0x0000000000000000000000000000000000000000'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'builderFills',
        builder: '0x0000000000000000000000000000000000000000'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field           | Type    | Description                                                      |
| --------------- | ------- | ---------------------------------------------------------------- |
| `coin`          | string  | Asset symbol                                                     |
| `px`            | string  | Fill price                                                       |
| `sz`            | string  | Fill size                                                        |
| `side`          | string  | `"A"` (sell) or `"B"` (buy)                                      |
| `time`          | int     | Fill timestamp (ms)                                              |
| `startPosition` | string  | Position size before the fill                                    |
| `dir`           | string  | Direction (e.g. `"Open Long"`, `"Open Short"`, `"Short > Long"`) |
| `closedPnl`     | string  | Closed PnL from this fill                                        |
| `hash`          | string  | Transaction hash                                                 |
| `oid`           | int     | Order ID                                                         |
| `crossed`       | boolean | Whether the order crossed the spread                             |
| `fee`           | string  | Fee amount                                                       |
| `tid`           | int     | Trade ID                                                         |
| `builderFee`    | string  | Builder fee                                                      |
| `deployerFee`   | string? | Deployer fee (HIP-3 fills only)                                  |
| `priorityGas`   | string? | Priority gas fee in HYPE (optional)                              |
| `feeToken`      | string  | Fee token (e.g. `"USDC"`)                                        |
| `user`          | string  | User address who placed the order                                |
| `twapId`        | int     | TWAP order ID (null if not a TWAP fill)                          |
| `cloid`         | string? | Client order ID (optional)                                       |
| `txIndex`       | int     | Transaction index                                                |

<details>

<summary>Response</summary>

```json
[
  {
    "coin": "BTC",
    "px": "71070.00",
    "sz": "0.00541",
    "side": "A",
    "time": 1773429781878,
    "startPosition": "0.00",
    "dir": "Open Short",
    "closedPnl": "0.00",
    "hash": "0xa33ab861b80567f1a4b40436ff72410204530047530886c3470363b4770941dc",
    "oid": 348153004784,
    "crossed": true,
    "fee": "0.211467",
    "tid": 491098859095794,
    "builderFee": "0.038448",
    "deployerFee": "0.019224",
    "priorityGas": null,
    "feeToken": "USDC",
    "user": "0x5e24ba0e5753fb533e8ac74c63f00fa73488c484",
    "twapId": null,
    "txIndex": 21
  }
]
```

</details>


# builderFillsByTime

Get fills submitted by a builder in a certain time range

Get fills submitted by a builder in a certain time range.

{% hint style="info" %}
💧New endpoint - this endpoint is not a part of original Hyperliquid API and is added by us for builder convenience.
{% endhint %}

{% hint style="info" %}
**Data available from 28-07-2025**
{% endhint %}

## POST Request

<table><thead><tr><th width="164.6666259765625">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be "builderFillsByTime"</td></tr><tr><td><code>builder</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr><tr><td><code>startTime</code></td><td>integer</td><td>Start timestamp in milliseconds (skipped when cursor is used)</td></tr><tr><td><code>endTime</code></td><td>integer</td><td>End timestamp in milliseconds (optional)</td></tr><tr><td><code>cursor</code></td><td>string</td><td>Composite of time and txIndex with "_" separator (optional)</td></tr><tr><td><code>aggregateByTime</code></td><td>boolean</td><td>Collapse an order's partial fills at the same timestamp into a single fill. <code>true</code> or <code>false</code>, <code>false</code> by default (optional)</td></tr><tr><td><code>limit</code></td><td>integer</td><td>Max results to return, default and max 2000 (optional)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "builderFillsByTime",
    "builder": "0x0000000000000000000000000000000000000000",
    "startTime": 1234567890000,
    "endTime": 1234567900000,
    "cursor": "1234567890000_12"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'builderFillsByTime',
        'builder': '0x0000000000000000000000000000000000000000',
        'startTime': 1234567890000,
        'endTime': 1234567900000,
        'cursor': '1234567890000_12'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'builderFillsByTime',
        builder: '0x0000000000000000000000000000000000000000',
        startTime: 1234567890000,
        endTime: 1234567900000,
        cursor: '1234567890000_12'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field           | Type    | Description                                                      |
| --------------- | ------- | ---------------------------------------------------------------- |
| `coin`          | string  | Asset symbol                                                     |
| `px`            | string  | Fill price                                                       |
| `sz`            | string  | Fill size                                                        |
| `side`          | string  | `"A"` (sell) or `"B"` (buy)                                      |
| `time`          | int     | Fill timestamp (ms)                                              |
| `startPosition` | string  | Position size before the fill                                    |
| `dir`           | string  | Direction (e.g. `"Open Long"`, `"Open Short"`, `"Short > Long"`) |
| `closedPnl`     | string  | Closed PnL from this fill                                        |
| `hash`          | string  | Transaction hash                                                 |
| `oid`           | int     | Order ID                                                         |
| `crossed`       | boolean | Whether the order crossed the spread                             |
| `cloid`         | string? | Client order ID (optional)                                       |
| `fee`           | string  | Fee amount                                                       |
| `tid`           | int     | Trade ID                                                         |
| `builderFee`    | string? | Builder fee (optional)                                           |
| `deployerFee`   | string? | Deployer fee (HIP-3 fills only)                                  |
| `priorityGas`   | string? | Priority gas fee in HYPE (optional)                              |
| `feeToken`      | string  | Fee token (e.g. `"USDC"`)                                        |
| `user`          | string  | User address who placed the order                                |
| `twapId`        | int     | TWAP order ID (null if not a TWAP fill)                          |
| `txIndex`       | int     | Transaction index                                                |

<details>

<summary>Response</summary>

```json
[
  {
    "coin": "BTC",
    "px": "71070.00",
    "sz": "0.00541",
    "side": "A",
    "time": 1773429781878,
    "startPosition": "0.00",
    "dir": "Open Short",
    "closedPnl": "0.00",
    "hash": "0xa33ab861b80567f1a4b40436ff72410204530047530886c3470363b4770941dc",
    "oid": 348153004784,
    "crossed": true,
    "fee": "0.211467",
    "tid": 491098859095794,
    "builderFee": "0.038448",
    "deployerFee": "0.019224",
    "priorityGas": null,
    "feeToken": "USDC",
    "user": "0x5e24ba0e5753fb533e8ac74c63f00fa73488c484",
    "twapId": null,
    "txIndex": 21
  }
]
```

</details>


# builderApprovedFillsByTime

Fills that occurred while a user had an active builder-fee approval for your builder address.

{% hint style="info" %}
This is **not** the same as [builderFillsByTime](/readme/rest-api/historical-data/builderfillsbytime).

`builderFillsByTime` returns fills that were *routed through* your builder — the order carried your builder address. `builderApprovedFillsByTime` returns **every** fill a user made while they had approved your builder, including trades placed elsewhere and trades with no builder attached at all.

A user who approves your builder and then trades on another frontend appears here, and not in `builderFillsByTime`.
{% endhint %}

### Why you need this

Some fills can never carry a builder code, so they are invisible to `builderFillsByTime` no matter how the user trades:

* **Liquidations** — the fill is generated by the protocol, not by an order the user signed, so there is no builder to attach.
* **TWAP sub-fills** — the individual slices carry no builder code.

Attributing by *approval* rather than by *routing* captures both, so activity from your users stops disappearing from your numbers the moment it takes one of these paths.

{% hint style="warning" %}
The flip side: approval-based attribution reflects what a user **could** route through you, not what they did. A user who holds their own private key can trade directly or through another builder while your approval is still active, and those fills appear here. Treat this endpoint as "activity by users who approved me", not as "revenue routed through me" — for the latter, use [builderFillsByTime](/readme/rest-api/historical-data/builderfillsbytime).
{% endhint %}

## POST Request

<table><thead><tr><th width="180">Field</th><th width="110">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Required. <code>"builderApprovedFillsByTime"</code></td></tr><tr><td><code>builder</code></td><td>string</td><td>Required. Builder address, 42-char hex.</td></tr><tr><td><code>startTime</code></td><td>number</td><td>Required unless <code>cursor</code> is given. Inclusive, milliseconds.</td></tr><tr><td><code>endTime</code></td><td>number</td><td>Optional. Inclusive, milliseconds.</td></tr><tr><td><code>cursor</code></td><td>string</td><td>Optional. Continue from a previous page. Format <code>"{time}_{txIndex}"</code>.</td></tr><tr><td><code>limit</code></td><td>number</td><td>Optional. Default and maximum 2000.</td></tr></tbody></table>

Results are returned oldest-first, ordered by `(time, txIndex)`.

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{
    "type": "builderApprovedFillsByTime",
    "builder": "0x1924b8561eef20e70ede628a296175d358be80e5",
    "startTime": 1786000000000,
    "limit": 100
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

resp = requests.post(
    "https://api.hydromancer.xyz/info",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "type": "builderApprovedFillsByTime",
        "builder": "0x1924b8561eef20e70ede628a296175d358be80e5",
        "startTime": 1786000000000,
        "limit": 100,
    },
)
fills = resp.json()
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
const resp = await fetch("https://api.hydromancer.xyz/info", {
  method: "POST",
  headers: { "Content-Type": "application/json", "X-API-Key": "YOUR_API_KEY" },
  body: JSON.stringify({
    type: "builderApprovedFillsByTime",
    builder: "0x1924b8561eef20e70ede628a296175d358be80e5",
    startTime: 1786000000000,
    limit: 100,
  }),
});
const fills = await resp.json();
```

{% endtab %}
{% endtabs %}

***

## Pagination

Take the last returned fill and build `cursor` as `"{time}_{txIndex}"`, then repeat the request with that `cursor` instead of `startTime`. A page shorter than `limit` means you have reached the end of the range.

## Semantics

An approval applies from the block it lands in, and a revocation likewise. A fill that happened while an approval was active stays attributed permanently — revoking does not remove past fills from this endpoint.

## Response Fields

An array of fill objects, each including the `user` that made the fill — the same shape as [builderFillsByTime](/readme/rest-api/historical-data/builderfillsbytime), plus a `builder` field.

The `builder` field is the builder the fill was **routed through**, which is a separate question from why the fill is in this response. It is usually `null`: liquidations and TWAP sub-fills carry no builder code, and a user who approved you can trade through anyone. `builderFillsByTime` does not return this field, because there every fill is routed through the builder you asked for.

<details>

<summary>Response</summary>

```json
[
  {
    "coin": "BTC",
    "px": "50000.0",
    "sz": "1.5",
    "side": "B",
    "time": 1786000001000,
    "startPosition": "0.0",
    "dir": "Open Long",
    "closedPnl": "0.0",
    "hash": "0x...",
    "oid": 12345,
    "crossed": false,
    "fee": "0.5",
    "tid": 20001,
    "feeToken": "USDC",
    "builder": null,
    "user": "0x0000000000000000000000000000000000000001",
    "txIndex": 0
  }
]
```

</details>


# builderApprovedFundingByTime

Hourly funding payments made by users who had an active builder-fee approval for your builder address.

The funding counterpart of [builderApprovedFillsByTime](/readme/rest-api/historical-data/builderapprovedfillsbytime): every hourly funding payment made by a user while they had approved your builder, across all of those users at once. Each row is exactly a [userFunding](/readme/rest-api/historical-data/userfunding) row with the paying `user` added.

{% hint style="info" %}
**Attribution is by approval, not by routing.** A funding payment has no builder code and no order behind it — it is charged by the protocol once an hour on every open position — so it can only be attributed by asking who the user had approved at that block. A user who approved your builder and then opened a position through another frontend still appears here.
{% endhint %}

### Why you need this

Funding is often the largest recurring cost or income for a perp position, and it is invisible to every routing-based endpoint. If you report net PnL for the users who approved you, fills alone overstate it; this endpoint supplies the missing leg without you having to poll `userFunding` per user.

## POST Request

<table><thead><tr><th width="180">Field</th><th width="110">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Required. <code>"builderApprovedFundingByTime"</code></td></tr><tr><td><code>builder</code></td><td>string</td><td>Required. Builder address, 42-char hex.</td></tr><tr><td><code>startTime</code></td><td>number</td><td>Required unless <code>cursor</code> is given. Inclusive, milliseconds.</td></tr><tr><td><code>endTime</code></td><td>number</td><td>Optional. Inclusive, milliseconds.</td></tr><tr><td><code>cursor</code></td><td>string</td><td>Optional. Continue from a previous page. Format <code>"{time}_{user}_{coin}"</code>.</td></tr><tr><td><code>limit</code></td><td>number</td><td>Optional. Default and maximum 2000.</td></tr></tbody></table>

Results are returned oldest-first, ordered by `(time, user, coin)`.

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{
    "type": "builderApprovedFundingByTime",
    "builder": "0x1924b8561eef20e70ede628a296175d358be80e5",
    "startTime": 1786000000000,
    "limit": 100
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

resp = requests.post(
    "https://api.hydromancer.xyz/info",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "type": "builderApprovedFundingByTime",
        "builder": "0x1924b8561eef20e70ede628a296175d358be80e5",
        "startTime": 1786000000000,
        "limit": 100,
    },
)
funding = resp.json()
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
const resp = await fetch("https://api.hydromancer.xyz/info", {
  method: "POST",
  headers: { "Content-Type": "application/json", "X-API-Key": "YOUR_API_KEY" },
  body: JSON.stringify({
    type: "builderApprovedFundingByTime",
    builder: "0x1924b8561eef20e70ede628a296175d358be80e5",
    startTime: 1786000000000,
    limit: 100,
  }),
});
const funding = await resp.json();
```

{% endtab %}
{% endtabs %}

***

## Pagination

Take the last returned row and build `cursor` as `"{time}_{user}_{delta.coin}"`, then repeat the request with that `cursor` instead of `startTime`. A page shorter than `limit` means you have reached the end of the range.

Funding is charged once an hour, and every payment of that hour carries the same `time`, so a page boundary usually falls **inside** an hour. That is why the cursor carries `user` and `coin` rather than a transaction index: it resumes exactly after the last row you saw without repeating or skipping the rest of the hour.

## Semantics

* **Hourly rows.** One row per `(user, coin)` position per funding hour, with the block timestamp of the funding event as `time`. There are no rows between funding hours.
* **Attributed at the block.** An approval applies from the block it lands in, and a revocation likewise. A payment that happened while an approval was active stays attributed permanently — revoking does not remove past rows from this endpoint.
* **Same row as `userFunding`.** `time`, `hash` and `delta` are byte-for-byte what [userFunding](/readme/rest-api/historical-data/userfunding) returns for that user; only `user` is added. `hash` is always the zero hash, as it is there, because funding is a protocol event with no transaction.

## Response Fields

| Field               | Type   | Description                                                                               |
| ------------------- | ------ | ----------------------------------------------------------------------------------------- |
| `user`              | string | The user who paid or received the funding, and who had approved your builder at the time. |
| `time`              | int    | Funding block timestamp (ms).                                                             |
| `hash`              | string | Always the zero hash.                                                                     |
| `delta`             | object | Funding payment details, identical to `userFunding`.                                      |
| `delta.type`        | string | Always `"funding"`.                                                                       |
| `delta.coin`        | string | Asset symbol.                                                                             |
| `delta.usdc`        | string | USDC amount of the funding payment (negative when paid).                                  |
| `delta.szi`         | string | Position size at the time of funding.                                                     |
| `delta.fundingRate` | string | Funding rate applied.                                                                     |

<details>

<summary>Response</summary>

```json
[
  {
    "user": "0x0000000000000000000000000000000000000001",
    "time": 1786000000066,
    "hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "delta": {
      "type": "funding",
      "coin": "BTC",
      "usdc": "0.014419",
      "szi": "-0.01",
      "fundingRate": "0.0000125"
    }
  }
]
```

</details>


# builderApprovedNonFundingLedgerUpdatesByTime

Deposits, withdrawals, transfers and other non-funding ledger updates made by users who had an active builder-fee approval for your builder address.

The ledger counterpart of [builderApprovedFillsByTime](/readme/rest-api/historical-data/builderapprovedfillsbytime): every non-funding ledger update — deposits, withdrawals, transfers, vault flows, liquidations and the rest — made by a user while they had approved your builder, across all of those users at once. Each row is exactly a [userNonFundingLedgerUpdates](/readme/rest-api/historical-data/usernonfundingledgerupdates) row with the `user` it was attributed to, their `role`, and the `txIndex` needed to page added.

{% hint style="info" %}
**Attribution is by approval, not by routing.** Ledger updates carry no builder code, so the only way to attribute one is to ask who the user had approved at that block. A deposit made through any frontend by a user who had approved your builder appears here.
{% endhint %}

### Why you need this

Deposits and withdrawals are the earliest and latest signals you have about a user: a first deposit precedes any fill, and a withdrawal often precedes churn. Funding aside, this is the rest of the money movement for the users who approved you, without polling `userNonFundingLedgerUpdates` per user.

## POST Request

<table><thead><tr><th width="180">Field</th><th width="110">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Required. <code>"builderApprovedNonFundingLedgerUpdatesByTime"</code></td></tr><tr><td><code>builder</code></td><td>string</td><td>Required. Builder address, 42-char hex.</td></tr><tr><td><code>startTime</code></td><td>number</td><td>Required unless <code>cursor</code> is given. Inclusive, milliseconds.</td></tr><tr><td><code>endTime</code></td><td>number</td><td>Optional. Inclusive, milliseconds.</td></tr><tr><td><code>cursor</code></td><td>string</td><td>Optional. Continue from a previous page. Format <code>"{time}_{txIndex}_{user}_{role}"</code>.</td></tr><tr><td><code>limit</code></td><td>number</td><td>Optional. Default and maximum 2000.</td></tr></tbody></table>

Results are returned oldest-first, ordered by `(time, txIndex, user, role)`.

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{
    "type": "builderApprovedNonFundingLedgerUpdatesByTime",
    "builder": "0x1924b8561eef20e70ede628a296175d358be80e5",
    "startTime": 1786000000000,
    "limit": 100
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

resp = requests.post(
    "https://api.hydromancer.xyz/info",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "type": "builderApprovedNonFundingLedgerUpdatesByTime",
        "builder": "0x1924b8561eef20e70ede628a296175d358be80e5",
        "startTime": 1786000000000,
        "limit": 100,
    },
)
updates = resp.json()
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
const resp = await fetch("https://api.hydromancer.xyz/info", {
  method: "POST",
  headers: { "Content-Type": "application/json", "X-API-Key": "YOUR_API_KEY" },
  body: JSON.stringify({
    type: "builderApprovedNonFundingLedgerUpdatesByTime",
    builder: "0x1924b8561eef20e70ede628a296175d358be80e5",
    startTime: 1786000000000,
    limit: 100,
  }),
});
const updates = await resp.json();
```

{% endtab %}
{% endtabs %}

***

## Pagination

Take the last returned row and build `cursor` as `"{time}_{txIndex}_{user}_{role}"`, then repeat the request with that `cursor` instead of `startTime`. A page shorter than `limit` means you have reached the end of the range.

Several updates land in one block and share `time`, and a self-transfer even shares `txIndex` and `user` across its two rows, so the cursor carries all four parts: it resumes exactly after the last row you saw without repeating or skipping the rest of the block.

## Semantics

* **One row per participating approving user.** A transfer names two users, and each is attributed independently. If the sender approved you, you get their row with `role: "sender"`; if the receiver approved you, you get theirs with `role: "receiver"`; if both did, you get both. `delta` is what `userNonFundingLedgerUpdates` shows that participant: `user` is always the sender and `destination` the receiver on either row, and the fee appears on the sender's row only — `role` is what tells you which side the row is for. Single-party updates such as deposits carry `role: "user"`.
* **Attributed at the block.** An approval applies from the block it lands in, and a revocation likewise. An update that happened while an approval was active stays attributed permanently — revoking does not remove past rows from this endpoint.
* **Same row as `userNonFundingLedgerUpdates`.** `time`, `hash` and `delta` are byte-for-byte what [userNonFundingLedgerUpdates](/readme/rest-api/historical-data/usernonfundingledgerupdates) returns for that user; only `user`, `role` and `txIndex` are added. Funding is excluded here exactly as it is there — use [builderApprovedFundingByTime](/readme/rest-api/historical-data/builderapprovedfundingbytime) for it.

## Response Fields

| Field     | Type   | Description                                                                                                                                                                                         |
| --------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `user`    | string | The participant this row is attributed to, who had approved your builder at the time.                                                                                                               |
| `role`    | string | `"user"` for single-party updates; `"sender"` or `"receiver"` for the side of a transfer this row is for.                                                                                           |
| `time`    | int    | Block timestamp (ms).                                                                                                                                                                               |
| `txIndex` | int    | Position of the update within its block. Needed only to build `cursor`.                                                                                                                             |
| `hash`    | string | Transaction hash.                                                                                                                                                                                   |
| `delta`   | object | Ledger update details, identical to `userNonFundingLedgerUpdates`. Fields vary by `delta.type`; see [that page](/readme/rest-api/historical-data/usernonfundingledgerupdates) for every delta type. |

<details>

<summary>Response</summary>

```json
[
  {
    "user": "0x0000000000000000000000000000000000000001",
    "role": "user",
    "time": 1786000001000,
    "txIndex": 0,
    "hash": "0xdc02464296095090dd7c04304bdac40205640028310c6f627fcaf195550d2a7b",
    "delta": {
      "type": "deposit",
      "usdc": "1000.50"
    }
  },
  {
    "user": "0x0000000000000000000000000000000000000002",
    "role": "receiver",
    "time": 1786000002000,
    "txIndex": 3,
    "hash": "0x9d3f0a2c4b6e8f1a3c5e7a9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f",
    "delta": {
      "type": "internalTransfer",
      "usdc": "25.00",
      "user": "0x0000000000000000000000000000000000000001",
      "destination": "0x0000000000000000000000000000000000000002",
      "fee": "0.00"
    }
  }
]
```

</details>


# userFunding

Get a users' funding payment history

Get a users' funding payment history.

{% hint style="info" %}
**Data available from 28-07-2025**
{% endhint %}

## POST Request

<table><thead><tr><th width="107.333251953125">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"userFunding"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr><tr><td><code>startTime</code></td><td>int</td><td>Start time in ms (inclusive)</td></tr><tr><td><code>endTime</code></td><td>int</td><td>End time in ms (optional)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "userFunding",
    "user": "0x0000000000000000000000000000000000000000",
    "startTime": 0
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'userFunding',
        'user': '0x0000000000000000000000000000000000000000',
        'startTime': 0
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'userFunding',
        user: '0x0000000000000000000000000000000000000000',
        startTime: 0
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field               | Type   | Description                                |
| ------------------- | ------ | ------------------------------------------ |
| `time`              | int    | Timestamp (ms)                             |
| `hash`              | string | Transaction hash                           |
| `delta`             | object | Funding payment details                    |
| `delta.type`        | string | Always `"funding"`                         |
| `delta.coin`        | string | Asset symbol                               |
| `delta.usdc`        | string | USDC amount of funding payment             |
| `delta.szi`         | string | Position size at time of funding           |
| `delta.fundingRate` | string | Funding rate applied                       |
| `delta.nSamples`    | int    | Number of samples (null if not applicable) |

<details>

<summary>Response</summary>

```json
[
    {
        "time": 1754064000066,
        "hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
        "delta": {
            "type": "funding",
            "coin": "BTC",
            "usdc": "0.014419",
            "szi": "-0.01",
            "fundingRate": "0.0000125",
            "nSamples": null
        }
    }
]
```

</details>


# fundingHistory

Get the funding history for a coin

Get the funding history for a coin.

{% hint style="info" %}
**Data available from 28-07-2025**
{% endhint %}

## POST Request

<table><thead><tr><th width="107.333251953125">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"fundingHistory"</code></td></tr><tr><td><code>coin</code></td><td>string</td><td>i.e. "BTC", "ETH"</td></tr><tr><td><code>startTime</code></td><td>int</td><td>Start time in ms (inclusive)</td></tr><tr><td><code>endTime</code></td><td>int</td><td>End time in ms (optional)</td></tr><tr><td><code>limit</code></td><td>int</td><td>Max results to return, default and max 500 (optional)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "fundingHistory",
    "coin": "BTC",
    "startTime": 0
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'fundingHistory',
        'coin': 'BTC',
        'startTime': 0
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'fundingHistory',
        coin: 'BTC',
        startTime: 0
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field         | Type   | Description                 |
| ------------- | ------ | --------------------------- |
| `coin`        | string | Asset symbol                |
| `fundingRate` | string | Funding rate for the period |
| `time`        | int    | Timestamp (ms)              |

<details>

<summary>Response</summary>

```json
[
    {
        "coin": "BTC",
        "fundingRate": "0.0000125",
        "time": 1762398000007
    },
    {
        "coin": "BTC",
        "fundingRate": "0.0000125",
        "time": 1762401600087
    }
]
```

</details>


# liquidationHistoryByTime

Get historical liquidation events for a coin or market-wide

Get historical liquidation events, for a single coin or across all markets. The most recent events are returned first.

{% hint style="info" %}
**All data fully available from 28-07-2025. We have performed a full backfill of all fills the HL native API offered, meaning that we have full historical data for most traders except for some very high volume addresses. TWAP fills are included from 02-08-2025.**
{% endhint %}

## POST Request

<table><thead><tr><th width="120">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"liquidationHistoryByTime"</code></td></tr><tr><td><code>coin</code></td><td>string</td><td>i.e. "BTC", "ETH", or a HIP-3 market like "xyz:JPY". Omit for market-wide (optional)</td></tr><tr><td><code>startTime</code></td><td>int</td><td>Start time in ms, inclusive (optional)</td></tr><tr><td><code>endTime</code></td><td>int</td><td>End time in ms, inclusive (optional)</td></tr><tr><td><code>limit</code></td><td>int</td><td>Max results to return, default 500, max 1000 (optional)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "liquidationHistoryByTime",
    "coin": "BTC"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'liquidationHistoryByTime',
        'coin': 'BTC'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'liquidationHistoryByTime',
        coin: 'BTC'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

Each event is the liquidated user's fill. `side` is `"A"` when a long was liquidated (forced sell) and `"B"` when a short was liquidated (forced buy).

| Field           | Type    | Description                                       |
| --------------- | ------- | ------------------------------------------------- |
| `coin`          | string  | Asset symbol                                      |
| `user`          | string  | Address that was liquidated                       |
| `px`            | string  | Fill price                                        |
| `sz`            | string  | Fill size                                         |
| `side`          | string  | `"A"` = long liquidated, `"B"` = short liquidated |
| `time`          | int     | Timestamp (ms)                                    |
| `startPosition` | string  | Position size before the fill                     |
| `dir`           | string  | Direction, e.g. `"Close Long"`                    |
| `closedPnl`     | string  | Realized PnL on the fill                          |
| `hash`          | string  | Transaction hash                                  |
| `oid`           | int     | Order id                                          |
| `crossed`       | bool    | Whether the fill crossed the book                 |
| `fee`           | string  | Fee paid                                          |
| `tid`           | int     | Trade id                                          |
| `cloid`         | string? | Client order ID (optional)                        |
| `builderFee`    | string? | Builder fee (optional)                            |
| `deployerFee`   | string? | Deployer fee (optional, HIP-3 fills only)         |
| `priorityGas`   | string? | Priority gas fee in HYPE (optional)               |
| `feeToken`      | string  | Token the fee was paid in                         |
| `builder`       | string? | Builder address (optional)                        |
| `twapId`        | int?    | TWAP order ID (null if not a TWAP fill)           |
| `liquidation`   | object  | Liquidation detail (see below)                    |
| `txIndex`       | int     | Intra-block ordering index                        |

`liquidation` object:

| Field            | Type   | Description                                                                                                          |
| ---------------- | ------ | -------------------------------------------------------------------------------------------------------------------- |
| `liquidatedUser` | string | Address that was liquidated                                                                                          |
| `markPx`         | string | Mark price at liquidation                                                                                            |
| `method`         | string | `"market"` (closed against the order book) or `"backstop"` (absorbed by the backstop liquidator at bankruptcy price) |

<details>

<summary>Response</summary>

```json
[
    {
        "coin": "BTC",
        "px": "50000.00",
        "sz": "1.0",
        "side": "A",
        "time": 1762398000007,
        "startPosition": "1.0",
        "dir": "Close Long",
        "closedPnl": "-1200.00",
        "hash": "0x1234567890abcdef",
        "oid": 123456,
        "crossed": true,
        "fee": "25.00",
        "tid": 789012,
        "cloid": null,
        "builderFee": null,
        "deployerFee": null,
        "priorityGas": null,
        "feeToken": "USDC",
        "builder": null,
        "twapId": null,
        "user": "0xabc...",
        "liquidation": {
            "liquidatedUser": "0xabc...",
            "markPx": "50000.00",
            "method": "market"
        },
        "txIndex": 12
    }
]
```

</details>


# userNonFundingLedgerUpdates

Get a users' non funding ledger updates

{% hint style="info" %}
**Data available from 28-07-2025**
{% endhint %}

## POST Request

<table><thead><tr><th width="107.333251953125">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"userNonFundingLedgerUpdates"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr><tr><td><code>startTime</code></td><td>int</td><td>Start time in ms (inclusive)</td></tr><tr><td><code>endTime</code></td><td>int</td><td>End time in ms (optional)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "userNonFundingLedgerUpdates",
    "user": "0x0000000000000000000000000000000000000000",
    "startTime": 0
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'userNonFundingLedgerUpdates',
        'user': '0x0000000000000000000000000000000000000000'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'userNonFundingLedgerUpdates',
        user: '0x0000000000000000000000000000000000000000'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field                  | Type   | Description                                                                             |
| ---------------------- | ------ | --------------------------------------------------------------------------------------- |
| `time`                 | int    | Timestamp (ms)                                                                          |
| `hash`                 | string | Transaction hash                                                                        |
| `delta`                | object | Ledger update details (fields vary by `delta.type`, see delta types below)              |
| `delta.type`           | string | Type of ledger update (e.g. `"send"`, `"deposit"`, `"withdraw"`, `"liquidation"`, etc.) |
| `delta.amount`         | string | Transfer amount (present on most delta types)                                           |
| `delta.token`          | string | Token symbol                                                                            |
| `delta.usdc`           | string | USDC amount (used by some delta types instead of `amount`)                              |
| `delta.usdcValue`      | string | USD value of the transfer                                                               |
| `delta.user`           | string | Sender/source user address                                                              |
| `delta.destination`    | string | Destination address                                                                     |
| `delta.destinationDex` | string | Destination DEX (e.g. `"spot"`)                                                         |
| `delta.sourceDex`      | string | Source DEX (e.g. `"spot"`)                                                              |
| `delta.fee`            | string | Fee amount                                                                              |
| `delta.feeToken`       | string | Fee token symbol                                                                        |
| `delta.nativeTokenFee` | string | Native token fee amount                                                                 |
| `delta.nonce`          | int    | Transaction nonce (null if not applicable)                                              |

<details>

<summary>Response</summary>

```json
[
    {
        "time": 1764256235694,
        "hash": "0xdc02464296095090dd7c04304bdac40205640028310c6f627fcaf195550d2a7b",
        "delta": {
            "amount": "0.00710881",
            "destination": "0x0000000000000000000000000000000000000000",
            "destinationDex": "spot",
            "fee": "",
            "feeToken": "",
            "nativeTokenFee": "",
            "nonce": null,
            "sourceDex": "spot",
            "token": "LIQUID",
            "type": "send",
            "usdcValue": "0.001473",
            "user": "0x9eff7b0c989f52003c0868b5353290d277196e6d"
        }
    }
]
```

</details>

<details>

<summary>All possible delta types</summary>

**withdraw**

```json
{
  "type": "withdraw",
  "usdc": "1000.0",
  "nonce": 12345,
  "fee": "1.5"
}
```

**deposit**

```json
{
  "type": "deposit",
  "usdc": "1000.0"
}
```

**vaultCreate**

```json
{
  "type": "vaultCreate",
  "vault": "0x...",
  "usdc": "10000.0",
  "fee": "10.0"
}
```

**vaultDeposit**

```json
{
  "type": "vaultDeposit",
  "vault": "0x...",
  "usdc": "5000.0"
}
```

**vaultWithdraw**

```json
{
  "type": "vaultWithdraw",
  "vault": "0x...",
  "user": "0x...",
  "requestedUsd": "1000.0",
  "commission": "10.0",
  "closingCost": "5.0",
  "basis": "995.0",
  "netWithdrawnUsd": "985.0"
}
```

**vaultDistribution**

```json
{
  "type": "vaultDistribution",
  "vault": "0x...",
  "usdc": "100.0"
}
```

**vaultLeaderCommission**

```json
{
  "type": "vaultLeaderCommission",
  "user": "0x...",
  "usdc": "50.0"
}
```

**liquidation**

```json
{
  "type": "liquidation",
  "liquidatedNtlPos": "10000.0",
  "accountValue": "-500.0",
  "leverageType": "Cross",
  "liquidatedPositions": [
    {
      "coin": "ETH",
      "szi": "-5.0"
    }
  ]
}
```

**internalTransfer**

```json
{
  "type": "internalTransfer",
  "usdc": "1000.0",
  "user": "0x...",
  "destination": "0x...",
  "fee": "0.0"
}
```

**subAccountTransfer**

```json
{
  "type": "subAccountTransfer",
  "usdc": "500.0",
  "user": "0x...",
  "destination": "0x..."
}
```

**spotTransfer**

```json
{
  "type": "spotTransfer",
  "token": "USDC",
  "amount": "1000.0",
  "usdcValue": "1000.0",
  "user": "0x...",
  "destination": "0x...",
  "fee": "1.5",
  "nativeTokenFee": "0.1",
  "nonce": 12345,
  "feeToken": "USDC"
}
```

**spotGenesis**

```json
{
  "type": "spotGenesis",
  "token": "HYPE",
  "amount": "1000000.0"
}
```

**rewardsClaim**

```json
{
  "type": "rewardsClaim",
  "amount": "100.0",
  "token": "USDC"
}
```

**accountClassTransfer**

```json
{
  "type": "accountClassTransfer",
  "usdc": "1000.0",
  "toPerp": true
}
```

**accountActivationGas**

```json
{
  "type": "accountActivationGas",
  "amount": "0.1",
  "token": "ETH"
}
```

**perpDexClassTransfer**

```json
{
  "type": "perpDexClassTransfer",
  "amount": "1000.0",
  "token": "USDC",
  "dex": "hyperliquid",
  "toPerp": true
}
```

**deployGasAuction**

```json
{
  "type": "deployGasAuction",
  "token": "ETH",
  "amount": "0.5"
}
```

**cStakingTransfer**

```json
{
  "type": "cStakingTransfer",
  "amount": "1000.0",
  "isDeposit": true,
  "token": "HYPE"
}
```

**send**

```json
{
  "type": "send",
  "amount": "100.0",
  "destination": "0x...",
  "destinationDex": "",
  "fee": "1.0",
  "feeToken": "USDC",
  "nativeTokenFee": "0.1",
  "nonce": 12345,
  "sourceDex": "",
  "token": "USDC",
  "usdcValue": "100.0",
  "user": "0x..."
}
```

**activateDexAbstraction**

```json
{
  "type": "activateDexAbstraction",
  "dex": "hyperliquid",
  "token": "USDC",
  "amount": "10.0"
}
```

**borrowLend**

```json
{
  "type": "borrowLend",
  "token": "USDC",
  "operation": "supply",
  "amount": "5000.0",
  "interestAmount": "12.5"
}
```

**borrowLendBackstopLiquidation**

```json
{
  "type": "borrowLendBackstopLiquidation",
  "token": "USDC",
  "balanceChange": "-500.0"
}
```

</details>


# historicalOrders

Get the 2000 latest order status updates of a certain user.

Get the latest order status updates of a certain user.

{% hint style="info" %}
**Data available from 7th of Aug 2025**
{% endhint %}

## POST Request

<table><thead><tr><th width="161.9998779296875">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"historicalOrders"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr><tr><td><code>limit</code></td><td>integer</td><td>Max results to return, default and max 2000 (optional)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "historicalOrders",
    "user": "0x0000000000000000000000000000000000000000"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'historicalOrders',
        'user': '0x0000000000000000000000000000000000000000'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'historicalOrders',
        user: '0x0000000000000000000000000000000000000000'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field                    | Type    | Description                                                |
| ------------------------ | ------- | ---------------------------------------------------------- |
| `builder`                | string  | Builder address if order was placed via builder (optional) |
| `builderFee`             | int     | Builder fee in basis points (optional)                     |
| `txIndex`                | int     | Transaction index                                          |
| `order`                  | object  | Order details (see Order Object below)                     |
| `status`                 | string  | Order status (see status values below)                     |
| `statusTimestamp`        | int     | Timestamp of status update in milliseconds                 |
| `order.coin`             | string  | Asset symbol                                               |
| `order.side`             | string  | `"A"` (sell) or `"B"` (buy)                                |
| `order.limitPx`          | string  | Limit price                                                |
| `order.sz`               | string  | Order size                                                 |
| `order.oid`              | int     | Order ID                                                   |
| `order.timestamp`        | int     | Order creation timestamp in milliseconds                   |
| `order.triggerCondition` | string  | Trigger condition if applicable                            |
| `order.isTrigger`        | boolean | Whether order is a trigger order                           |
| `order.triggerPx`        | string  | Trigger price                                              |
| `order.children`         | array   | Child orders for take profit/stop loss orders              |
| `order.isPositionTpsl`   | boolean | Whether order is position TP/SL                            |
| `order.reduceOnly`       | boolean | Whether order is reduce-only                               |
| `order.orderType`        | string  | Order type (e.g. `"Limit"`, `"Market"`)                    |
| `order.origSz`           | string  | Original order size                                        |
| `order.tif`              | string  | Time in force, e.g. `"Gtc"`, `"Ioc"`, `"Alo"` (optional)   |
| `order.cloid`            | string  | Client order ID (optional)                                 |

<details>

<summary>Response</summary>

```json
[
  {
    "builder": "0x...", // optional
    "builderFee": 100, // optional
    "txIndex": 12,
    "order": {
      "coin": "BTC",
      "side": "B",
      "limitPx": "45000.00",
      "sz": "0.5",
      "oid": 123456,
      "timestamp": 1234567890123,
      "triggerCondition": "tp",
      "isTrigger": false,
      "triggerPx": "0.00",
      "children": [],
      "isPositionTpsl": false,
      "reduceOnly": false,
      "orderType": "Limit",
      "origSz": "0.5",
      "tif": "Gtc", // optional
      "cloid": "client-order-123" // optional
    },
    "status": "filled",
    "statusTimestamp": 1234567890123
  }
]
```

</details>

<details>

<summary>Status values</summary>

**Active:**

* `open` - Order is resting on the orderbook
* `triggered` - Stop/trigger order was triggered
* `scheduledCancel` - Order is scheduled for cancellation

**Filled:**

* `filled` - Order completely filled

**Canceled:**

* `canceled` - Canceled by user
* `marginCanceled` - Insufficient margin
* `liquidatedCanceled` - Position was liquidated
* `delistedCanceled` - Asset was delisted
* `reduceOnlyCanceled` - Reduce-only order canceled (no position)
* `selfTradeCanceled` - Would have resulted in self-trade
* `siblingFilledCanceled` - Sibling TP/SL order filled
* `vaultWithdrawalCanceled` - Vault withdrawal triggered cancellation
* `openInterestCapCanceled` - Open interest cap reached

**Rejected:**

* `badAloPxRejected` - ALO price would cross the book
* `iocCancelRejected` - IOC order couldn't fill
* `reduceOnlyRejected` - Reduce-only order rejected
* `oracleRejected` - Oracle price check failed
* `perpMarginRejected` - Insufficient perp margin
* `perpMaxPositionRejected` - Max position size exceeded
* `openInterestIncreaseRejected` - Open interest increase rejected
* `positionFlipAtOpenInterestCapRejected` - Position flip at OI cap rejected
* `positionIncreaseAtOpenInterestCapRejected` - Position increase at OI cap rejected
* `tooAggressiveAtOpenInterestCapRejected` - Too aggressive at OI cap
* `minTradeNtlRejected` - Below minimum trade notional
* `insufficientSpotBalanceRejected` - Insufficient spot balance

</details>


# orderStatusByOid

Get the latest status snapshot of a single order by oid or cloid.

Look up the latest status of a single order, identified by `(user, oid)` or `(user, cloid)`. Returns a single snapshot object reflecting the most recent transition for that order, or `null` if the order is not in our index.

{% hint style="info" %}
**Data available from \~90 days back** for orders with terminal status (`filled`, `triggered`), and from the last 3 days for orders in any other status (`open`, `canceled`, all rejection variants, etc.). Older non-terminal transitions are pruned by TTL.
{% endhint %}

{% hint style="info" %}
Our endpoint covers every wallet uniformly back to the 90-day terminal-retention boundary, regardless of order volume.
{% endhint %}

## POST Request

<table><thead><tr><th width="161.9998779296875">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"orderStatusByOid"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr><tr><td><code>oid</code></td><td>integer</td><td>Order ID (unsigned 64-bit integer). Provide exactly one of <code>oid</code> or <code>cloid</code>.</td></tr><tr><td><code>cloid</code></td><td>string</td><td>Client order ID. Provide exactly one of <code>oid</code> or <code>cloid</code>.</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}
OID lookup:

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "orderStatusByOid",
    "user": "0x0000000000000000000000000000000000000000",
    "oid": 123456789
  }'
```

CLOID lookup:

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "orderStatusByOid",
    "user": "0x0000000000000000000000000000000000000000",
    "cloid": "0x000000334e48424f354c36373646384d"
  }'
```

{% endtab %}

{% tab title="Python" %}
OID lookup:

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'orderStatusByOid',
        'user': '0x0000000000000000000000000000000000000000',
        'oid': 123456789
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

CLOID lookup:

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'orderStatusByOid',
        'user': '0x0000000000000000000000000000000000000000',
        'cloid': '0x000000334e48424f354c36373646384d'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}
OID lookup:

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'orderStatusByOid',
        user: '0x0000000000000000000000000000000000000000',
        oid: 123456789
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

CLOID lookup:

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'orderStatusByOid',
        user: '0x0000000000000000000000000000000000000000',
        cloid: '0x000000334e48424f354c36373646384d'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

Returns a **single order-snapshot object**, or JSON `null` when the `(user, oid)` or `(user, cloid)` is not found in our index. The response is **not** an array (unlike most other historical-data endpoints, which return an array).

| Field                    | Type    | Description                                                 |
| ------------------------ | ------- | ----------------------------------------------------------- |
| `builder`                | string  | Builder address if order was placed via builder (optional)  |
| `builderFee`             | int     | Builder fee in basis points (optional)                      |
| `txIndex`                | int     | Transaction index of the latest status transition           |
| `order`                  | object  | Order details (see Order Object below)                      |
| `status`                 | string  | Latest order status (see status values below)               |
| `statusTimestamp`        | int     | Timestamp of the latest status transition in milliseconds   |
| `order.coin`             | string  | Asset symbol                                                |
| `order.side`             | string  | `"A"` (sell) or `"B"` (buy)                                 |
| `order.limitPx`          | string  | Limit price                                                 |
| `order.sz`               | string  | Remaining order size (0 if fully filled)                    |
| `order.oid`              | int     | Order ID                                                    |
| `order.timestamp`        | int     | Order creation timestamp in milliseconds                    |
| `order.triggerCondition` | string  | Trigger condition if applicable                             |
| `order.isTrigger`        | boolean | Whether order is a trigger order                            |
| `order.triggerPx`        | string  | Trigger price                                               |
| `order.children`         | array   | Child orders for take profit/stop loss orders               |
| `order.isPositionTpsl`   | boolean | Whether order is position TP/SL                             |
| `order.reduceOnly`       | boolean | Whether order is reduce-only                                |
| `order.orderType`        | string  | Order type (e.g. `"Limit"`, `"Market"`)                     |
| `order.origSz`           | string  | Original order size — use `origSz - sz` for cumulative fill |
| `order.tif`              | string  | Time in force, e.g. `"Gtc"`, `"Ioc"`, `"Alo"` (optional)    |
| `order.cloid`            | string  | Client order ID (optional)                                  |

<details>

<summary>Response — hit (order found)</summary>

```json
{
  "builder": "0x...",
  "builderFee": 100,
  "txIndex": 1243,
  "order": {
    "coin": "BTC",
    "side": "B",
    "limitPx": "45000.00",
    "sz": "0.0",
    "oid": 123456789,
    "timestamp": 1234567890123,
    "triggerCondition": "N/A",
    "isTrigger": false,
    "triggerPx": "0.00",
    "children": [],
    "isPositionTpsl": false,
    "reduceOnly": false,
    "orderType": "Limit",
    "origSz": "0.5",
    "tif": "Gtc",
    "cloid": "0x000000334e48424f354c36373646384d"
  },
  "status": "filled",
  "statusTimestamp": 1234567890456
}
```

</details>

<details>

<summary>Response — miss (order not found)</summary>

```json
null
```

</details>

<details>

<summary>Status values</summary>

**Active:**

* `open` — Order is resting on the orderbook
* `triggered` — Stop/trigger order was triggered
* `scheduledCancel` — Order is scheduled for cancellation

**Filled:**

* `filled` — Order completely filled

**Canceled:**

* `canceled` — Canceled by user
* `marginCanceled` — Insufficient margin
* `liquidatedCanceled` — Position was liquidated
* `delistedCanceled` — Asset was delisted
* `reduceOnlyCanceled` — Reduce-only order canceled (no position)
* `selfTradeCanceled` — Would have resulted in self-trade
* `siblingFilledCanceled` — Sibling TP/SL order filled
* `vaultWithdrawalCanceled` — Vault withdrawal triggered cancellation
* `openInterestCapCanceled` — Open interest cap reached

**Rejected:**

* `badAloPxRejected` — ALO price would cross the book
* `iocCancelRejected` — IOC order couldn't fill
* `reduceOnlyRejected` — Reduce-only order rejected
* `oracleRejected` — Oracle price check failed
* `perpMarginRejected` — Insufficient perp margin
* `perpMaxPositionRejected` — Max position size exceeded
* `openInterestIncreaseRejected` — Open interest increase rejected
* `positionFlipAtOpenInterestCapRejected` — Position flip at OI cap rejected
* `positionIncreaseAtOpenInterestCapRejected` — Position increase at OI cap rejected
* `tooAggressiveAtOpenInterestCapRejected` — Too aggressive at OI cap
* `minTradeNtlRejected` — Below minimum trade notional
* `insufficientSpotBalanceRejected` — Insufficient spot balance

</details>

***

## Errors

| HTTP | Body                                                                                   | Cause                                             |
| ---- | -------------------------------------------------------------------------------------- | ------------------------------------------------- |
| 400  | `{"error":"Missing field: user"}`                                                      | `user` field absent from request                  |
| 400  | `{"error":"Invalid Ethereum address: ..."}`                                            | `user` is not a valid 0x-prefixed 42-char address |
| 400  | ``{"error":"Missing required field: provide either `oid` (u64) or `cloid` (string)"}`` | Neither `oid` nor `cloid` was provided            |
| 400  | ``{"error":"Provide exactly one of `oid` or `cloid`, not both"}``                      | Both `oid` and `cloid` were provided              |

A successful lookup that finds nothing returns HTTP 200 with body `null` — **not** a 404.


# builderOrdersByTime

Returns a builder's sent order status updates within a specified timerange.

{% hint style="info" %}
💧New endpoint - this endpoint is not a part of original Hyperliquid API and is added by us for builder convenience.
{% endhint %}

{% hint style="info" %}
Historical data is available from August 7th, 2025. Users who had >100k orders between Aug 7 and Nov 4, 2025 will have only last 100k orders available. All orders are retained indefinitely going forward.
{% endhint %}

## POST Request

<table><thead><tr><th width="164.6666259765625">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"builderOrdersByTime"</code></td></tr><tr><td><code>builder</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr><tr><td><code>startTime</code></td><td>integer</td><td>Start timestamp in milliseconds (skipped when cursor is used)</td></tr><tr><td><code>endTime</code></td><td>integer</td><td>End timestamp in milliseconds (optional, defaults to now)</td></tr><tr><td><code>cursor</code></td><td>string</td><td>Composite of statusTimestamp and txIndex with "_" separator (optional)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "builderOrdersByTime",
    "builder": "0x0000000000000000000000000000000000000000",
    "startTime": 1234567890000,
    "endTime": 1234567900000
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'builderOrdersByTime',
        'builder': '0x0000000000000000000000000000000000000000',
        'startTime': 1234567890000,
        'endTime': 1234567900000
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'builderOrdersByTime',
        builder: '0x0000000000000000000000000000000000000000',
        startTime: 1234567890000,
        endTime: 1234567900000
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field                    | Type    | Description                                              |
| ------------------------ | ------- | -------------------------------------------------------- |
| `user`                   | string  | User address who placed the order                        |
| `builderFee`             | int     | Builder fee in basis points                              |
| `txIndex`                | int     | Transaction index                                        |
| `order`                  | object  | Order details (see Order Object below)                   |
| `status`                 | string  | Order status (see status values below)                   |
| `statusTimestamp`        | int     | Timestamp of status update in milliseconds               |
| `order.coin`             | string  | Asset symbol                                             |
| `order.side`             | string  | `"A"` (sell) or `"B"` (buy)                              |
| `order.limitPx`          | string  | Limit price                                              |
| `order.sz`               | string  | Order size                                               |
| `order.oid`              | int     | Order ID                                                 |
| `order.timestamp`        | int     | Order creation timestamp in milliseconds                 |
| `order.triggerCondition` | string  | Trigger condition if applicable                          |
| `order.isTrigger`        | boolean | Whether order is a trigger order                         |
| `order.triggerPx`        | string  | Trigger price                                            |
| `order.children`         | array   | Child orders for take profit/stop loss orders            |
| `order.isPositionTpsl`   | boolean | Whether order is position TP/SL                          |
| `order.reduceOnly`       | boolean | Whether order is reduce-only                             |
| `order.orderType`        | string  | Order type (e.g. `"Limit"`, `"Market"`)                  |
| `order.origSz`           | string  | Original order size                                      |
| `order.tif`              | string  | Time in force, e.g. `"Gtc"`, `"Ioc"`, `"Alo"` (optional) |
| `order.cloid`            | string  | Client order ID (optional, null if not set)              |

<details>

<summary>Response</summary>

```json
[
  {
    "user": "0x...",
    "builderFee": 100, // optional
    "txIndex": 12,
    "order": {
      "coin": "BTC",
      "side": "B",
      "limitPx": "45000.00",
      "sz": "0.5",
      "oid": 123456,
      "timestamp": 1234567890123,
      "triggerCondition": "tp",
      "isTrigger": false,
      "triggerPx": "0.00",
      "children": [],
      "isPositionTpsl": false,
      "reduceOnly": false,
      "orderType": "Limit",
      "origSz": "0.5",
      "tif": "Gtc", // optional
      "cloid": "client-order-123" // optional
    },
    "status": "filled",
    "statusTimestamp": 1234567890123
  }
]
```

</details>

<details>

<summary>Status values</summary>

**Active:**

* `open` - Order is resting on the orderbook
* `triggered` - Stop/trigger order was triggered
* `scheduledCancel` - Order is scheduled for cancellation

**Filled:**

* `filled` - Order completely filled

**Canceled:**

* `canceled` - Canceled by user
* `marginCanceled` - Insufficient margin
* `liquidatedCanceled` - Position was liquidated
* `delistedCanceled` - Asset was delisted
* `reduceOnlyCanceled` - Reduce-only order canceled (no position)
* `selfTradeCanceled` - Would have resulted in self-trade
* `siblingFilledCanceled` - Sibling TP/SL order filled
* `vaultWithdrawalCanceled` - Vault withdrawal triggered cancellation
* `openInterestCapCanceled` - Open interest cap reached

**Rejected:**

* `badAloPxRejected` - ALO price would cross the book
* `iocCancelRejected` - IOC order couldn't fill
* `reduceOnlyRejected` - Reduce-only order rejected
* `oracleRejected` - Oracle price check failed
* `perpMarginRejected` - Insufficient perp margin
* `perpMaxPositionRejected` - Max position size exceeded
* `openInterestIncreaseRejected` - Open interest increase rejected
* `positionFlipAtOpenInterestCapRejected` - Position flip at OI cap rejected
* `positionIncreaseAtOpenInterestCapRejected` - Position increase at OI cap rejected
* `tooAggressiveAtOpenInterestCapRejected` - Too aggressive at OI cap
* `minTradeNtlRejected` - Below minimum trade notional
* `insufficientSpotBalanceRejected` - Insufficient spot balance

</details>

<details>

<summary>Pagination</summary>

* When a cursor is provided, `startTime` is ignored
* Results are ordered by timestamp
* For pagination construct the cursor with the statusTimestamp and txIndex of the last order returned in the previous fetch like "cursor":"{statusTimestamp}\_{txIndex}"

</details>


# userLeverageUpdatesByTime

Paginate a user's leverage change history by time, oldest-first.

Returns leverage updates (`updateLeverage` actions) for a user with `time` ≥ `startTime` (or after a `cursor`), ordered **oldest-first** by `time` then `tx_index`.

For pagination: pass `startTime` for the first page, then on each subsequent page pass the `cursor` `"{time}_{tx_index}"` built from the **last record** of the previous response. When `cursor` is supplied, `startTime` is ignored and the boundary record is excluded from the next page (no duplicates).

{% hint style="info" %}
New endpoint - this endpoint is not a part of original Hyperliquid API and is added by us for builder convenience.
{% endhint %}

{% hint style="info" %}
This endpoint returns **leverage changes only**. The [userLeverageUpdates WebSocket channel](/readme/websocket/leverage-and-margin-updates/userleverageupdates) additionally interleaves isolated-margin records for backward compatibility — for that history, use [userIsolatedMarginUpdatesByTime](/readme/rest-api/historical-data/userisolatedmarginupdatesbytime). Record shapes match the WS channel's, so REST history and the live stream can be merged and deduplicated on `(time, tx_index)`.
{% endhint %}

## POST Request

<table><thead><tr><th width="161.9998779296875">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"userLeverageUpdatesByTime"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr><tr><td><code>startTime</code></td><td>integer</td><td>Earliest <code>time</code> to include (Unix ms, inclusive). Skipped when <code>cursor</code> is used. Either <code>startTime</code> or <code>cursor</code> must be supplied</td></tr><tr><td><code>endTime</code></td><td>integer</td><td>Latest <code>time</code> to include (Unix ms, inclusive). Default: now (optional)</td></tr><tr><td><code>cursor</code></td><td>string</td><td>Composite of <code>time</code> and <code>tx_index</code> with <code>"_"</code> separator (e.g. <code>"1734571490123_12"</code>). Take from the <strong>last record</strong> of the previous response (optional)</td></tr><tr><td><code>limit</code></td><td>integer</td><td>Max results to return. Default 100, max 500 (optional)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
# First page
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "userLeverageUpdatesByTime",
    "user": "0x0000000000000000000000000000000000000000",
    "startTime": 0,
    "limit": 100
  }'

# Next page — cursor built from the last record of the previous response
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "userLeverageUpdatesByTime",
    "user": "0x0000000000000000000000000000000000000000",
    "cursor": "1734571490123_12",
    "limit": 100
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

url = 'https://api.hydromancer.xyz/info'
headers = {
    'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
    'Content-Type': 'application/json',
}
user = '0x0000000000000000000000000000000000000000'
limit = 500

params = {'type': 'userLeverageUpdatesByTime', 'user': user, 'startTime': 0, 'limit': limit}
while True:
    page = requests.post(url, json=params, headers=headers).json()
    if not page:
        break
    for update in page:
        ...  # process leverage update
    if len(page) < limit:
        break
    last = page[-1]
    params = {
        'type': 'userLeverageUpdatesByTime',
        'user': user,
        'cursor': f"{last['time']}_{last['tx_index']}",
        'limit': limit,
    }
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const url = 'https://api.hydromancer.xyz/info';
const headers = {
    'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
    'Content-Type': 'application/json',
};
const user = '0x0000000000000000000000000000000000000000';
const limit = 500;

let params = { type: 'userLeverageUpdatesByTime', user, startTime: 0, limit };
while (true) {
    const { data: page } = await axios.post(url, params, { headers });
    if (!page.length) break;
    for (const update of page) { /* process leverage update */ }
    if (page.length < limit) break;
    const last = page[page.length - 1];
    params = {
        type: 'userLeverageUpdatesByTime',
        user,
        cursor: `${last.time}_${last.tx_index}`,
        limit,
    };
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

JSON array of leverage update records, ordered **oldest-first** by `time` then `tx_index`.

| Field         | Type    | Description                                                                              |
| ------------- | ------- | ---------------------------------------------------------------------------------------- |
| `update_type` | string  | Always `"leverage"`                                                                      |
| `time`        | int     | Block time when the update was made (Unix ms) — **first half of the next-page `cursor`** |
| `user`        | string  | Ethereum address                                                                         |
| `coin`        | string  | Asset symbol                                                                             |
| `is_cross`    | boolean | `true` for cross margin, `false` for isolated margin                                     |
| `leverage`    | int     | New leverage value                                                                       |
| `tx_index`    | int     | Transaction index within the block — **second half of the next-page `cursor`**           |


# userIsolatedMarginUpdatesByTime

Paginate a user's isolated margin update history by time, oldest-first.

Returns isolated margin updates (`updateIsolatedMargin` and `topUpIsolatedOnlyMargin` actions) for a user with `time` ≥ `startTime` (or after a `cursor`), ordered **oldest-first** by `time` then `tx_index`.

For pagination: pass `startTime` for the first page, then on each subsequent page pass the `cursor` `"{time}_{tx_index}"` built from the **last record** of the previous response. When `cursor` is supplied, `startTime` is ignored and the boundary record is excluded from the next page (no duplicates).

{% hint style="info" %}
New endpoint - this endpoint is not a part of original Hyperliquid API and is added by us for builder convenience.
{% endhint %}

{% hint style="info" %}
Record shapes match the [userIsolatedMarginUpdates WebSocket channel](/readme/websocket/leverage-and-margin-updates/userisolatedmarginupdates), so REST history and the live stream can be merged and deduplicated on `(time, tx_index)`. For leverage change history, see [userLeverageUpdatesByTime](/readme/rest-api/historical-data/userleverageupdatesbytime).
{% endhint %}

## POST Request

<table><thead><tr><th width="161.9998779296875">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"userIsolatedMarginUpdatesByTime"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr><tr><td><code>startTime</code></td><td>integer</td><td>Earliest <code>time</code> to include (Unix ms, inclusive). Skipped when <code>cursor</code> is used. Either <code>startTime</code> or <code>cursor</code> must be supplied</td></tr><tr><td><code>endTime</code></td><td>integer</td><td>Latest <code>time</code> to include (Unix ms, inclusive). Default: now (optional)</td></tr><tr><td><code>cursor</code></td><td>string</td><td>Composite of <code>time</code> and <code>tx_index</code> with <code>"_"</code> separator (e.g. <code>"1734571490123_12"</code>). Take from the <strong>last record</strong> of the previous response (optional)</td></tr><tr><td><code>limit</code></td><td>integer</td><td>Max results to return. Default 100, max 500 (optional)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
# First page
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "userIsolatedMarginUpdatesByTime",
    "user": "0x0000000000000000000000000000000000000000",
    "startTime": 0,
    "limit": 100
  }'

# Next page — cursor built from the last record of the previous response
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "userIsolatedMarginUpdatesByTime",
    "user": "0x0000000000000000000000000000000000000000",
    "cursor": "1734571490123_12",
    "limit": 100
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

url = 'https://api.hydromancer.xyz/info'
headers = {
    'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
    'Content-Type': 'application/json',
}
user = '0x0000000000000000000000000000000000000000'
limit = 500

params = {'type': 'userIsolatedMarginUpdatesByTime', 'user': user, 'startTime': 0, 'limit': limit}
while True:
    page = requests.post(url, json=params, headers=headers).json()
    if not page:
        break
    for update in page:
        ...  # process isolated margin update
    if len(page) < limit:
        break
    last = page[-1]
    params = {
        'type': 'userIsolatedMarginUpdatesByTime',
        'user': user,
        'cursor': f"{last['time']}_{last['tx_index']}",
        'limit': limit,
    }
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const url = 'https://api.hydromancer.xyz/info';
const headers = {
    'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
    'Content-Type': 'application/json',
};
const user = '0x0000000000000000000000000000000000000000';
const limit = 500;

let params = { type: 'userIsolatedMarginUpdatesByTime', user, startTime: 0, limit };
while (true) {
    const { data: page } = await axios.post(url, params, { headers });
    if (!page.length) break;
    for (const update of page) { /* process isolated margin update */ }
    if (page.length < limit) break;
    const last = page[page.length - 1];
    params = {
        type: 'userIsolatedMarginUpdatesByTime',
        user,
        cursor: `${last.time}_${last.tx_index}`,
        limit,
    };
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

JSON array of isolated margin update records, ordered **oldest-first** by `time` then `tx_index`. `update_type` selects one of two record shapes; fields the shape doesn't carry are omitted.

#### `"isolated_margin"` — margin added or removed (`updateIsolatedMargin`)

| Field         | Type    | Description                                                                              |
| ------------- | ------- | ---------------------------------------------------------------------------------------- |
| `update_type` | string  | `"isolated_margin"`                                                                      |
| `time`        | int     | Block time when the update was made (Unix ms) — **first half of the next-page `cursor`** |
| `user`        | string  | Ethereum address                                                                         |
| `coin`        | string  | Asset symbol                                                                             |
| `is_buy`      | boolean | Position side the margin change applies to                                               |
| `ntli`        | string  | Notional transfer amount (USDC); positive adds margin, negative removes                  |
| `tx_index`    | int     | Transaction index within the block — **second half of the next-page `cursor`**           |

#### `"top_up_isolated_margin"` — margin topped up to a target leverage (`topUpIsolatedOnlyMargin`)

| Field             | Type   | Description                                                                              |
| ----------------- | ------ | ---------------------------------------------------------------------------------------- |
| `update_type`     | string | `"top_up_isolated_margin"`                                                               |
| `time`            | int    | Block time when the update was made (Unix ms) — **first half of the next-page `cursor`** |
| `user`            | string | Ethereum address                                                                         |
| `coin`            | string | Asset symbol                                                                             |
| `target_leverage` | string | Leverage the margin top-up targets                                                       |
| `tx_index`        | int    | Transaction index within the block — **second half of the next-page `cursor`**           |


# User performance

Endpoints for analyzing a user's trading performance — realized PnL from closed positions, win/loss stats, fees, funding, ranked leaderboards, and (coming soon) unrealized PnL, ROI, and other metrics.

#### **Aggregate stats for a single user**

{% content-ref url="/pages/gD4ErKzaspk4KWMVIhII" %}
[userPnlSummary](/readme/rest-api/user-performance/userpnlsummary)
{% endcontent-ref %}

#### **Top traders ranked by PnL, win rate, or volume**

{% content-ref url="/pages/Ak3VdFVO5mH2tR2zer07" %}
[userPnlLeaderboard](/readme/rest-api/user-performance/userpnlleaderboard)
{% endcontent-ref %}

#### **A user's most recent completed trades**

{% content-ref url="/pages/yK9zbUW4vMxCUan8phPm" %}
[userCompletedTrades](/readme/rest-api/user-performance/usercompletedtrades)
{% endcontent-ref %}

#### **Paginate a user's completed trades by time (cursor-based)**

{% content-ref url="/pages/R9FKEZaKOJWO8wo2JDtG" %}
[userCompletedTradesByTime](/readme/rest-api/user-performance/usercompletedtradesbytime)
{% endcontent-ref %}


# userPnlSummary

Aggregate realized-PnL stats for a single user, computed from completed trades.

Returns aggregate realized-PnL metrics for a user, derived from their completed (fully closed) positions. Includes total net PnL, win/loss rates, volume traded, fees, funding PnL, account age, traded pairs, and a heuristic "human score" (0–100, higher = more likely human, lower = more likely an algorithmic trader).

`startTime` and `endTime` are optional and let you scope the metrics to a specific window (filtered on the position's `close_time`).

`dex` is optional. Omit for aggregate across every perp DEX. Set to `"main_dex"` for the native Hyperliquid dex, or to a HIP-3 dex name (e.g. `"xyz"`) to scope to that dex. When the filter is set, `tradedPairs` is scoped to the dex; `accountAgeDays` is always lifetime by design.

**note: data used to compute the leaderboard is starting from 1st of aug 2025**

## POST Request

<table><thead><tr><th width="161.9998779296875">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"userPnlSummary"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr><tr><td><code>startTime</code></td><td>int</td><td>Start time in ms, filters on <code>close_time</code> (optional)</td></tr><tr><td><code>endTime</code></td><td>int</td><td>End time in ms, filters on <code>close_time</code> (optional)</td></tr><tr><td><code>dex</code></td><td>string</td><td>Scope to a single perp DEX. <code>"main_dex"</code> for the native Hyperliquid dex, or a HIP-3 dex name (e.g. <code>"xyz"</code>). Omit for all dexes (optional)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "userPnlSummary",
    "user": "0x0000000000000000000000000000000000000000"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'userPnlSummary',
        'user': '0x0000000000000000000000000000000000000000'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'userPnlSummary',
        user: '0x0000000000000000000000000000000000000000'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field            | Type      | Description                                                                                                                                                                        |
| ---------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `user`           | string    | Ethereum address (echoed from the request)                                                                                                                                         |
| `totalPnl`       | string    | Sum of net PnL across all completed trades in the window. Net PnL is `gross_pnl - fees + funding_pnl`                                                                              |
| `winRate`        | float     | Fraction of trades with `net_pnl > 0`, rounded to 4 decimals (0–1)                                                                                                                 |
| `lossRate`       | float     | Fraction of trades with `net_pnl <= 0`, rounded to 4 decimals (0–1)                                                                                                                |
| `totalTrades`    | int       | Number of completed trades in the window                                                                                                                                           |
| `volumeTraded`   | string    | Sum of `\|px × sz\|` across all of the user's fills in the window (notional traded)                                                                                                |
| `totalFees`      | string    | Sum of fees paid across completed trades                                                                                                                                           |
| `totalFunding`   | string    | Sum of cumulative funding PnL across completed trades (positive = received, negative = paid). Already included in `totalPnl`                                                       |
| `daysActive`     | int       | Number of distinct UTC days on which the user had any fill in the window                                                                                                           |
| `accountAgeDays` | int?      | Days between the user's earliest known fill and now. `null` if the user has never had a fill on record                                                                             |
| `tradedPairs`    | string\[] | Distinct coin symbols the user has ever filled on (lifetime)                                                                                                                       |
| `humanScore`     | int       | Heuristic 0–100 score, higher = more likely a human trader. Combines average fills per trade, average distinct trading hours per active day, and the ratio of maker to taker fills |

<details>

<summary>Response</summary>

```json
{
  "user": "0x0000000000000000000000000000000000000000",
  "totalPnl": "12345.67",
  "winRate": 0.6234,
  "lossRate": 0.3766,
  "totalTrades": 412,
  "volumeTraded": "8421000.00",
  "totalFees": "1684.20",
  "totalFunding": "-23.45",
  "daysActive": 87,
  "accountAgeDays": 312,
  "tradedPairs": ["BTC", "ETH", "SOL", "HYPE"],
  "humanScore": 95
}
```

</details>


# userPnlLeaderboard

Top traders ranked by realized PnL, win rate, or volume, with quality filters.

Returns a ranked list of users by realized PnL, win rate, or volume traded over a configurable window. Quality filters (`minTrades`, `minDaysActive`, `minAccountAgeDays`, `minHumanScore`) let you exclude one-shot accounts, brand-new wallets, and high-frequency bots.

`builder` is optional. Set it to a builder address to rank only the traders who have routed a fill through that builder — useful for "how are *my* users doing" rather than the whole exchange. Membership is **lifetime**: a trader counts if they have ever routed a fill through the builder, not only within the selected window. `total` reflects the builder-scoped result set, so pagination stays correct. An address that has never routed a fill returns an empty board, not the unfiltered one, and a malformed `builder` is a `400` rather than a silently unfiltered result — omit the field (or send `null`) when you want every user.

`dex` is optional. Omit for a leaderboard aggregated across every perp DEX. Set to `"main_dex"` for the native Hyperliquid dex, or to a HIP-3 dex name (e.g. `"xyz"`) to scope the leaderboard to that dex. When the filter is set, each user's `tradedPairs` is scoped to the dex; `accountAgeDays` is always lifetime by design.

**note: data used to compute the leaderboard is starting from 1st of aug 2025**

## POST Request

<table><thead><tr><th width="180">Field</th><th width="105">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"userPnlLeaderboard"</code></td></tr><tr><td><code>window</code></td><td>string</td><td>One of <code>"1d"</code>, <code>"7d"</code>, <code>"30d"</code>, <code>"90d"</code>, <code>"all"</code>. Default <code>"30d"</code> (optional)</td></tr><tr><td><code>sortBy</code></td><td>string</td><td>One of <code>"totalPnl"</code>, <code>"winRate"</code>, <code>"volumeTraded"</code>. Default <code>"totalPnl"</code> (optional)</td></tr><tr><td><code>limit</code></td><td>int</td><td>Max results to return. Default 100, max 1000 (optional)</td></tr><tr><td><code>offset</code></td><td>int</td><td>Pagination offset. Default 0 (optional)</td></tr><tr><td><code>minTrades</code></td><td>int</td><td>Minimum completed trades to include a user. Default 5 (optional)</td></tr><tr><td><code>minDaysActive</code></td><td>int</td><td>Minimum distinct active days to include a user. Default 1 (optional)</td></tr><tr><td><code>minAccountAgeDays</code></td><td>int</td><td>Minimum account age in days. Default 0 (optional)</td></tr><tr><td><code>minHumanScore</code></td><td>int</td><td>Minimum human score (0–100). Filters out users below this score (optional)</td></tr><tr><td><code>builder</code></td><td>string</td><td>Rank only traders who have ever routed a fill through this builder address. Omit for all users (optional)</td></tr><tr><td><code>dex</code></td><td>string</td><td>Scope the leaderboard to a single perp DEX. <code>"main_dex"</code> for the native Hyperliquid dex, or a HIP-3 dex name (e.g. <code>"xyz"</code>). Omit for all dexes (optional)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "userPnlLeaderboard",
    "window": "30d",
    "sortBy": "totalPnl",
    "limit": 50,
    "minTrades": 10,
    "minHumanScore": 60
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'userPnlLeaderboard',
        'window': '30d',
        'sortBy': 'totalPnl',
        'limit': 50,
        'minTrades': 10,
        'minHumanScore': 60
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'userPnlLeaderboard',
        window: '30d',
        sortBy: 'totalPnl',
        limit: 50,
        minTrades: 10,
        minHumanScore: 60
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

The response is an object with `users`, `total`, `limit`, and `offset` fields. Each entry in `users` has the same shape as a [userPnlSummary](/readme/rest-api/user-performance/userpnlsummary) response (minus `lossRate`).

| Field    | Type      | Description                                                         |
| -------- | --------- | ------------------------------------------------------------------- |
| `users`  | object\[] | Ranked list of user entries (see below)                             |
| `total`  | int       | Total users matching all filters before `limit`/`offset` is applied |
| `limit`  | int       | Echo of the request's `limit`                                       |
| `offset` | int       | Echo of the request's `offset`                                      |

### `users[]` entry

| Field            | Type      | Description                                                                                                                                                                        |
| ---------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `user`           | string    | Ethereum address                                                                                                                                                                   |
| `totalPnl`       | string    | Sum of net PnL across the user's completed trades in the window. Net PnL is `gross_pnl - fees + funding_pnl`                                                                       |
| `winRate`        | float     | Fraction of trades with `net_pnl > 0`, rounded to 4 decimals (0–1)                                                                                                                 |
| `totalTrades`    | int       | Number of completed trades in the window                                                                                                                                           |
| `volumeTraded`   | string    | Sum of `\|px × sz\|` across all of the user's fills in the window                                                                                                                  |
| `totalFees`      | string    | Sum of fees paid across completed trades                                                                                                                                           |
| `totalFunding`   | string    | Sum of cumulative funding PnL across completed trades. Already included in `totalPnl`                                                                                              |
| `daysActive`     | int       | Number of distinct UTC days on which the user had any fill in the window                                                                                                           |
| `accountAgeDays` | int?      | Days between the user's earliest known fill and now. `null` if the user has never had a fill on record                                                                             |
| `tradedPairs`    | string\[] | Distinct coin symbols the user has ever filled on (lifetime)                                                                                                                       |
| `humanScore`     | int       | Heuristic 0–100 score, higher = more likely a human trader. Combines average fills per trade, average distinct trading hours per active day, and the ratio of maker to taker fills |

<details>

<summary>Response</summary>

```json
{
  "users": [
    {
      "user": "0xabc0000000000000000000000000000000000001",
      "totalPnl": "248913.50",
      "winRate": 0.7124,
      "totalTrades": 178,
      "volumeTraded": "12450000.00",
      "totalFees": "2490.10",
      "totalFunding": "412.33",
      "daysActive": 28,
      "accountAgeDays": 145,
      "tradedPairs": ["BTC", "ETH", "HYPE"],
      "humanScore": 88
    },
    {
      "user": "0xabc0000000000000000000000000000000000002",
      "totalPnl": "187654.21",
      "winRate": 0.6489,
      "totalTrades": 312,
      "volumeTraded": "9821000.00",
      "totalFees": "1964.20",
      "totalFunding": "-87.41",
      "daysActive": 30,
      "accountAgeDays": 312,
      "tradedPairs": ["SOL", "BTC", "ETH", "HYPE"],
      "humanScore": 75
    }
  ],
  "total": 1842,
  "limit": 50,
  "offset": 0
}
```

</details>


# userCompletedTrades

Get a user's most recent completed (fully closed) positions, newest-first.

Returns the latest N completed trades for a user, newest-first. A completed trade represents a position that has been fully closed (size returned to \~0). Each record includes gross/net/funding PnL, average entry and exit prices, fees, fill counts (total and maker), open/close timestamps, duration, peak position size during the position's lifetime, leverage at close, and last-touch builder attribution.

`dex` is optional. Omit to return trades from every perp DEX. Set to `"main_dex"` for the native Hyperliquid dex, or to a HIP-3 dex name (e.g. `"xyz"`) to scope the trade list to that dex.

**note: data used to compute the leaderboard is starting from 1st of aug 2025**

`outcomes` is optional. Set it to `true` to return trades from HIP-4 outcome markets (coins like `#8131`) instead of perp and spot trades. The two sets are disjoint and are never mixed in one response.

Outcome records **omit** `positionType`, `fundingPnl`, `leverage` and `isCross` entirely. These are not unknown values — they do not apply. Outcome exposure is a token holding, so there is no short side, no leverage and no funding, and emitting `"Long"` or `"0"` would assert facts about the market that are not true.

On a perp or spot record all four are **always present and always carry a value**, so a client may read them directly there. Treat an absent field as "not applicable to this market type" — equivalently, as "this record is from an outcome market".

## POST Request

<table><thead><tr><th width="161.9998779296875">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"userCompletedTrades"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr><tr><td><code>builder</code></td><td>string</td><td>Filter to trades whose closing fill was routed through this builder address (last-touch attribution, 0x-prefixed). Omit (or send <code>null</code>) for no filtering. A malformed, empty or non-string value is a <code>400</code> rather than a silently unfiltered result (optional)</td></tr><tr><td><code>limit</code></td><td>int</td><td>Max results to return. Default 100, max 500 (optional)</td></tr><tr><td><code>dex</code></td><td>string</td><td>Scope to a single perp DEX. <code>"main_dex"</code> for the native Hyperliquid dex, or a HIP-3 dex name (e.g. <code>"xyz"</code>). Omit for all dexes (optional)</td></tr><tr><td><code>outcomes</code></td><td>bool</td><td>Return HIP-4 outcome-market trades instead of perp/spot trades. Defaults to <code>false</code>. Cannot be combined with <code>dex</code>, since outcome markets are not dex-scoped. Outcome records <strong>omit</strong> <code>positionType</code>, <code>fundingPnl</code>, <code>leverage</code> and <code>isCross</code> entirely, rather than reporting placeholder values: outcome exposure is a token holding that is only ever long, is unlevered, and accrues no funding. All four are always present on perp and spot records (optional)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "userCompletedTrades",
    "user": "0x0000000000000000000000000000000000000000",
    "limit": 100
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'userCompletedTrades',
        'user': '0x0000000000000000000000000000000000000000',
        'limit': 100
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'userCompletedTrades',
        user: '0x0000000000000000000000000000000000000000',
        limit: 100
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

The response is a JSON array of completed-trade records, ordered newest-first by `close_time` then `tx_index`.

| Field                  | Type    | Description                                                                                                                                                                           |
| ---------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `user`                 | string  | Ethereum address                                                                                                                                                                      |
| `coin`                 | string  | Asset symbol                                                                                                                                                                          |
| `position_type`        | string  | `"Long"` or `"Short"`. Omitted on outcome markets, which are only ever long                                                                                                           |
| `gross_pnl`            | string  | Realized PnL before fees (`exit_value - entry_value`, sign-adjusted for shorts)                                                                                                       |
| `net_pnl`              | string  | Realized PnL after fees and funding (`gross_pnl - fees + funding_pnl`)                                                                                                                |
| `funding_pnl`          | string  | Cumulative funding PnL accrued while the position was open (positive = received, negative = paid). Already included in `net_pnl`. Omitted on outcome markets, which accrue no funding |
| `entry_px`             | string  | Volume-weighted average entry price                                                                                                                                                   |
| `exit_px`              | string  | Volume-weighted average exit price                                                                                                                                                    |
| `position_closed_size` | string  | Size of the closed position, in contracts                                                                                                                                             |
| `fees`                 | string  | Total fees paid on fills attributed to this position                                                                                                                                  |
| `fills`                | int     | Number of fills on this position                                                                                                                                                      |
| `maker_fills`          | int     | Number of uncrossed (maker) fills on this position                                                                                                                                    |
| `open_time`            | int     | Time the position was opened (Unix ms)                                                                                                                                                |
| `close_time`           | int     | Time the position was fully closed (Unix ms)                                                                                                                                          |
| `duration_ms`          | int     | `close_time - open_time` in milliseconds                                                                                                                                              |
| `max_position_size`    | string  | Peak absolute position size reached during the position's lifetime                                                                                                                    |
| `builder`              | string? | Builder address from the closing fill, if any (last-touch attribution)                                                                                                                |
| `tx_index`             | int     | Transaction index of the closing fill (use with `close_time` for cursor-based pagination)                                                                                             |
| `leverage`             | int     | Leverage multiplier at close (e.g. `10` = 10x). Omitted on outcome markets, which are unlevered                                                                                       |
| `is_cross`             | boolean | `true` = cross margin, `false` = isolated. Omitted on outcome markets                                                                                                                 |

<details>

<summary>Response</summary>

```json
[
  {
    "user": "0x0000000000000000000000000000000000000000",
    "coin": "BTC",
    "position_type": "Long",
    "gross_pnl": "1240.50",
    "net_pnl": "1215.15",
    "funding_pnl": "-3.10",
    "entry_px": "45000.00",
    "exit_px": "45620.00",
    "position_closed_size": "2.0",
    "fees": "22.25",
    "fills": 4,
    "maker_fills": 2,
    "open_time": 1734567890123,
    "close_time": 1734571490123,
    "duration_ms": 3600000,
    "max_position_size": "2.5",
    "builder": null,
    "tx_index": 12,
    "leverage": 10,
    "is_cross": true
  }
]
```

</details>


# userCompletedTradesByTime

Paginate a user's completed (fully closed) positions by close time, oldest-first.

Returns completed trades for a user with `close_time` ≥ `startTime` (or after a `cursor`), ordered **oldest-first** by `close_time` then `tx_index`. Pagination is identical to [`userFillsByTime`](/readme/rest-api/historical-data/userfillsbytime): pass `startTime` for the first page, then on each subsequent page pass the `cursor` `"{close_time}_{tx_index}"` built from the **last record** of the previous response. When `cursor` is supplied, `startTime` is ignored and the boundary record is excluded from the next page (no duplicates, no `+ 1` hack).

`dex` is optional. Omit to return trades from every perp DEX. Set to `"main_dex"` for the native Hyperliquid dex, or to a HIP-3 dex name (e.g. `"xyz"`) to scope the trade list to that dex.

`outcomes` is optional. Set it to `true` to return trades from HIP-4 outcome markets (coins like `#8131`) instead of perp and spot trades. The two sets are disjoint and are never mixed in one response.

Outcome records **omit** `positionType`, `fundingPnl`, `leverage` and `isCross` entirely. These are not unknown values — they do not apply. Outcome exposure is a token holding, so there is no short side, no leverage and no funding, and emitting `"Long"` or `"0"` would assert facts about the market that are not true.

On a perp or spot record all four are **always present and always carry a value**, so a client may read them directly there. Treat an absent field as "not applicable to this market type" — equivalently, as "this record is from an outcome market".

## POST Request

<table><thead><tr><th width="161.9998779296875">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"userCompletedTradesByTime"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr><tr><td><code>startTime</code></td><td>integer</td><td>Earliest <code>close_time</code> to include (Unix ms, inclusive). Skipped when <code>cursor</code> is used. Either <code>startTime</code> or <code>cursor</code> must be supplied</td></tr><tr><td><code>endTime</code></td><td>integer</td><td>Latest <code>close_time</code> to include (Unix ms, inclusive). Default: now (optional)</td></tr><tr><td><code>cursor</code></td><td>string</td><td>Composite of <code>close_time</code> and <code>tx_index</code> with <code>"_"</code> separator (e.g. <code>"1734571490123_12"</code>). Take from the <strong>last record</strong> of the previous response (optional)</td></tr><tr><td><code>builder</code></td><td>string</td><td>Filter to trades whose closing fill was routed through this builder address (last-touch attribution, 0x-prefixed). Omit (or send <code>null</code>) for no filtering. A malformed, empty or non-string value is a <code>400</code> rather than a silently unfiltered result (optional)</td></tr><tr><td><code>limit</code></td><td>integer</td><td>Max results to return. Default 100, max 500 (optional)</td></tr><tr><td><code>dex</code></td><td>string</td><td>Scope to a single perp DEX. <code>"main_dex"</code> for the native Hyperliquid dex, or a HIP-3 dex name (e.g. <code>"xyz"</code>). Omit for all dexes (optional)</td></tr><tr><td><code>outcomes</code></td><td>bool</td><td>Return HIP-4 outcome-market trades instead of perp/spot trades. Defaults to <code>false</code>. Cannot be combined with <code>dex</code>, since outcome markets are not dex-scoped. Outcome records <strong>omit</strong> <code>positionType</code>, <code>fundingPnl</code>, <code>leverage</code> and <code>isCross</code> entirely, rather than reporting placeholder values: outcome exposure is a token holding that is only ever long, is unlevered, and accrues no funding. All four are always present on perp and spot records (optional)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
# First page
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "userCompletedTradesByTime",
    "user": "0x0000000000000000000000000000000000000000",
    "startTime": 0,
    "limit": 100
  }'

# Next page — cursor built from the last record of the previous response
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "userCompletedTradesByTime",
    "user": "0x0000000000000000000000000000000000000000",
    "cursor": "1734571490123_12",
    "limit": 100
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

url = 'https://api.hydromancer.xyz/info'
headers = {
    'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
    'Content-Type': 'application/json',
}
user = '0x0000000000000000000000000000000000000000'
limit = 500

params = {'type': 'userCompletedTradesByTime', 'user': user, 'startTime': 0, 'limit': limit}
while True:
    page = requests.post(url, json=params, headers=headers).json()
    if not page:
        break
    for trade in page:
        ...  # process trade
    if len(page) < limit:
        break
    last = page[-1]
    params = {
        'type': 'userCompletedTradesByTime',
        'user': user,
        'cursor': f"{last['close_time']}_{last['tx_index']}",
        'limit': limit,
    }
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const url = 'https://api.hydromancer.xyz/info';
const headers = {
    'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
    'Content-Type': 'application/json',
};
const user = '0x0000000000000000000000000000000000000000';
const limit = 500;

let params = { type: 'userCompletedTradesByTime', user, startTime: 0, limit };
while (true) {
    const { data: page } = await axios.post(url, params, { headers });
    if (!page.length) break;
    for (const trade of page) { /* process trade */ }
    if (page.length < limit) break;
    const last = page[page.length - 1];
    params = {
        type: 'userCompletedTradesByTime',
        user,
        cursor: `${last.close_time}_${last.tx_index}`,
        limit,
    };
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

JSON array of completed-trade records, ordered **oldest-first** by `close_time` then `tx_index`. Same record shape as [userCompletedTrades](/readme/rest-api/user-performance/usercompletedtrades):

| Field                  | Type    | Description                                                                                                                                                                           |
| ---------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `user`                 | string  | Ethereum address                                                                                                                                                                      |
| `coin`                 | string  | Asset symbol                                                                                                                                                                          |
| `position_type`        | string  | `"Long"` or `"Short"`. Omitted on outcome markets, which are only ever long                                                                                                           |
| `gross_pnl`            | string  | Realized PnL before fees                                                                                                                                                              |
| `net_pnl`              | string  | Realized PnL after fees and funding (`gross_pnl - fees + funding_pnl`)                                                                                                                |
| `funding_pnl`          | string  | Cumulative funding PnL accrued while the position was open (positive = received, negative = paid). Already included in `net_pnl`. Omitted on outcome markets, which accrue no funding |
| `entry_px`             | string  | Volume-weighted average entry price                                                                                                                                                   |
| `exit_px`              | string  | Volume-weighted average exit price                                                                                                                                                    |
| `position_closed_size` | string  | Size of the closed position, in contracts                                                                                                                                             |
| `fees`                 | string  | Total fees paid on fills attributed to this position                                                                                                                                  |
| `fills`                | int     | Number of fills on this position                                                                                                                                                      |
| `maker_fills`          | int     | Number of uncrossed (maker) fills on this position                                                                                                                                    |
| `open_time`            | int     | Time the position was opened (Unix ms)                                                                                                                                                |
| `close_time`           | int     | Time the position was fully closed (Unix ms) — **first half of the next-page `cursor`**                                                                                               |
| `duration_ms`          | int     | `close_time - open_time` in milliseconds                                                                                                                                              |
| `max_position_size`    | string  | Peak absolute position size during the position's lifetime                                                                                                                            |
| `builder`              | string? | Builder address from the closing fill, if any                                                                                                                                         |
| `tx_index`             | int     | Transaction index of the closing fill — **second half of the next-page `cursor`**                                                                                                     |
| `leverage`             | int     | Leverage multiplier at close (e.g. `10` = 10x). Omitted on outcome markets, which are unlevered                                                                                       |
| `is_cross`             | boolean | `true` = cross margin, `false` = isolated. Omitted on outcome markets                                                                                                                 |


# Outcomes

Endpoints for querying prediction market outcomes.

These endpoints provide data about HIP-4 prediction market outcomes on-chain.

{% content-ref url="/pages/l6hJFl03wZTmXY5OAr29" %}
[outcomeMeta](/readme/rest-api/outcomes/outcomemeta)
{% endcontent-ref %}

{% content-ref url="/pages/Xz1MxZzE6c8buIgMNiJS" %}
[settledOutcomesById](/readme/rest-api/outcomes/settledoutcomesbyid)
{% endcontent-ref %}

{% content-ref url="/pages/wGhUiGJaZKv6eOGLcPfF" %}
[settledOutcomes](/readme/rest-api/outcomes/settledoutcomes)
{% endcontent-ref %}

{% content-ref url="/pages/FAxfD9y1goNcpYOGsZQI" %}
[registeredOutcomesById](/readme/rest-api/outcomes/registeredoutcomesbyid)
{% endcontent-ref %}

{% content-ref url="/pages/gk9VixjcYGHyCwWXHXwT" %}
[registeredOutcomes](/readme/rest-api/outcomes/registeredoutcomes)
{% endcontent-ref %}

{% content-ref url="/pages/gXGhrEYTGnaZ4GrVDL8M" %}
[registeredOutcomesSnapshot](/readme/rest-api/outcomes/registeredoutcomessnapshot)
{% endcontent-ref %}

{% content-ref url="/pages/TTAu82ghKe4OTAuKGMIo" %}
[outcomeTemplatesOverview](/readme/rest-api/outcomes/outcometemplatesoverview)
{% endcontent-ref %}


# outcomeMeta

Get metadata for all registered prediction market outcomes.

Returns metadata for all registered prediction market outcomes. This request returns currently active outcomes with their descriptions and side specifications.

## POST Request

<table><thead><tr><th width="161">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"outcomeMeta"</code></td></tr><tr><td><code>venue</code></td><td>string</td><td>Only outcomes deployed by this permissionless venue, e.g. <code>"skew"</code>. 2–4 ASCII letters, case-insensitive; a venue not present in <code>deployers</code> returns <code>400</code> (optional)</td></tr><tr><td><code>deployedBy</code></td><td>string</td><td><code>"all"</code> (default), <code>"validator"</code> (registered by validator quorum, no venue), or <code>"venue"</code> (any permissionless venue) (optional)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "outcomeMeta"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'outcomeMeta'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'outcomeMeta'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

Only outcomes deployed by the `skew` venue, then only validator-deployed outcomes:

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type": "outcomeMeta", "venue": "skew"}'

curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type": "outcomeMeta", "deployedBy": "validator"}'
```

***

## Response Fields

| Field                              | Type    | Description                                                                                                              |
| ---------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------ |
| `outcomes`                         | array   | List of registered outcome entries                                                                                       |
| `outcomes[].outcome`               | integer | The outcome ID                                                                                                           |
| `outcomes[].name`                  | string  | Outcome name                                                                                                             |
| `outcomes[].description`           | string  | Description or pipe-delimited metadata (e.g. \`"class:priceBinary                                                        |
| `outcomes[].sideSpecs`             | array   | Side specifications with name for each side                                                                              |
| `outcomes[].sideSpecs[].name`      | string  | Name of the side (e.g. `"Yes"`, `"No"`, `"Hypurr"`)                                                                      |
| `outcomes[].venue`                 | string? | Permissionless venue that deployed this outcome. **Absent** (not null) on validator-deployed outcomes                    |
| `outcomes[].quoteToken`            | string? | Quote token **name** (e.g. `"USDC"`), not the numeric index — resolve via [spotMeta](/readme/rest-api/metadata/spotmeta) |
| `outcomes[].deployerFeeScale`      | string? | Deployer-fee multiplier. Absent at the default of `1`; absence means the default, not unknown                            |
| `feeScale`                         | string? | Chain-wide default fee scale that each outcome's `deployerFeeScale` overrides                                            |
| `deployers`                        | array   | Registered permissionless deployers, one entry per venue                                                                 |
| `deployers[].deployer`             | string  | Deployer address that claimed the venue                                                                                  |
| `deployers[].venue`                | string  | Venue name, as it appears in `outcomes[].venue`                                                                          |
| `deployers[].subDeployers`         | array   | Addresses the deployer has delegated actions to, with the action variants each may perform                               |
| `questions`                        | array   | List of multi-outcome questions                                                                                          |
| `questions[].question`             | integer | The question ID                                                                                                          |
| `questions[].name`                 | string  | Question text                                                                                                            |
| `questions[].description`          | string  | Question description                                                                                                     |
| `questions[].fallbackOutcome`      | integer | Outcome ID used as fallback                                                                                              |
| `questions[].namedOutcomes`        | array   | List of outcome IDs that are part of this question                                                                       |
| `questions[].settledNamedOutcomes` | array   | List of outcome IDs that have been settled                                                                               |

<details>

<summary>Response</summary>

```json
{
  "outcomes": [
    {
      "outcome": 9,
      "name": "Who will win the HL 100 meter dash?",
      "description": "This race is yet to be scheduled.",
      "sideSpecs": [
        { "name": "Hypurr" },
        { "name": "Usain Bolt" }
      ]
    },
    {
      "outcome": 3151,
      "name": "Recurring",
      "description": "class:priceBinary|underlying:HYPE|expiry:20260404-1145|targetPrice:38|period:15m",
      "sideSpecs": [
        { "name": "Yes" },
        { "name": "No" }
      ],
      "venue": "skew",
      "quoteToken": "USDC",
      "deployerFeeScale": "10"
    }
  ],
  "questions": [
    {
      "question": 1,
      "name": "What will Hypurr eat the most of in Feb 2026?",
      "description": "Hypurr has committed to weighing and recording daily food intake in a food journal.",
      "fallbackOutcome": 13,
      "namedOutcomes": [10, 11, 12],
      "settledNamedOutcomes": []
    }
  ],
  "deployers": [
    {
      "deployer": "0xb48c1a1ac675dcaa294ca7831eb729622c487671",
      "venue": "skew",
      "subDeployers": []
    }
  ],
  "feeScale": "1"
}
```

</details>


# settledOutcome

Returns the settlement spec and result for a single outcome by its outcome index. Returns `null` if the outcome is unknown or not yet settled.

<table><thead><tr><th width="115">Field</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"settledOutcome"</code></td></tr><tr><td><code>outcome</code></td><td>int</td><td>Outcome index (required)</td></tr></tbody></table>

## Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "settledOutcome",
    "outcome": 0
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'settledOutcome',
        'outcome': 0
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'settledOutcome',
    outcome: 0
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response Fields

Returns `null` if the outcome is unknown or not yet settled.

| Field              | Type   | Description                                                                                                           |
| ------------------ | ------ | --------------------------------------------------------------------------------------------------------------------- |
| `spec.outcome`     | int    | Outcome index                                                                                                         |
| `spec.name`        | string | Outcome name                                                                                                          |
| `spec.description` | string | Encoded outcome spec (e.g. `"class:priceBinary\|underlying:BTC\|expiry:20260503-0600\|targetPrice:78213\|period:1d"`) |
| `spec.sideSpecs`   | array  | List of `{ name }` objects, one per side (e.g. `Yes`/`No`)                                                            |
| `spec.quoteToken`  | string | Quote token for the outcome market                                                                                    |
| `settleFraction`   | string | Settlement fraction for the winning side                                                                              |
| `details`          | string | Settlement details (e.g. `"price:78212.4"`)                                                                           |

<details>

<summary>Response</summary>

```json
{
  "spec": {
    "outcome": 0,
    "name": "Recurring",
    "description": "class:priceBinary|underlying:BTC|expiry:20260503-0600|targetPrice:78213|period:1d",
    "sideSpecs": [
      { "name": "Yes" },
      { "name": "No" }
    ],
    "quoteToken": "USDH"
  },
  "settleFraction": "0.0",
  "details": "price:78212.4"
}
```

</details>


# settledOutcomesById

Get settled prediction market outcomes by their outcome IDs or asset IDs.

Returns metadata and stats for one or more settled prediction market outcomes.

## POST Request

<table><thead><tr><th width="161">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"settledOutcomesById"</code></td></tr><tr><td><code>kind</code></td><td>string</td><td><code>"all"</code> (default for by-id), <code>"price"</code>, or <code>"canonical"</code> — see <a href="#the-kind-filter">The kind filter</a> (optional)</td></tr><tr><td><code>outcome_ids</code></td><td>integer[]</td><td>Array of outcome IDs (optional)</td></tr><tr><td><code>asset_ids</code></td><td>string[]</td><td>Array of asset IDs prefixed with <code>#</code>, e.g. <code>"#90"</code> (optional)</td></tr><tr><td><code>question_ids</code></td><td>integer[]</td><td>Array of HIP-4 question IDs (optional). Each question is server-side-expanded to its child outcomes (named + fallback), which appear in <code>outcomes</code>. The question itself appears in <code>questions</code>.</td></tr></tbody></table>

At least one of `outcome_ids`, `asset_ids`, or `question_ids` must be provided and non-empty. They can be combined — the results are merged and deduplicated. The combined number of unique IDs must not exceed 100.

Filtering by `outcome_ids` or `asset_ids` for a child of a question also surfaces the parent question in the `questions` array, so a single child lookup always returns its enclosing question.

> By default (`kind` omitted) **all** requested ids are returned regardless of market type — a by-id lookup names exact rows, so it doesn't apply the list endpoints' price default. Pass `kind: "price"` to restrict to structured markets, or `kind: "canonical"` for HIP-4 validator-voted (prose) markets only. See [The kind filter](#the-kind-filter).

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "settledOutcomesById",
    "outcome_ids": [9],
    "asset_ids": ["#30800"]
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'settledOutcomesById',
        'outcome_ids': [9],
        'asset_ids': ['#30800']
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'settledOutcomesById',
        outcome_ids: [9],
        asset_ids: ['#30800']
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

Returns an object with two arrays: `outcomes` (matched settled outcome objects, sorted descending by `outcomeId`) and `questions` (the parent HIP-4 questions of any priceBucket children that appear in `outcomes`, plus any explicitly-requested `question_ids`, sorted descending by `questionId`). Both arrays are always present, even when empty.

### Target price formats

The `targetPrice` field on each outcome is a string whose format depends on the outcome's `class`.

**`priceBinary`** — a single numeric strike. The outcome resolves YES if the underlying's settle price meets the strike, NO otherwise.

```
"targetPrice": "52.328"
```

**`priceBucket`** — outcomes belong to a parent question that defines `priceThresholds` (a sorted comma-separated list of 2 cut-points splitting the price line into 3 buckets). The question has 3 named children plus one fallback child. Each named child resolves YES if the settle price falls in its bucket; the fallback child resolves YES if all named children resolve NO. The format mirrors interval notation:

| Child role                     | `targetPrice` value | Example (thresholds `80828, 81071`) |
| ------------------------------ | ------------------- | ----------------------------------- |
| First named child (index `0`)  | `<t0`               | `<80828`                            |
| Middle named child (index `1`) | `[t0,t1)`           | `[80828,81071)`                     |
| Last named child (index `2`)   | `>=t1`              | `>=81071`                           |
| Fallback child                 | raw threshold list  | `80828,81071`                       |

The fallback's literal comma-separated value signals "any price not covered by a named child" rather than a specific range. Use the parent question's `priceThresholds` field if you need to render the fallback's range yourself.

### Outcome object

| Field              | Type    | Description                                                                                                                                                            |
| ------------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `outcomeId`        | integer | The outcome ID                                                                                                                                                         |
| `kind`             | string  | `"price"` for structured markets, `"canonical"` for HIP-4 validator-voted (prose) markets                                                                              |
| `name`             | string? | Outcome name from the register event                                                                                                                                   |
| `description`      | string? | Pipe-separated description. priceBucket children copy this as-is from the parent question                                                                              |
| `sideSpecs`        | array?  | Side specifications, e.g. `[{"name":"Yes"},{"name":"No"}]`                                                                                                             |
| `class`            | string? | `"priceBinary"` or `"priceBucket"`. `null` when `kind` is `"canonical"`                                                                                                |
| `underlying`       | string? | Underlying asset, e.g. `"HYPE"`. `null` when `kind` is `"canonical"`                                                                                                   |
| `expiry`           | string? | Expiry timestamp. `null` when `kind` is `"canonical"`                                                                                                                  |
| `targetPrice`      | string? | Numeric strike for `priceBinary`; bucket-range string for `priceBucket` (see [Target price formats](#target-price-formats) above). `null` when `kind` is `"canonical"` |
| `period`           | string? | Period. `null` when `kind` is `"canonical"`                                                                                                                            |
| `category`         | string? | Canonical-market category. `null` on price markets                                                                                                                     |
| `subCategory`      | string? | Canonical-market sub-category. `null` on price markets                                                                                                                 |
| `quoteToken`       | string  | Quote token ID                                                                                                                                                         |
| `yesAssetId`       | string  | YES-side asset ID, format `"#{outcomeId * 10}"`                                                                                                                        |
| `noAssetId`        | string  | NO-side asset ID, format `"#{outcomeId * 10 + 1}"`                                                                                                                     |
| `settleFraction`   | string  | `"1"` if this outcome won, `"0"` otherwise. priceBucket children: exactly one named child has `"1"`; the fallback has `"1"` only when no named child wins              |
| `settleDetails`    | string? | Numeric settle price for price markets (e.g. `"73336"`); freeform decision text for canonical markets                                                                  |
| `yesStats`         | object  | YES-side market stats; zero-valued when no fills (see [Stats object](#stats-object) below)                                                                             |
| `noStats`          | object  | NO-side market stats                                                                                                                                                   |
| `deployerAddress`  | string? | Permissionless-venue deployer address; null on validator-registered outcomes                                                                                           |
| `deployerVenue`    | string? | Permissionless venue name; null on validator-registered outcomes                                                                                                       |
| `deployerFeeScale` | string? | Multiplier applied to the deployer fee for this market, e.g. `"10"`. `null` on validator-registered outcomes and when the chain uses its default scale of 1            |

### Question object

| Field                 | Type              | Description                                                                                                                                  |
| --------------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `questionId`          | integer           | The question ID (assigned by chain)                                                                                                          |
| `kind`                | string            | `"price"` or `"canonical"`                                                                                                                   |
| `name`                | string            | Question name                                                                                                                                |
| `description`         | string            | Pipe-separated description; named children copy this as-is                                                                                   |
| `class`               | string?           | `"priceBucket"`. `null` when `kind` is `"canonical"`                                                                                         |
| `underlying`          | string?           | Underlying asset. `null` when `kind` is `"canonical"`                                                                                        |
| `expiry`              | string?           | Expiry timestamp. `null` when `kind` is `"canonical"`                                                                                        |
| `period`              | string?           | Period. `null` when `kind` is `"canonical"`                                                                                                  |
| `priceThresholds`     | string?           | Sorted comma-separated list of 2 cut-points. `null` when `kind` is `"canonical"`                                                             |
| `category`            | string?           | Canonical-market category. `null` on price questions                                                                                         |
| `subCategory`         | string?           | Canonical-market sub-category. `null` on price questions                                                                                     |
| `quoteToken`          | string            | Quote token ID                                                                                                                               |
| `fallbackOutcome`     | integer           | `outcomeId` of the fallback child                                                                                                            |
| `fallbackName`        | string            | Name of the fallback child                                                                                                                   |
| `fallbackDescription` | string            | Description of the fallback child                                                                                                            |
| `namedOutcomes`       | array of integers | `outcomeId`s of the 3 named children, in named-index order                                                                                   |
| `winningOutcome`      | integer?          | `outcomeId` of the child that resolved YES (a named child, or the fallback if all named children resolve NO)                                 |
| `winningNamedIndex`   | integer?          | Position in `namedOutcomes` of the winner if a named child won, `null` if the fallback won                                                   |
| `settleDetails`       | string?           | Numeric settle price for price questions; freeform decision text for canonical questions                                                     |
| `time`                | integer           | Settlement timestamp (ms)                                                                                                                    |
| `stats`               | object            | Aggregate trading stats across the question's children. Always present; zero-valued when no fills. See [Stats object](#stats-object) below.  |
| `deployerAddress`     | string?           | Permissionless-venue deployer address; null on validator-registered questions                                                                |
| `deployerVenue`       | string?           | Permissionless venue name; null on validator-registered questions                                                                            |
| `deployerFeeScale`    | string?           | Multiplier applied to the deployer fee, e.g. `"10"`. `null` on validator-registered questions and when the chain uses its default scale of 1 |

### Stats object

All fields except `settlementClosedPnl` reflect orderbook trading only. Fills with `dir = "Settlement"` (auto-close fills produced when the outcome settles, at price 1 for the winning side and 0 for the losing side) are excluded so vwap, lastPrice, min/max, largestTrade, and avg/median trade notional aren't distorted by them. `settlementClosedPnl` summarises the realized PnL across those Settlement-direction fills for the side.

| Field                 | Type    | Description                                                         |
| --------------------- | ------- | ------------------------------------------------------------------- |
| `coin`                | string  | Asset ID for this side                                              |
| `trades`              | integer | Number of orderbook fills                                           |
| `uniqueTraders`       | integer | Distinct users that traded this side                                |
| `volumeNotional`      | string  | Sum of `px * sz` across orderbook fills                             |
| `volumeContracts`     | string  | Sum of `sz` across orderbook fills                                  |
| `lastPrice`           | string  | Price of the most recent orderbook fill                             |
| `vwap`                | number  | Volume-weighted average orderbook price                             |
| `minPrice`            | string  | Minimum orderbook fill price                                        |
| `maxPrice`            | string  | Maximum orderbook fill price                                        |
| `avgTradeNotional`    | number  | Mean `px * sz` across orderbook fills                               |
| `medianTradeNotional` | number  | Median `px * sz` across orderbook fills                             |
| `largestTrade`        | string  | Maximum `px * sz` of any orderbook fill                             |
| `firstTrade`          | integer | Timestamp (ms) of earliest orderbook fill                           |
| `lastTrade`           | integer | Timestamp (ms) of latest orderbook fill                             |
| `settlementClosedPnl` | string  | Sum of `closed_pnl` across Settlement-direction fills for this side |

#### Question stats object

Question stats are intentionally trimmed compared to outcome stats. Price-shaped metrics (`lastPrice`, `vwap`, `minPrice`, `maxPrice`, `largestTrade`, `avgTradeNotional`, `medianTradeNotional`) don't aggregate cleanly across the children's YES + NO assets, so they aren't reported. There's no `coin` field — questions don't own a single asset. Settlement and the four HIP-4 conversion ops (`Split Outcome`, `Negate Outcome`, `Merge Outcome`, `Merge Question`) are excluded from all metrics.

| Field             | Type    | Description                                                                                                                                                          |
| ----------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `trades`          | integer | Number of orderbook matches across all child YES + NO assets. Counts each chain match exactly once (filters to `dir = 'Buy'`; every match emits one Buy + one Sell). |
| `uniqueTraders`   | integer | Distinct users that traded any child asset (Buy or Sell).                                                                                                            |
| `volumeNotional`  | string  | Sum of `px * sz` across `dir = 'Buy'` fills on any child.                                                                                                            |
| `volumeContracts` | string  | Sum of `sz` across `dir = 'Buy'` fills on any child.                                                                                                                 |
| `firstTrade`      | integer | Timestamp (ms) of the earliest orderbook fill on any child.                                                                                                          |
| `lastTrade`       | integer | Timestamp (ms) of the latest orderbook fill on any child.                                                                                                            |

<details>

<summary>Response</summary>

Example for `{"question_ids": [302]}` — a settled HIP-4 question with three named children plus its fallback. The middle named child (`outcomeId: 7603`, `targetPrice: "[80518,80760)"`) won (`settleFraction: "1"`); the others have `settleFraction: "0"`. The question's `winningOutcome` and `winningNamedIndex` point at the winner.

```json
{
  "outcomes": [
    {
      "outcomeId": 7604,
      "name": "Recurring Named Outcome",
      "description": "class:priceBucket|underlying:BTC|expiry:20260508-1245|priceThresholds:80518,80760|period:15m",
      "sideSpecs": [{"name": "Yes"}, {"name": "No"}],
      "class": "priceBucket",
      "underlying": "BTC",
      "expiry": "20260508-1245",
      "targetPrice": ">=80760",
      "period": "15m",
      "quoteToken": "1452",
      "yesAssetId": "#76040",
      "noAssetId": "#76041",
      "settleFraction": "0",
      "settleDetails": "80547.9",
      "yesStats": { "coin": "#76040", "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0", "vwap": 0.0, "minPrice": "0", "maxPrice": "0", "avgTradeNotional": 0.0, "medianTradeNotional": 0.0, "largestTrade": "0", "firstTrade": 0, "lastTrade": 0, "settlementClosedPnl": "0" },
      "noStats":  { "coin": "#76041", "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0", "vwap": 0.0, "minPrice": "0", "maxPrice": "0", "avgTradeNotional": 0.0, "medianTradeNotional": 0.0, "largestTrade": "0", "firstTrade": 0, "lastTrade": 0, "settlementClosedPnl": "0" }
    },
    {
      "outcomeId": 7603,
      "name": "Recurring Named Outcome",
      "description": "class:priceBucket|underlying:BTC|expiry:20260508-1245|priceThresholds:80518,80760|period:15m",
      "sideSpecs": [{"name": "Yes"}, {"name": "No"}],
      "class": "priceBucket",
      "underlying": "BTC",
      "expiry": "20260508-1245",
      "targetPrice": "[80518,80760)",
      "period": "15m",
      "quoteToken": "1452",
      "yesAssetId": "#76030",
      "noAssetId": "#76031",
      "settleFraction": "1",
      "settleDetails": "80547.9",
      "yesStats": { "coin": "#76030", "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0", "vwap": 0.0, "minPrice": "0", "maxPrice": "0", "avgTradeNotional": 0.0, "medianTradeNotional": 0.0, "largestTrade": "0", "firstTrade": 0, "lastTrade": 0, "settlementClosedPnl": "0" },
      "noStats":  { "coin": "#76031", "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0", "vwap": 0.0, "minPrice": "0", "maxPrice": "0", "avgTradeNotional": 0.0, "medianTradeNotional": 0.0, "largestTrade": "0", "firstTrade": 0, "lastTrade": 0, "settlementClosedPnl": "0" }
    },
    {
      "outcomeId": 7602,
      "name": "Recurring Named Outcome",
      "description": "class:priceBucket|underlying:BTC|expiry:20260508-1245|priceThresholds:80518,80760|period:15m",
      "sideSpecs": [{"name": "Yes"}, {"name": "No"}],
      "class": "priceBucket",
      "underlying": "BTC",
      "expiry": "20260508-1245",
      "targetPrice": "<80518",
      "period": "15m",
      "quoteToken": "1452",
      "yesAssetId": "#76020",
      "noAssetId": "#76021",
      "settleFraction": "0",
      "settleDetails": "80547.9",
      "yesStats": { "coin": "#76020", "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0", "vwap": 0.0, "minPrice": "0", "maxPrice": "0", "avgTradeNotional": 0.0, "medianTradeNotional": 0.0, "largestTrade": "0", "firstTrade": 0, "lastTrade": 0, "settlementClosedPnl": "0" },
      "noStats":  { "coin": "#76021", "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0", "vwap": 0.0, "minPrice": "0", "maxPrice": "0", "avgTradeNotional": 0.0, "medianTradeNotional": 0.0, "largestTrade": "0", "firstTrade": 0, "lastTrade": 0, "settlementClosedPnl": "0" }
    },
    {
      "outcomeId": 7601,
      "name": "Recurring Fallback",
      "description": "class:priceBucket|underlying:BTC|expiry:20260508-1245|priceThresholds:80518,80760|period:15m",
      "sideSpecs": [{"name": "Yes"}, {"name": "No"}],
      "class": "priceBucket",
      "underlying": "BTC",
      "expiry": "20260508-1245",
      "targetPrice": "80518,80760",
      "period": "15m",
      "quoteToken": "1452",
      "yesAssetId": "#76010",
      "noAssetId": "#76011",
      "settleFraction": "0",
      "settleDetails": "80547.9",
      "yesStats": { "coin": "#76010", "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0", "vwap": 0.0, "minPrice": "0", "maxPrice": "0", "avgTradeNotional": 0.0, "medianTradeNotional": 0.0, "largestTrade": "0", "firstTrade": 0, "lastTrade": 0, "settlementClosedPnl": "0" },
      "noStats":  { "coin": "#76011", "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0", "vwap": 0.0, "minPrice": "0", "maxPrice": "0", "avgTradeNotional": 0.0, "medianTradeNotional": 0.0, "largestTrade": "0", "firstTrade": 0, "lastTrade": 0, "settlementClosedPnl": "0" }
    }
  ],
  "questions": [
    {
      "questionId": 302,
      "name": "Recurring",
      "description": "class:priceBucket|underlying:BTC|expiry:20260508-1245|priceThresholds:80518,80760|period:15m",
      "class": "priceBucket",
      "underlying": "BTC",
      "expiry": "20260508-1245",
      "period": "15m",
      "priceThresholds": "80518,80760",
      "quoteToken": "1452",
      "fallbackOutcome": 7601,
      "fallbackName": "Recurring Fallback",
      "fallbackDescription": "other",
      "namedOutcomes": [7602, 7603, 7604],
      "winningOutcome": 7603,
      "winningNamedIndex": 1,
      "settleDetails": "80547.9",
      "time": 1778244305560,
      "stats": { "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "firstTrade": 0, "lastTrade": 0 }
    }
  ]
}
```

</details>

***

## The kind filter

The optional `kind` request field controls which of the requested ids are returned: `"all"` (the by-id default) returns every requested id regardless of type, `"price"` only structured markets, `"canonical"` only HIP-4 validator-voted (prose) markets. An id whose market doesn't match `kind` is omitted from the response.

Each returned row carries a `kind` field. **Nullability by kind:** on a `"price"` row the structured fields (`class`, `underlying`, `expiry`, `targetPrice`, `period`) are populated and `category` / `subCategory` are `null`; on a `"canonical"` row those structured fields are `null` and `category` / `subCategory` are populated.

Request semantics — id-set merging, child expansion via `question_ids`, parent-question derivation from child outcomes, 50-id cap — are unchanged.


# settledOutcomes

Get recent settled prediction market outcomes.

Returns a list of recently settled prediction market outcomes, ordered by most recent first.

## POST Request

<table><thead><tr><th width="161">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"settledOutcomes"</code></td></tr><tr><td><code>limit</code></td><td>integer</td><td>Max results to return, default 100, max 100 (optional)</td></tr><tr><td><code>kind</code></td><td>string</td><td><code>"all"</code> (default), <code>"price"</code>, or <code>"canonical"</code> — see <a href="#the-kind-filter">The kind filter</a> (optional)</td></tr><tr><td><code>name</code></td><td>string</td><td>Filter by outcome name (optional)</td></tr><tr><td><code>class</code></td><td>string</td><td>Filter by outcome class, e.g. <code>"priceBinary"</code> (optional)</td></tr><tr><td><code>underlying</code></td><td>string</td><td>Filter by underlying asset, e.g. <code>"HYPE"</code> (optional)</td></tr><tr><td><code>period</code></td><td>string</td><td>Filter by period, e.g. <code>"15m"</code> (optional)</td></tr><tr><td><code>category</code></td><td>string</td><td>Filter by canonical-market category, e.g. <code>"sports"</code>, case-insensitive (optional)</td></tr><tr><td><code>subCategory</code></td><td>string</td><td>Filter by canonical-market sub-category, case-insensitive (optional)</td></tr><tr><td><code>search</code></td><td>string</td><td>Free-text search across name, description, category and subCategory — see <a href="#free-text-search">Free-text search</a> (optional)</td></tr><tr><td><code>venue</code></td><td>string</td><td>Only outcomes deployed by this permissionless venue, e.g. <code>"skew"</code>. 2–4 ASCII letters, case-insensitive (optional)</td></tr><tr><td><code>deployedBy</code></td><td>string</td><td><code>"all"</code> (default), <code>"validator"</code> (registered by validator quorum, no venue), or <code>"venue"</code> (any permissionless venue) (optional)</td></tr></tbody></table>

> By default (`kind` omitted) all outcome kinds are returned. Pass `kind: "price"` for structured price markets only, or `kind: "canonical"` for HIP-4 prose markets only. See [The kind filter](#the-kind-filter).

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "settledOutcomes",
    "limit": 10,
    "underlying": "HYPE"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'settledOutcomes',
        'limit': 10,
        'underlying': 'HYPE'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'settledOutcomes',
        limit: 10,
        underlying: 'HYPE'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

Only outcomes deployed by the `skew` venue, then only validator-deployed outcomes:

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type": "settledOutcomes", "kind": "all", "venue": "skew"}'

curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type": "settledOutcomes", "kind": "all", "deployedBy": "validator"}'
```

***

## Response Fields

Returns an object with two arrays: `outcomes` (the settled outcome objects, sorted descending by `outcomeId`) and `questions` (the parent HIP-4 questions of any priceBucket children that appear in `outcomes`, sorted descending by `questionId`). Both arrays are always present, even when empty.

The `limit` and the filter parameters (`name`, `class`, `underlying`, `period`, `search`) apply to `outcomes` only. `questions` is derived from the resulting outcomes — a question is included if at least one of its children (named or fallback) is in the `outcomes` result. Practical implications: filtering by `class: "priceBinary"` yields priceBinary outcomes plus an empty `questions` array (standalone outcomes have no parent question); filtering by `class: "priceBucket"` yields priceBucket children plus their parent question(s).

### Outcome object

| Field              | Type    | Description                                                                                                                                                            |
| ------------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `outcomeId`        | integer | The outcome ID                                                                                                                                                         |
| `kind`             | string  | `"price"` for structured markets, `"canonical"` for HIP-4 validator-voted (prose) markets                                                                              |
| `name`             | string  | Outcome name from the register event                                                                                                                                   |
| `description`      | string  | Pipe-separated description. priceBucket children copy this as-is from the parent question                                                                              |
| `sideSpecs`        | array   | Side specifications, e.g. `[{"name":"Yes"},{"name":"No"}]`                                                                                                             |
| `class`            | string? | `"priceBinary"` or `"priceBucket"`. `null` when `kind` is `"canonical"`                                                                                                |
| `underlying`       | string? | Underlying asset, e.g. `"HYPE"`. `null` when `kind` is `"canonical"`                                                                                                   |
| `expiry`           | string? | Expiry timestamp, e.g. `"20260508-1245"`. `null` when `kind` is `"canonical"`                                                                                          |
| `targetPrice`      | string? | Numeric strike for `priceBinary`; bucket-range string for `priceBucket` (see [Target price formats](#target-price-formats) below). `null` when `kind` is `"canonical"` |
| `period`           | string? | Period, e.g. `"15m"`. `null` when `kind` is `"canonical"`                                                                                                              |
| `category`         | string? | Canonical-market category, e.g. `"sports"`. `null` on price markets                                                                                                    |
| `subCategory`      | string? | Canonical-market sub-category. `null` on price markets                                                                                                                 |
| `quoteToken`       | string  | Quote token ID                                                                                                                                                         |
| `yesAssetId`       | string  | YES-side asset ID, format `"#{outcomeId * 10}"`                                                                                                                        |
| `noAssetId`        | string  | NO-side asset ID, format `"#{outcomeId * 10 + 1}"`                                                                                                                     |
| `settleFraction`   | string  | `"1"` if this outcome won, `"0"` otherwise. priceBucket children: exactly one named child has `"1"`; the fallback has `"1"` only when no named child wins              |
| `settleDetails`    | string? | Settlement result: numeric settle price as a string for price markets (e.g. `"73336"`); freeform decision text for canonical markets                                   |
| `yesStats`         | object  | YES-side market stats. Always present; zero-valued when no fills (see [Stats object](#stats-object) below)                                                             |
| `noStats`          | object  | NO-side market stats                                                                                                                                                   |
| `deployerAddress`  | string? | Permissionless-venue deployer address; null on validator-registered outcomes                                                                                           |
| `deployerVenue`    | string? | Permissionless venue name; null on validator-registered outcomes                                                                                                       |
| `deployerFeeScale` | string? | Multiplier applied to the deployer fee for this market, e.g. `"10"`. `null` on validator-registered outcomes and when the chain uses its default scale of 1            |

### Question object

Question entries appear when the response includes priceBucket children — each such child has a parent question grouping 3 named children plus one fallback child. Question fields:

| Field                 | Type              | Description                                                                                                                                     |
| --------------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `questionId`          | integer           | The question ID (assigned by chain)                                                                                                             |
| `kind`                | string            | `"price"` or `"canonical"`                                                                                                                      |
| `name`                | string            | Question name                                                                                                                                   |
| `description`         | string            | Pipe-separated description; named children copy this as-is                                                                                      |
| `class`               | string?           | `"priceBucket"`. `null` when `kind` is `"canonical"`                                                                                            |
| `underlying`          | string?           | Underlying asset. `null` when `kind` is `"canonical"`                                                                                           |
| `expiry`              | string?           | Expiry timestamp. `null` when `kind` is `"canonical"`                                                                                           |
| `period`              | string?           | Period. `null` when `kind` is `"canonical"`                                                                                                     |
| `priceThresholds`     | string?           | Sorted comma-separated list of 2 cut-points. `null` when `kind` is `"canonical"`                                                                |
| `category`            | string?           | Canonical-market category. `null` on price questions                                                                                            |
| `subCategory`         | string?           | Canonical-market sub-category. `null` on price questions                                                                                        |
| `quoteToken`          | string            | Quote token ID                                                                                                                                  |
| `fallbackOutcome`     | integer           | `outcomeId` of the fallback child                                                                                                               |
| `fallbackName`        | string            | Name of the fallback child                                                                                                                      |
| `fallbackDescription` | string            | Description of the fallback child                                                                                                               |
| `namedOutcomes`       | array of integers | `outcomeId`s of the 3 named children, in named-index order                                                                                      |
| `winningOutcome`      | integer?          | `outcomeId` of the child that resolved YES (a named child, or the fallback if all named children resolve NO). `null` until the question settles |
| `winningNamedIndex`   | integer?          | Position in `namedOutcomes` of the winner if a named child won, `null` if the fallback won (or unsettled)                                       |
| `settleDetails`       | string?           | Numeric settle price for price questions; freeform decision text for canonical questions                                                        |
| `time`                | integer           | Settlement timestamp (ms)                                                                                                                       |
| `stats`               | object            | Aggregate trading stats across the question's children. Always present; zero-valued when no fills. See [Stats object](#stats-object) below.     |
| `deployerAddress`     | string?           | Permissionless-venue deployer address; null on validator-registered questions                                                                   |
| `deployerVenue`       | string?           | Permissionless venue name; null on validator-registered questions                                                                               |
| `deployerFeeScale`    | string?           | Multiplier applied to the deployer fee, e.g. `"10"`. `null` on validator-registered questions and when the chain uses its default scale of 1    |

### Target price formats

The `targetPrice` field on each outcome is a string whose format depends on the outcome's `class`.

**`priceBinary`** — a single numeric strike. The outcome resolves YES if the underlying's settle price meets the strike, NO otherwise.

```
"targetPrice": "52.328"
```

**`priceBucket`** — outcomes belong to a parent question that defines `priceThresholds` (a sorted comma-separated list of 2 cut-points splitting the price line into 3 buckets). The question has 3 named children plus one fallback child. Each named child resolves YES if the settle price falls in its bucket; the fallback child resolves YES if all named children resolve NO. The format mirrors interval notation:

| Child role                     | `targetPrice` value | Example (thresholds `80828, 81071`) |
| ------------------------------ | ------------------- | ----------------------------------- |
| First named child (index `0`)  | `<t0`               | `<80828`                            |
| Middle named child (index `1`) | `[t0,t1)`           | `[80828,81071)`                     |
| Last named child (index `2`)   | `>=t1`              | `>=81071`                           |
| Fallback child                 | raw threshold list  | `80828,81071`                       |

The fallback's literal comma-separated value signals "any price not covered by a named child" rather than a specific range. Use the parent question's `priceThresholds` field if you need to render the fallback's range yourself.

### Stats object

All fields except `settlementClosedPnl` reflect orderbook trading only. Fills with `dir = "Settlement"` (auto-close fills produced when the outcome settles, at price 1 for the winning side and 0 for the losing side) are excluded so vwap, lastPrice, min/max, largestTrade, and avg/median trade notional aren't distorted by them. `settlementClosedPnl` summarises the realized PnL across those Settlement-direction fills for the side.

| Field                 | Type    | Description                                                         |
| --------------------- | ------- | ------------------------------------------------------------------- |
| `coin`                | string  | Asset ID for this side                                              |
| `trades`              | integer | Number of orderbook fills                                           |
| `uniqueTraders`       | integer | Distinct users that traded this side                                |
| `volumeNotional`      | string  | Sum of `px * sz` across orderbook fills                             |
| `volumeContracts`     | string  | Sum of `sz` across orderbook fills                                  |
| `lastPrice`           | string  | Price of the most recent orderbook fill                             |
| `vwap`                | number  | Volume-weighted average orderbook price                             |
| `minPrice`            | string  | Minimum orderbook fill price                                        |
| `maxPrice`            | string  | Maximum orderbook fill price                                        |
| `avgTradeNotional`    | number  | Mean `px * sz` across orderbook fills                               |
| `medianTradeNotional` | number  | Median `px * sz` across orderbook fills                             |
| `largestTrade`        | string  | Maximum `px * sz` of any orderbook fill                             |
| `firstTrade`          | integer | Timestamp (ms) of earliest orderbook fill                           |
| `lastTrade`           | integer | Timestamp (ms) of latest orderbook fill                             |
| `settlementClosedPnl` | string  | Sum of `closed_pnl` across Settlement-direction fills for this side |

#### Question stats object

Question stats are intentionally trimmed compared to outcome stats. Price-shaped metrics (`lastPrice`, `vwap`, `minPrice`, `maxPrice`, `largestTrade`, `avgTradeNotional`, `medianTradeNotional`) don't aggregate cleanly across the children's YES + NO assets, so they aren't reported. There's no `coin` field — questions don't own a single asset. Settlement and the four HIP-4 conversion ops (`Split Outcome`, `Negate Outcome`, `Merge Outcome`, `Merge Question`) are excluded from all metrics.

| Field             | Type    | Description                                                                                                                                                          |
| ----------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `trades`          | integer | Number of orderbook matches across all child YES + NO assets. Counts each chain match exactly once (filters to `dir = 'Buy'`; every match emits one Buy + one Sell). |
| `uniqueTraders`   | integer | Distinct users that traded any child asset (Buy or Sell).                                                                                                            |
| `volumeNotional`  | string  | Sum of `px * sz` across `dir = 'Buy'` fills on any child.                                                                                                            |
| `volumeContracts` | string  | Sum of `sz` across `dir = 'Buy'` fills on any child.                                                                                                                 |
| `firstTrade`      | integer | Timestamp (ms) of the earliest orderbook fill on any child.                                                                                                          |
| `lastTrade`       | integer | Timestamp (ms) of the latest orderbook fill on any child.                                                                                                            |

<details>

<summary>Response</summary>

The example covers three settled outcomes — a named priceBucket child (`7604`), the fallback child of the same question (`7601`), and a standalone priceBinary outcome (`7600`) — all with `settleFraction: "0"` (`"0"` for losers, `"1"` for the winner). Question `302`'s actual winner is `7603`, surfaced in the question's `winningOutcome` field; the question itself is automatically derived into `questions` because its child `7604` appears in `outcomes`.

```json
{
  "outcomes": [
    {
      "outcomeId": 7604,
      "kind": "price",
      "name": "Recurring Named Outcome",
      "description": "class:priceBucket|underlying:BTC|expiry:20260508-1245|priceThresholds:80518,80760|period:15m",
      "sideSpecs": [{"name": "Yes"}, {"name": "No"}],
      "class": "priceBucket",
      "underlying": "BTC",
      "expiry": "20260508-1245",
      "targetPrice": ">=80760",
      "period": "15m",
      "category": null,
      "subCategory": null,
      "quoteToken": "1452",
      "yesAssetId": "#76040",
      "noAssetId": "#76041",
      "settleFraction": "0",
      "settleDetails": "80547.9",
      "yesStats": { "coin": "#76040", "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0", "vwap": 0.0, "minPrice": "0", "maxPrice": "0", "avgTradeNotional": 0.0, "medianTradeNotional": 0.0, "largestTrade": "0", "firstTrade": 0, "lastTrade": 0, "settlementClosedPnl": "0" },
      "noStats":  { "coin": "#76041", "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0", "vwap": 0.0, "minPrice": "0", "maxPrice": "0", "avgTradeNotional": 0.0, "medianTradeNotional": 0.0, "largestTrade": "0", "firstTrade": 0, "lastTrade": 0, "settlementClosedPnl": "0" }
    },
    {
      "outcomeId": 7601,
      "kind": "price",
      "name": "Recurring Fallback",
      "description": "class:priceBucket|underlying:BTC|expiry:20260508-1245|priceThresholds:80518,80760|period:15m",
      "sideSpecs": [{"name": "Yes"}, {"name": "No"}],
      "class": "priceBucket",
      "underlying": "BTC",
      "expiry": "20260508-1245",
      "targetPrice": "80518,80760",
      "period": "15m",
      "category": null,
      "subCategory": null,
      "quoteToken": "1452",
      "yesAssetId": "#76010",
      "noAssetId": "#76011",
      "settleFraction": "0",
      "settleDetails": "80547.9",
      "yesStats": { "coin": "#76010", "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0", "vwap": 0.0, "minPrice": "0", "maxPrice": "0", "avgTradeNotional": 0.0, "medianTradeNotional": 0.0, "largestTrade": "0", "firstTrade": 0, "lastTrade": 0, "settlementClosedPnl": "0" },
      "noStats":  { "coin": "#76011", "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0", "vwap": 0.0, "minPrice": "0", "maxPrice": "0", "avgTradeNotional": 0.0, "medianTradeNotional": 0.0, "largestTrade": "0", "firstTrade": 0, "lastTrade": 0, "settlementClosedPnl": "0" }
    },
    {
      "outcomeId": 7600,
      "kind": "price",
      "name": "Recurring",
      "description": "class:priceBinary|underlying:HYPE|expiry:20260508-1245|targetPrice:28.52|period:15m",
      "sideSpecs": [{"name": "Yes"}, {"name": "No"}],
      "class": "priceBinary",
      "underlying": "HYPE",
      "expiry": "20260508-1245",
      "targetPrice": "28.52",
      "period": "15m",
      "category": null,
      "subCategory": null,
      "quoteToken": "1452",
      "yesAssetId": "#76000",
      "noAssetId": "#76001",
      "settleFraction": "0",
      "settleDetails": "28.52",
      "yesStats": { "coin": "#76000", "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0", "vwap": 0.0, "minPrice": "0", "maxPrice": "0", "avgTradeNotional": 0.0, "medianTradeNotional": 0.0, "largestTrade": "0", "firstTrade": 0, "lastTrade": 0, "settlementClosedPnl": "0" },
      "noStats":  { "coin": "#76001", "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0", "vwap": 0.0, "minPrice": "0", "maxPrice": "0", "avgTradeNotional": 0.0, "medianTradeNotional": 0.0, "largestTrade": "0", "firstTrade": 0, "lastTrade": 0, "settlementClosedPnl": "0" }
    }
  ],
  "questions": [
    {
      "questionId": 302,
      "kind": "price",
      "name": "Recurring",
      "description": "class:priceBucket|underlying:BTC|expiry:20260508-1245|priceThresholds:80518,80760|period:15m",
      "class": "priceBucket",
      "underlying": "BTC",
      "expiry": "20260508-1245",
      "period": "15m",
      "priceThresholds": "80518,80760",
      "category": null,
      "subCategory": null,
      "quoteToken": "1452",
      "fallbackOutcome": 7601,
      "fallbackName": "Recurring Fallback",
      "fallbackDescription": "other",
      "namedOutcomes": [7602, 7603, 7604],
      "winningOutcome": 7603,
      "winningNamedIndex": 1,
      "settleDetails": "80547.9",
      "time": 1778244305560,
      "stats": { "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "firstTrade": 0, "lastTrade": 0 }
    }
  ]
}
```

</details>

***

## Free-text search

The optional `search` field matches case-insensitively against `name`, `description`, `category` and `subCategory`, combining with every other filter. A row matches when the whole query appears as a substring of one of those fields, or when every word of the query matches some word of a field:

* exactly, or
* as a prefix (for query words of at least 4 characters), or
* within a spelling-error budget (Damerau-Levenshtein distance): words of 5–8 characters allow 1 error, 9 or more allow 2. Words of up to 4 characters get no error budget — tickers and venue codes like `BTC` never near-match.

Examples: `"world cup"` matches `World Cup Final: Spain vs Argentina`; so do `"wolrd cup"` (typo) and `"spain argent"` (partial words, any order). `"BTX"` does not match `BTC`. Result order and `limit` semantics are unchanged.

## The kind filter

A single optional `kind` request field selects which markets are returned:

| `kind`            | Returns                                                        |
| ----------------- | -------------------------------------------------------------- |
| `"all"` (default) | Both kinds in one `outcomes` / `questions` envelope.           |
| `"price"`         | Structured price markets only (`priceBinary` / `priceBucket`). |
| `"canonical"`     | HIP-4 validator-voted (prose) markets only.                    |

The response shape is identical regardless of `kind` — the same `outcomes` / `questions` envelope, sort order, stats objects, and `limit` semantics. Each row carries a `kind` field telling you which it is.

**Nullability by kind.** On a `kind: "price"` response the structured fields (`class`, `underlying`, `expiry`, `targetPrice`, `period`) are always populated and `category` / `subCategory` are `null`. On a `kind: "canonical"` response those structured fields are `null` and `category` / `subCategory` are populated. A `kind: "all"` response mixes both, so treat every structured field as nullable and branch on `kind`.


# registeredOutcomesById

Get registered prediction market outcomes by their outcome IDs or asset IDs.

Returns metadata and stats for one or more registered prediction market outcomes that have not yet been settled. Each object consists of metadata and stats.

## POST Request

<table><thead><tr><th width="161">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"registeredOutcomesById"</code></td></tr><tr><td><code>kind</code></td><td>string</td><td><code>"all"</code> (default for by-id), <code>"price"</code>, or <code>"canonical"</code> — see <a href="#the-kind-filter">The kind filter</a> (optional)</td></tr><tr><td><code>outcome_ids</code></td><td>integer[]</td><td>Array of outcome IDs (optional)</td></tr><tr><td><code>asset_ids</code></td><td>string[]</td><td>Array of asset IDs prefixed with <code>#</code>, e.g. <code>"#36360"</code> (optional)</td></tr><tr><td><code>question_ids</code></td><td>integer[]</td><td>Array of HIP-4 question IDs (optional). Each question is server-side-expanded to its child outcomes (named + fallback), which appear in <code>outcomes</code>. The question itself appears in <code>questions</code>.</td></tr></tbody></table>

At least one of `outcome_ids`, `asset_ids`, or `question_ids` must be provided and non-empty. They can be combined — the results are merged and deduplicated. The combined number of unique IDs must not exceed 100.

Filtering by `outcome_ids` or `asset_ids` for a child of a question also surfaces the parent question in the `questions` array, so a single child lookup always returns its enclosing question.

> By default (`kind` omitted) **all** requested ids are returned regardless of market type — a by-id lookup names exact rows, so it doesn't apply the list endpoints' price default. Pass `kind: "price"` to restrict to structured markets, or `kind: "canonical"` for HIP-4 validator-voted (prose) markets only. See [The kind filter](#the-kind-filter).

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "registeredOutcomesById",
    "outcome_ids": [3616],
    "asset_ids": ["#36170"]
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'registeredOutcomesById',
        'outcome_ids': [3616],
        'asset_ids': ['#36170']
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'registeredOutcomesById',
        outcome_ids: [3616],
        asset_ids: ['#36170']
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

Returns an object with two arrays: `outcomes` (matched outcome objects, sorted descending by `outcomeId`) and `questions` (the parent HIP-4 questions of any priceBucket children that appear in `outcomes`, plus any explicitly-requested `question_ids`, sorted descending by `questionId`). Both arrays are always present, even when empty.

### Outcome object

| Field              | Type    | Description                                                                                                                                                            |
| ------------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `outcomeId`        | integer | The outcome ID                                                                                                                                                         |
| `kind`             | string  | `"price"` for structured markets, `"canonical"` for HIP-4 validator-voted (prose) markets                                                                              |
| `name`             | string  | Outcome name from the register event                                                                                                                                   |
| `description`      | string  | Pipe-separated description. priceBucket children copy this as-is from the parent question                                                                              |
| `sideSpecs`        | array   | Side specifications, e.g. `[{"name":"Yes"},{"name":"No"}]`                                                                                                             |
| `class`            | string? | `"priceBinary"` or `"priceBucket"`. `null` when `kind` is `"canonical"`                                                                                                |
| `underlying`       | string? | Underlying asset, e.g. `"HYPE"`. `null` when `kind` is `"canonical"`                                                                                                   |
| `expiry`           | string? | Expiry timestamp, e.g. `"20260508-1300"`. `null` when `kind` is `"canonical"`                                                                                          |
| `targetPrice`      | string? | Numeric strike for `priceBinary`; bucket-range string for `priceBucket` (see [Target price formats](#target-price-formats) below). `null` when `kind` is `"canonical"` |
| `period`           | string? | Period, e.g. `"15m"`. `null` when `kind` is `"canonical"`                                                                                                              |
| `category`         | string? | Canonical-market category. `null` on price markets                                                                                                                     |
| `subCategory`      | string? | Canonical-market sub-category. `null` on price markets                                                                                                                 |
| `quoteToken`       | string  | Quote token ID                                                                                                                                                         |
| `yesAssetId`       | string  | YES-side asset ID, format `"#{outcomeId * 10}"`                                                                                                                        |
| `noAssetId`        | string  | NO-side asset ID, format `"#{outcomeId * 10 + 1}"`                                                                                                                     |
| `yesStats`         | object  | Market stats for the YES side. Always present; zero-valued when no fills (see [Stats object](#stats-object) below)                                                     |
| `noStats`          | object  | Market stats for the NO side                                                                                                                                           |
| `deployerAddress`  | string? | Permissionless-venue deployer address; null on validator-registered outcomes                                                                                           |
| `deployerVenue`    | string? | Permissionless venue name (see `outcomeMeta.deployers`); null on validator-registered outcomes                                                                         |
| `deployerFeeScale` | string? | Multiplier applied to the deployer fee for this market, e.g. `"10"`. `null` on validator-registered outcomes and when the chain uses its default scale of 1            |

### Question object

| Field                  | Type              | Description                                                                                                                                                        |
| ---------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `questionId`           | integer           | The question ID (assigned by chain)                                                                                                                                |
| `kind`                 | string            | `"price"` or `"canonical"`                                                                                                                                         |
| `name`                 | string            | Question name                                                                                                                                                      |
| `description`          | string            | Pipe-separated description; named children copy this as-is                                                                                                         |
| `class`                | string?           | `"priceBucket"`. `null` when `kind` is `"canonical"`                                                                                                               |
| `underlying`           | string?           | Underlying asset. `null` when `kind` is `"canonical"`                                                                                                              |
| `expiry`               | string?           | Expiry timestamp. `null` when `kind` is `"canonical"`                                                                                                              |
| `period`               | string?           | Period. `null` when `kind` is `"canonical"`                                                                                                                        |
| `priceThresholds`      | string?           | Sorted comma-separated list of 2 cut-points. `null` when `kind` is `"canonical"`                                                                                   |
| `category`             | string?           | Canonical-market category. `null` on price questions                                                                                                               |
| `subCategory`          | string?           | Canonical-market sub-category. `null` on price questions                                                                                                           |
| `quoteToken`           | string            | Quote token ID                                                                                                                                                     |
| `fallbackOutcome`      | integer           | `outcomeId` of the fallback child                                                                                                                                  |
| `fallbackName`         | string            | Name of the fallback child                                                                                                                                         |
| `fallbackDescription`  | string            | Description of the fallback child                                                                                                                                  |
| `namedOutcomes`        | array of integers | `outcomeId`s of the named children still open, in named-index order. A child that settles moves to `settledNamedOutcomes`                                          |
| `settledNamedOutcomes` | array of integers | `outcomeId`s of named children already settled. Disjoint from `namedOutcomes`, matching `outcomeMeta`. A question can have settled children while it is still open |
| `stats`                | object            | Aggregate trading stats across the question's children. Always present; zero-valued when no fills. See [Stats object](#stats-object) below.                        |
| `deployerAddress`      | string?           | Permissionless-venue deployer address; null on validator-registered questions                                                                                      |
| `deployerVenue`        | string?           | Permissionless venue name; null on validator-registered questions                                                                                                  |
| `deployerFeeScale`     | string?           | Multiplier applied to the deployer fee, e.g. `"10"`. `null` on validator-registered questions and when the chain uses its default scale of 1                       |

### Stats object

| Field                 | Type    | Description                          |
| --------------------- | ------- | ------------------------------------ |
| `coin`                | string  | Asset ID for this side               |
| `trades`              | integer | Number of fills                      |
| `uniqueTraders`       | integer | Distinct users that traded this side |
| `volumeNotional`      | string  | Sum of `px * sz` across fills        |
| `volumeContracts`     | string  | Sum of `sz` across fills             |
| `lastPrice`           | string  | Price of the most recent fill        |
| `vwap`                | number  | Volume-weighted average price        |
| `minPrice`            | string  | Minimum fill price                   |
| `maxPrice`            | string  | Maximum fill price                   |
| `avgTradeNotional`    | number  | Mean `px * sz`                       |
| `medianTradeNotional` | number  | Median `px * sz`                     |
| `largestTrade`        | string  | Maximum `px * sz` of any fill        |
| `firstTrade`          | integer | Timestamp (ms) of earliest fill      |
| `lastTrade`           | integer | Timestamp (ms) of latest fill        |

#### Question stats object

Question stats are intentionally trimmed compared to outcome stats. Price-shaped metrics (`lastPrice`, `vwap`, `minPrice`, `maxPrice`, `largestTrade`, `avgTradeNotional`, `medianTradeNotional`) don't aggregate cleanly across the children's YES + NO assets, so they aren't reported. There's no `coin` field — questions don't own a single asset. Settlement and the four HIP-4 conversion ops (`Split Outcome`, `Negate Outcome`, `Merge Outcome`, `Merge Question`) are excluded from all metrics.

| Field             | Type    | Description                                                                                                                                                          |
| ----------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `trades`          | integer | Number of orderbook matches across all child YES + NO assets. Counts each chain match exactly once (filters to `dir = 'Buy'`; every match emits one Buy + one Sell). |
| `uniqueTraders`   | integer | Distinct users that traded any child asset (Buy or Sell).                                                                                                            |
| `volumeNotional`  | string  | Sum of `px * sz` across `dir = 'Buy'` fills on any child.                                                                                                            |
| `volumeContracts` | string  | Sum of `sz` across `dir = 'Buy'` fills on any child.                                                                                                                 |
| `firstTrade`      | integer | Timestamp (ms) of the earliest orderbook fill on any child.                                                                                                          |
| `lastTrade`       | integer | Timestamp (ms) of the latest orderbook fill on any child.                                                                                                            |

### Target price formats

The `targetPrice` field on each outcome is a string whose format depends on the outcome's `class`.

**`priceBinary`** — a single numeric strike. The outcome resolves YES if the underlying's settle price meets the strike, NO otherwise.

```
"targetPrice": "52.328"
```

**`priceBucket`** — outcomes belong to a parent question that defines `priceThresholds` (a sorted comma-separated list of 2 cut-points splitting the price line into 3 buckets). The question has 3 named children plus one fallback child. Each named child resolves YES if the settle price falls in its bucket; the fallback child resolves YES if all named children resolve NO. The format mirrors interval notation:

| Child role                     | `targetPrice` value | Example (thresholds `80828, 81071`) |
| ------------------------------ | ------------------- | ----------------------------------- |
| First named child (index `0`)  | `<t0`               | `<80828`                            |
| Middle named child (index `1`) | `[t0,t1)`           | `[80828,81071)`                     |
| Last named child (index `2`)   | `>=t1`              | `>=81071`                           |
| Fallback child                 | raw threshold list  | `80828,81071`                       |

The fallback's literal comma-separated value signals "any price not covered by a named child" rather than a specific range. Use the parent question's `priceThresholds` field if you need to render the fallback's range yourself.

<details>

<summary>Response</summary>

Example for `{"outcome_ids": [7605, 7609]}`. `7605` is a standalone priceBinary outcome; `7609` is a priceBucket child whose parent question (`303`) is automatically derived into `questions`.

```json
{
  "outcomes": [
    {
      "outcomeId": 7609,
      "name": "Recurring Named Outcome",
      "description": "class:priceBucket|underlying:BTC|expiry:20260508-1300|priceThresholds:80425,80666|period:15m",
      "sideSpecs": [{"name": "Yes"}, {"name": "No"}],
      "class": "priceBucket",
      "underlying": "BTC",
      "expiry": "20260508-1300",
      "targetPrice": ">=80666",
      "period": "15m",
      "quoteToken": "1452",
      "yesAssetId": "#76090",
      "noAssetId": "#76091",
      "yesStats": { "coin": "#76090", "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0", "vwap": 0.0, "minPrice": "0", "maxPrice": "0", "avgTradeNotional": 0.0, "medianTradeNotional": 0.0, "largestTrade": "0", "firstTrade": 0, "lastTrade": 0 },
      "noStats":  { "coin": "#76091", "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0", "vwap": 0.0, "minPrice": "0", "maxPrice": "0", "avgTradeNotional": 0.0, "medianTradeNotional": 0.0, "largestTrade": "0", "firstTrade": 0, "lastTrade": 0 }
    },
    {
      "outcomeId": 7605,
      "name": "Recurring",
      "description": "class:priceBinary|underlying:HYPE|expiry:20260508-1300|targetPrice:28.52|period:15m",
      "sideSpecs": [{"name": "Yes"}, {"name": "No"}],
      "class": "priceBinary",
      "underlying": "HYPE",
      "expiry": "20260508-1300",
      "targetPrice": "28.52",
      "period": "15m",
      "quoteToken": "1452",
      "yesAssetId": "#76050",
      "noAssetId": "#76051",
      "yesStats": { "coin": "#76050", "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0", "vwap": 0.0, "minPrice": "0", "maxPrice": "0", "avgTradeNotional": 0.0, "medianTradeNotional": 0.0, "largestTrade": "0", "firstTrade": 0, "lastTrade": 0 },
      "noStats":  { "coin": "#76051", "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0", "vwap": 0.0, "minPrice": "0", "maxPrice": "0", "avgTradeNotional": 0.0, "medianTradeNotional": 0.0, "largestTrade": "0", "firstTrade": 0, "lastTrade": 0 }
    }
  ],
  "questions": [
    {
      "questionId": 303,
      "name": "Recurring",
      "description": "class:priceBucket|underlying:BTC|expiry:20260508-1300|priceThresholds:80425,80666|period:15m",
      "class": "priceBucket",
      "underlying": "BTC",
      "expiry": "20260508-1300",
      "period": "15m",
      "priceThresholds": "80425,80666",
      "quoteToken": "1452",
      "fallbackOutcome": 7606,
      "fallbackName": "Recurring Fallback",
      "fallbackDescription": "other",
      "namedOutcomes": [7607, 7608, 7609],
      "settledNamedOutcomes": [],
      "stats": { "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "firstTrade": 0, "lastTrade": 0 }
    }
  ]
}
```

</details>

***

## The kind filter

The optional `kind` request field controls which of the requested ids are returned: `"all"` (the by-id default) returns every requested id regardless of type, `"price"` only structured markets, `"canonical"` only HIP-4 validator-voted (prose) markets. An id whose market doesn't match `kind` is omitted from the response.

Each returned row carries a `kind` field. **Nullability by kind:** on a `"price"` row the structured fields (`class`, `underlying`, `expiry`, `targetPrice`, `period`) are populated and `category` / `subCategory` are `null`; on a `"canonical"` row those structured fields are `null` and `category` / `subCategory` are populated.

Request semantics — id-set merging, child expansion via `question_ids`, parent-question derivation from child outcomes, 50-id cap — are unchanged.


# registeredOutcomes

Get recent registered prediction market outcomes.

Returns a list of recently registered prediction market outcomes that have not yet been settled, ordered by most recent first.

## POST Request

<table><thead><tr><th width="161">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"registeredOutcomes"</code></td></tr><tr><td><code>limit</code></td><td>integer</td><td>Max results to return, default 100, max 100 (optional)</td></tr><tr><td><code>kind</code></td><td>string</td><td><code>"all"</code> (default), <code>"price"</code>, or <code>"canonical"</code> — see <a href="#the-kind-filter">The kind filter</a> (optional)</td></tr><tr><td><code>name</code></td><td>string</td><td>Filter by outcome name (optional)</td></tr><tr><td><code>class</code></td><td>string</td><td>Filter by outcome class, e.g. <code>"priceBinary"</code> (optional)</td></tr><tr><td><code>underlying</code></td><td>string</td><td>Filter by underlying asset, e.g. <code>"HYPE"</code> (optional)</td></tr><tr><td><code>period</code></td><td>string</td><td>Filter by period, e.g. <code>"15m"</code> (optional)</td></tr><tr><td><code>category</code></td><td>string</td><td>Filter by canonical-market category, case-insensitive (optional)</td></tr><tr><td><code>subCategory</code></td><td>string</td><td>Filter by canonical-market sub-category, case-insensitive (optional)</td></tr><tr><td><code>search</code></td><td>string</td><td>Free-text search across name, description, category and subCategory — see <a href="#free-text-search">Free-text search</a> (optional)</td></tr><tr><td><code>venue</code></td><td>string</td><td>Only outcomes deployed by this permissionless venue, e.g. <code>"skew"</code>. 2–4 ASCII letters, case-insensitive (optional)</td></tr><tr><td><code>deployedBy</code></td><td>string</td><td><code>"all"</code> (default), <code>"validator"</code> (registered by validator quorum, no venue), or <code>"venue"</code> (any permissionless venue) (optional)</td></tr></tbody></table>

> By default (`kind` omitted) all outcome kinds are returned. Pass `kind: "price"` for structured price markets only, or `kind: "canonical"` for HIP-4 prose markets only. See [The kind filter](#the-kind-filter).

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "registeredOutcomes",
    "limit": 10,
    "underlying": "HYPE"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'registeredOutcomes',
        'limit': 10,
        'underlying': 'HYPE'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'registeredOutcomes',
        limit: 10,
        underlying: 'HYPE'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

Only outcomes deployed by the `skew` venue, then only validator-deployed outcomes:

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type": "registeredOutcomes", "kind": "all", "venue": "skew"}'

curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type": "registeredOutcomes", "kind": "all", "deployedBy": "validator"}'
```

***

## Response Fields

Returns an object with two arrays: `outcomes` (the registered outcome objects, sorted descending by `outcomeId`) and `questions` (the parent HIP-4 questions of any priceBucket children that appear in `outcomes`, sorted descending by `questionId`). Both arrays are always present, even when empty.

The `limit` and the filter parameters (`name`, `class`, `underlying`, `period`, `search`) apply to `outcomes` only. `questions` is derived from the resulting outcomes — a question is included if at least one of its children (named or fallback) is in the `outcomes` result. Practical implications: filtering by `class: "priceBinary"` yields priceBinary outcomes plus an empty `questions` array (standalone outcomes have no parent question); filtering by `class: "priceBucket"` yields priceBucket children plus their parent question(s).

### Outcome object

| Field              | Type    | Description                                                                                                                                                            |
| ------------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `outcomeId`        | integer | The outcome ID                                                                                                                                                         |
| `kind`             | string  | `"price"` for structured markets, `"canonical"` for HIP-4 validator-voted (prose) markets                                                                              |
| `name`             | string  | Outcome name from the register event                                                                                                                                   |
| `description`      | string  | Pipe-separated description (\`class:...                                                                                                                                |
| `sideSpecs`        | array   | Side specifications, e.g. `[{"name":"Yes"},{"name":"No"}]`                                                                                                             |
| `class`            | string? | `"priceBinary"` or `"priceBucket"`. `null` when `kind` is `"canonical"`                                                                                                |
| `underlying`       | string? | Underlying asset, e.g. `"HYPE"`. `null` when `kind` is `"canonical"`                                                                                                   |
| `expiry`           | string? | Expiry timestamp, e.g. `"20260508-1300"`. `null` when `kind` is `"canonical"`                                                                                          |
| `targetPrice`      | string? | Numeric strike for `priceBinary`; bucket-range string for `priceBucket` (see [Target price formats](#target-price-formats) below). `null` when `kind` is `"canonical"` |
| `period`           | string? | Period, e.g. `"15m"`. `null` when `kind` is `"canonical"`                                                                                                              |
| `category`         | string? | Canonical-market category. `null` on price markets                                                                                                                     |
| `subCategory`      | string? | Canonical-market sub-category. `null` on price markets                                                                                                                 |
| `quoteToken`       | string  | Quote token ID                                                                                                                                                         |
| `yesAssetId`       | string  | YES-side asset ID, format `"#{outcomeId * 10}"`                                                                                                                        |
| `noAssetId`        | string  | NO-side asset ID, format `"#{outcomeId * 10 + 1}"`                                                                                                                     |
| `yesStats`         | object  | Market stats for the YES side. Always present; zero-valued when no fills (see [Stats object](#stats-object) below)                                                     |
| `noStats`          | object  | Market stats for the NO side                                                                                                                                           |
| `deployerAddress`  | string? | Permissionless-venue deployer address; null on validator-registered outcomes                                                                                           |
| `deployerVenue`    | string? | Permissionless venue name (see `outcomeMeta.deployers`); null on validator-registered outcomes                                                                         |
| `deployerFeeScale` | string? | Multiplier applied to the deployer fee for this market, e.g. `"10"`. `null` on validator-registered outcomes and when the chain uses its default scale of 1            |

### Question object

Question entries appear when the response includes priceBucket children — each such child has a parent question grouping 3 named children plus one fallback child. Question fields:

| Field                  | Type              | Description                                                                                                                                                        |
| ---------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `questionId`           | integer           | The question ID (assigned by chain)                                                                                                                                |
| `kind`                 | string            | `"price"` or `"canonical"`                                                                                                                                         |
| `name`                 | string            | Question name                                                                                                                                                      |
| `description`          | string            | Pipe-separated description; named children copy this as-is                                                                                                         |
| `class`                | string?           | `"priceBucket"`. `null` when `kind` is `"canonical"`                                                                                                               |
| `underlying`           | string?           | Underlying asset. `null` when `kind` is `"canonical"`                                                                                                              |
| `expiry`               | string?           | Expiry timestamp. `null` when `kind` is `"canonical"`                                                                                                              |
| `period`               | string?           | Period. `null` when `kind` is `"canonical"`                                                                                                                        |
| `priceThresholds`      | string?           | Sorted comma-separated list of 2 cut-points. `null` when `kind` is `"canonical"`                                                                                   |
| `category`             | string?           | Canonical-market category. `null` on price questions                                                                                                               |
| `subCategory`          | string?           | Canonical-market sub-category. `null` on price questions                                                                                                           |
| `quoteToken`           | string            | Quote token ID                                                                                                                                                     |
| `fallbackOutcome`      | integer           | `outcomeId` of the fallback child                                                                                                                                  |
| `fallbackName`         | string            | Name of the fallback child                                                                                                                                         |
| `fallbackDescription`  | string            | Description of the fallback child                                                                                                                                  |
| `namedOutcomes`        | array of integers | `outcomeId`s of the named children still open, in named-index order. A child that settles moves to `settledNamedOutcomes`                                          |
| `settledNamedOutcomes` | array of integers | `outcomeId`s of named children already settled. Disjoint from `namedOutcomes`, matching `outcomeMeta`. A question can have settled children while it is still open |
| `stats`                | object            | Aggregate trading stats across the question's children. Always present; zero-valued when no fills. See [Stats object](#stats-object) below.                        |
| `deployerAddress`      | string?           | Permissionless-venue deployer address; null on validator-registered questions                                                                                      |
| `deployerVenue`        | string?           | Permissionless venue name; null on validator-registered questions                                                                                                  |
| `deployerFeeScale`     | string?           | Multiplier applied to the deployer fee, e.g. `"10"`. `null` on validator-registered questions and when the chain uses its default scale of 1                       |

### Stats object

All stats fields reflect orderbook trading. The object is always emitted — when there are no fills, every numeric field is zero and timestamps are `0`.

| Field                 | Type    | Description                          |
| --------------------- | ------- | ------------------------------------ |
| `coin`                | string  | Asset ID for this side               |
| `trades`              | integer | Number of fills                      |
| `uniqueTraders`       | integer | Distinct users that traded this side |
| `volumeNotional`      | string  | Sum of `px * sz` across fills        |
| `volumeContracts`     | string  | Sum of `sz` across fills             |
| `lastPrice`           | string  | Price of the most recent fill        |
| `vwap`                | number  | Volume-weighted average price        |
| `minPrice`            | string  | Minimum fill price                   |
| `maxPrice`            | string  | Maximum fill price                   |
| `avgTradeNotional`    | number  | Mean `px * sz`                       |
| `medianTradeNotional` | number  | Median `px * sz`                     |
| `largestTrade`        | string  | Maximum `px * sz` of any fill        |
| `firstTrade`          | integer | Timestamp (ms) of earliest fill      |
| `lastTrade`           | integer | Timestamp (ms) of latest fill        |

#### Question stats object

Question stats are intentionally trimmed compared to outcome stats. Price-shaped metrics (`lastPrice`, `vwap`, `minPrice`, `maxPrice`, `largestTrade`, `avgTradeNotional`, `medianTradeNotional`) don't aggregate cleanly across the children's YES + NO assets, so they aren't reported. There's no `coin` field — questions don't own a single asset. Settlement and the four HIP-4 conversion ops (`Split Outcome`, `Negate Outcome`, `Merge Outcome`, `Merge Question`) are excluded from all metrics.

| Field             | Type    | Description                                                                                                                                                          |
| ----------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `trades`          | integer | Number of orderbook matches across all child YES + NO assets. Counts each chain match exactly once (filters to `dir = 'Buy'`; every match emits one Buy + one Sell). |
| `uniqueTraders`   | integer | Distinct users that traded any child asset (Buy or Sell).                                                                                                            |
| `volumeNotional`  | string  | Sum of `px * sz` across `dir = 'Buy'` fills on any child.                                                                                                            |
| `volumeContracts` | string  | Sum of `sz` across `dir = 'Buy'` fills on any child.                                                                                                                 |
| `firstTrade`      | integer | Timestamp (ms) of the earliest orderbook fill on any child.                                                                                                          |
| `lastTrade`       | integer | Timestamp (ms) of the latest orderbook fill on any child.                                                                                                            |

### Target price formats

The `targetPrice` field on each outcome is a string whose format depends on the outcome's `class`.

**`priceBinary`** — a single numeric strike. The outcome resolves YES if the underlying's settle price meets the strike, NO otherwise.

```
"targetPrice": "52.328"
```

**`priceBucket`** — outcomes belong to a parent question that defines `priceThresholds` (a sorted comma-separated list of 2 cut-points splitting the price line into 3 buckets). The question has 3 named children plus one fallback child. Each named child resolves YES if the settle price falls in its bucket; the fallback child resolves YES if all named children resolve NO. The format mirrors interval notation:

| Child role                     | `targetPrice` value | Example (thresholds `80828, 81071`) |
| ------------------------------ | ------------------- | ----------------------------------- |
| First named child (index `0`)  | `<t0`               | `<80828`                            |
| Middle named child (index `1`) | `[t0,t1)`           | `[80828,81071)`                     |
| Last named child (index `2`)   | `>=t1`              | `>=81071`                           |
| Fallback child                 | raw threshold list  | `80828,81071`                       |

The fallback's literal comma-separated value signals "any price not covered by a named child" rather than a specific range. Use the parent question's `priceThresholds` field if you need to render the fallback's range yourself.

<details>

<summary>Response</summary>

The example covers a priceBucket child (`outcomeId: 7609`), the corresponding fallback child (`7606`), a standalone priceBinary outcome (`7605`), and a child of a different question (`7470`) — plus both parent questions. Question `275` shows non-zero stats (16 fills); question `303` shows the zero-state.

```json
{
  "outcomes": [
    {
      "outcomeId": 7609,
      "name": "Recurring Named Outcome",
      "description": "class:priceBucket|underlying:BTC|expiry:20260508-1300|priceThresholds:80425,80666|period:15m",
      "sideSpecs": [{"name": "Yes"}, {"name": "No"}],
      "class": "priceBucket",
      "underlying": "BTC",
      "expiry": "20260508-1300",
      "targetPrice": ">=80666",
      "period": "15m",
      "quoteToken": "1452",
      "yesAssetId": "#76090",
      "noAssetId": "#76091",
      "yesStats": {
        "coin": "#76090", "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0",
        "lastPrice": "0", "vwap": 0.0, "minPrice": "0", "maxPrice": "0",
        "avgTradeNotional": 0.0, "medianTradeNotional": 0.0, "largestTrade": "0",
        "firstTrade": 0, "lastTrade": 0
      },
      "noStats": {
        "coin": "#76091", "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0",
        "lastPrice": "0", "vwap": 0.0, "minPrice": "0", "maxPrice": "0",
        "avgTradeNotional": 0.0, "medianTradeNotional": 0.0, "largestTrade": "0",
        "firstTrade": 0, "lastTrade": 0
      }
    },
    {
      "outcomeId": 7606,
      "name": "Recurring Fallback",
      "description": "class:priceBucket|underlying:BTC|expiry:20260508-1300|priceThresholds:80425,80666|period:15m",
      "sideSpecs": [{"name": "Yes"}, {"name": "No"}],
      "class": "priceBucket",
      "underlying": "BTC",
      "expiry": "20260508-1300",
      "targetPrice": "80425,80666",
      "period": "15m",
      "quoteToken": "1452",
      "yesAssetId": "#76060",
      "noAssetId": "#76061",
      "yesStats": { "coin": "#76060", "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0", "vwap": 0.0, "minPrice": "0", "maxPrice": "0", "avgTradeNotional": 0.0, "medianTradeNotional": 0.0, "largestTrade": "0", "firstTrade": 0, "lastTrade": 0 },
      "noStats":  { "coin": "#76061", "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0", "vwap": 0.0, "minPrice": "0", "maxPrice": "0", "avgTradeNotional": 0.0, "medianTradeNotional": 0.0, "largestTrade": "0", "firstTrade": 0, "lastTrade": 0 }
    },
    {
      "outcomeId": 7605,
      "name": "Recurring",
      "description": "class:priceBinary|underlying:HYPE|expiry:20260508-1300|targetPrice:28.52|period:15m",
      "sideSpecs": [{"name": "Yes"}, {"name": "No"}],
      "class": "priceBinary",
      "underlying": "HYPE",
      "expiry": "20260508-1300",
      "targetPrice": "28.52",
      "period": "15m",
      "quoteToken": "1452",
      "yesAssetId": "#76050",
      "noAssetId": "#76051",
      "yesStats": { "coin": "#76050", "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0", "vwap": 0.0, "minPrice": "0", "maxPrice": "0", "avgTradeNotional": 0.0, "medianTradeNotional": 0.0, "largestTrade": "0", "firstTrade": 0, "lastTrade": 0 },
      "noStats":  { "coin": "#76051", "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0", "vwap": 0.0, "minPrice": "0", "maxPrice": "0", "avgTradeNotional": 0.0, "medianTradeNotional": 0.0, "largestTrade": "0", "firstTrade": 0, "lastTrade": 0 }
    },
    {
      "outcomeId": 7470,
      "name": "Recurring Named Outcome",
      "description": "class:priceBucket|underlying:BTC|expiry:20260509-0600|priceThresholds:78342,81539|period:1d",
      "sideSpecs": [{"name": "Yes"}, {"name": "No"}],
      "class": "priceBucket",
      "underlying": "BTC",
      "expiry": "20260509-0600",
      "targetPrice": ">=81539",
      "period": "1d",
      "quoteToken": "1452",
      "yesAssetId": "#74700",
      "noAssetId": "#74701",
      "yesStats": { "coin": "#74700", "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0", "vwap": 0.0, "minPrice": "0", "maxPrice": "0", "avgTradeNotional": 0.0, "medianTradeNotional": 0.0, "largestTrade": "0", "firstTrade": 0, "lastTrade": 0 },
      "noStats":  { "coin": "#74701", "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "lastPrice": "0", "vwap": 0.0, "minPrice": "0", "maxPrice": "0", "avgTradeNotional": 0.0, "medianTradeNotional": 0.0, "largestTrade": "0", "firstTrade": 0, "lastTrade": 0 }
    }
  ],
  "questions": [
    {
      "questionId": 303,
      "name": "Recurring",
      "description": "class:priceBucket|underlying:BTC|expiry:20260508-1300|priceThresholds:80425,80666|period:15m",
      "class": "priceBucket",
      "underlying": "BTC",
      "expiry": "20260508-1300",
      "period": "15m",
      "priceThresholds": "80425,80666",
      "quoteToken": "1452",
      "fallbackOutcome": 7606,
      "fallbackName": "Recurring Fallback",
      "fallbackDescription": "other",
      "namedOutcomes": [7607, 7608, 7609],
      "settledNamedOutcomes": [],
      "stats": { "trades": 0, "uniqueTraders": 0, "volumeNotional": "0", "volumeContracts": "0", "firstTrade": 0, "lastTrade": 0 }
    },
    {
      "questionId": 275,
      "name": "Recurring",
      "description": "class:priceBucket|underlying:BTC|expiry:20260509-0600|priceThresholds:78342,81539|period:1d",
      "class": "priceBucket",
      "underlying": "BTC",
      "expiry": "20260509-0600",
      "period": "1d",
      "priceThresholds": "78342,81539",
      "quoteToken": "1452",
      "fallbackOutcome": 7467,
      "fallbackName": "Recurring Fallback",
      "fallbackDescription": "other",
      "namedOutcomes": [7468, 7469, 7470],
      "settledNamedOutcomes": [],
      "stats": {
        "trades": 16, "uniqueTraders": 2,
        "volumeNotional": "7799.98", "volumeContracts": "14000.00",
        "firstTrade": 1778222714885, "lastTrade": 1778223020033
      }
    }
  ]
}
```

</details>

***

## Free-text search

The optional `search` field matches case-insensitively against `name`, `description`, `category` and `subCategory`, combining with every other filter. A row matches when the whole query appears as a substring of one of those fields, or when every word of the query matches some word of a field:

* exactly, or
* as a prefix (for query words of at least 4 characters), or
* within a spelling-error budget (Damerau-Levenshtein distance): words of 5–8 characters allow 1 error, 9 or more allow 2. Words of up to 4 characters get no error budget — tickers and venue codes like `BTC` never near-match.

Examples: `"world cup"` matches `World Cup Final: Spain vs Argentina`; so do `"wolrd cup"` (typo) and `"spain argent"` (partial words, any order). `"BTX"` does not match `BTC`. Result order and `limit` semantics are unchanged.

## The kind filter

A single optional `kind` request field selects which markets are returned:

| `kind`            | Returns                                              |
| ----------------- | ---------------------------------------------------- |
| `"all"` (default) | Both kinds in one `outcomes` / `questions` envelope. |
| `"price"`         | Structured price markets only.                       |
| `"canonical"`     | HIP-4 validator-voted (prose) markets only.          |

The response shape is identical regardless of `kind`; each row carries a `kind` field telling you which it is.

**Nullability by kind.** On a `kind: "price"` response the structured fields (`class`, `underlying`, `expiry`, `targetPrice`, `period`) are always populated and `category` / `subCategory` are `null`. On a `kind: "canonical"` response those structured fields are `null` and `category` / `subCategory` are populated. A `kind: "all"` response mixes both, so treat every structured field as nullable and branch on `kind`.


# registeredOutcomesSnapshot

Per-side balance snapshots of every active prediction market outcome (zstd+msgpack).

{% hint style="warning" %}

### ⚠️ This is an add-on endpoint - access has to be purchased separately.

{% endhint %}

{% hint style="info" %}
**New: entry values (opt-in).** Pass `"includeEntryValues": true` to receive each balance entry as a `[size, entry_value]` 2-element array instead of a bare size string. The default response shape is unchanged — existing consumers are unaffected. See [Data Format](#data-format) below for both shapes.
{% endhint %}

Returns compressed snapshots for active HIP-4 outcomes — one snapshot per outcome side (YES/NO). Each snapshot lists every holder of that side, their balance, and their cumulative on-chain entry value.

There are two endpoints:

1. **Metadata Endpoint (Fast)** — check whether new snapshots are available.
2. **Snapshot Endpoint (Heavy)** — download compressed snapshot data.

***

## registeredOutcomesSnapshotTimestamp (Fast)

* **Endpoint:** `POST /info`
* **Purpose:** check whether new snapshots have been written
* **Response time:** \~1 ms

### Request

<table><thead><tr><th width="161">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"registeredOutcomesSnapshotTimestamp"</code></td></tr></tbody></table>

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "type": "registeredOutcomesSnapshotTimestamp" }'
```

### Response

```json
{
  "snapshot_id": "20260428_state_123456789",
  "timestamp": 1745846400
}
```

***

## registeredOutcomesSnapshot (Heavy)

* **Endpoint:** `POST /info`
* **Purpose:** download per-side outcome snapshots
* **Response time:** \~100 ms+

### Request

<table><thead><tr><th width="161">Field</th><th width="170">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"registeredOutcomesSnapshot"</code></td></tr><tr><td><code>outcome_ids</code></td><td>array of integers</td><td>Outcome ids to fetch (optional). Each id expands to two asset_ids: YES = <code>#{id*10}</code>, NO = <code>#{id*10+1}</code>.</td></tr><tr><td><code>asset_ids</code></td><td>array of strings</td><td>Asset ids in <code>#NNNN</code> format (optional). Used as-is.</td></tr><tr><td><code>question_ids</code></td><td>array of integers</td><td>HIP-4 question ids (optional). Each is server-side-expanded to its child outcomes (named + fallback), then each child to its YES + NO asset_ids.</td></tr><tr><td><code>includeEntryValues</code></td><td>boolean</td><td>Optional, default <code>false</code>. When <code>true</code>, each balances entry is a <code>[size, entry_value]</code> 2-element array instead of a bare size string.</td></tr></tbody></table>

If `outcome_ids`, `asset_ids`, and `question_ids` are all omitted, the response contains every active outcome side.

After deduplication, the combined `outcome_ids` (expanded) + `asset_ids` + `question_ids` (expanded to children, then to asset\_ids) list must not exceed **50 entries**; larger requests are rejected with `400 Bad Request`.

```bash
# Specific outcomes (YES + NO)
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  --output outcomes.bin \
  -d '{ "type": "registeredOutcomesSnapshot", "outcome_ids": [3, 7] }'

# All active outcomes
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  --output outcomes.bin \
  -d '{ "type": "registeredOutcomesSnapshot" }'
```

### Response Headers

* **Single asset\_id:** `x-payload-format: msgpack`, `Content-Encoding: zstd`
* **Multiple asset\_ids:** `x-payload-format: multi-zstd`, `x-compression: inner-zstd`

### Data Format

<details>

<summary>Single Snapshot Response</summary>

**Format:** raw zstd-compressed MessagePack.

**Decompressed structure** — a positional 4-element array. rmp-serde encodes Rust structs as msgpack arrays by default, so the field order matters, not the names:

Default (`includeEntryValues` omitted or `false`) — balances are bare size strings:

```json
[
  "20260428_state_123456789",            // [0] snapshot_id
  3,                                      // [1] outcome_id
  "#30",                                  // [2] asset_id
  {                                       // [3] balances — address → size
    "0xa11ce...000a": "100",
    "0xb0b...000b": "5"
  }
]
```

With `"includeEntryValues": true` — each balances entry is a `[size, entry_value]` 2-element array:

```json
[
  "20260428_state_123456789",            // [0] snapshot_id
  3,                                      // [1] outcome_id
  "#30",                                  // [2] asset_id
  {                                       // [3] balances — address → [size, entry_value]
    "0xa11ce...000a": ["100", "30.50"],
    "0xb0b...000b": ["5", "1.25"]
  }
]
```

> **Note:** both strings in either shape:
>
> * **`size`** is formatted via HL's size-decimals rules. Outcome side tokens currently ship with `szDecimals=0` and `weiDecimals=5` on-chain; the producer reads both per-token from spot meta and uses them to descale and format. With `szDecimals=0`, sizes are rounded to whole lots and rendered as integer strings — no decimal point, no trailing zeros (`"100"`, not `"100.00"`). Sub-lot dust uses banker's rounding (round-half-to-even). Parse with `int(s)`.
> * **`entry_value`** (only with `includeEntryValues: true`) is the holder's cumulative on-chain entry value in the outcome's quote token, formatted as a plain decimal string. `"0"` when the holding has no recorded entry (e.g. tokens acquired outside a fill, such as airdrops). Parse with `Decimal(s)` / `decimal.Decimal` / equivalent — don't use `float()` for accounting workflows.

> **Note:** the HL escrow precompile address for each token is excluded from the snapshot. Every spot token has a deterministic escrow at `0x32{:038x}` of its `token_id` (e.g. `0x32000000000000000000000000000000000001ca` for token 458) that holds the unsold/issuer supply — it isn't a real user position. Thus, it is dropped from each side's balances map.

</details>

<details>

<summary>Multiple Snapshots Response</summary>

**Format:** custom binary framing with per-snapshot zstd payloads.

**Binary structure:**

```
[count: 4 bytes LE][len1: 4 bytes LE][zstd_blob1][len2: 4 bytes LE][zstd_blob2]...
```

Each `zstd_blob` decompresses to one positional 4-element msgpack array with the `[snapshot_id, outcome_id, asset_id, balances]` shape shown above. Snapshots are returned in `(outcome_id, side_index)` order.

</details>

### Implementation Example

```python
import requests, struct, zstandard as zstd, msgpack, os
from decimal import Decimal

response = requests.post(
    "https://api.hydromancer.xyz/info",
    json={
        "type": "registeredOutcomesSnapshot",
        "outcome_ids": [3, 7],
        "includeEntryValues": True,  # omit for the legacy bare-size balances
    },
    headers={
        "Authorization": f"Bearer {os.environ['HYDROMANCER_API_KEY']}",
        "Content-Type": "application/json",
    },
)
body = response.content
fmt = response.headers.get("x-payload-format")

if fmt == "msgpack":
    snapshot = msgpack.unpackb(zstd.ZstdDecompressor().decompress(body), raw=False)
    print(snapshot)
else:
    # multi-zstd: count, then [len][blob] pairs
    count = struct.unpack("<I", body[:4])[0]
    offset = 4
    snapshots = []
    for _ in range(count):
        length = struct.unpack("<I", body[offset:offset + 4])[0]
        offset += 4
        blob = body[offset:offset + length]
        offset += length
        snapshots.append(
            msgpack.unpackb(zstd.ZstdDecompressor().decompress(blob), raw=False)
        )
    for snap in snapshots:
        # snap is a 4-element list: [snapshot_id, outcome_id, asset_id, balances_map].
        # With includeEntryValues, each balances value is a [size_str, entry_value_str]
        # 2-element array; without it, a bare size_str.
        # size uses sz_decimals=0 → integer lots; entry_value is a decimal string
        # in the outcome's quote token (parse with Decimal for accounting math).
        asset_id = snap[2]
        holders = {
            addr: {"size": int(pair[0]), "entry_value": Decimal(pair[1])}
            for addr, pair in snap[3].items()
        }
        print(asset_id, len(holders), "holders")
```

### Error Handling

* **400** — `asset_id` missing the `#` prefix, or the request exceeds 50 deduped asset\_ids.
* **500** — no matching snapshots in Redis, or the producer hasn't written any yet. Retry after polling `registeredOutcomesSnapshotTimestamp`.


# outcomeTemplatesOverview

List all registered permissionless HIP-4 outcome templates.

Returns every registered outcome template — the blueprints that permissionless venue deployers mint markets from via `registerStandaloneOutcomeFromTemplate`. One entry per template id, always the latest registration (templates can be re-registered with updated keyword types).

## POST Request

<table><thead><tr><th width="161">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"outcomeTemplatesOverview"</code></td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type": "outcomeTemplatesOverview"}'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={'type': 'outcomeTemplatesOverview'},
    headers={'Authorization': f"Bearer {os.environ['HYDROMANCER_API_KEY']}"},
)
print(response.json())
```

{% endtab %}
{% endtabs %}

## Response

<table><thead><tr><th width="211">Field</th><th width="160">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>templates</code></td><td>array</td><td>All templates, ordered by <code>id</code></td></tr><tr><td><code>templates[].id</code></td><td>string</td><td>Template id referenced by <code>registerStandaloneOutcomeFromTemplate</code>, e.g. <code>"binaryPrice"</code></td></tr><tr><td><code>templates[].keywordToHint</code></td><td>array of [string, string]</td><td>Placeholder slots and their type hints, e.g. <code>["perp", "hlPerp"]</code>, <code>["threshold", "uDecimal"]</code>, <code>["time", "dateTime"]</code></td></tr><tr><td><code>templates[].nameAndDescription</code></td><td>[string, string]</td><td>Market name and description text with <code>{keyword}</code> placeholders</td></tr><tr><td><code>templates[].role</code></td><td>object or string</td><td>Chain role, passed through verbatim: <code>{"standaloneOutcome": {"sideNames": [...]}}</code>, <code>"question"</code>, or <code>{"questionOutcome": {"parent": "..."}}</code></td></tr><tr><td><code>templates[].semanticRestriction</code></td><td>object, string, or null</td><td>Intended semantics of markets minted from this template, passed through verbatim. Markets contradicting it are malformed and slashable by validators. <code>null</code> on templates registered before the field existed</td></tr><tr><td><code>templates[].registeredAt</code></td><td>integer</td><td>Registration time of the latest version, ms since epoch</td></tr></tbody></table>

```json
{
  "templates": [
    {
      "id": "binaryPrice",
      "keywordToHint": [["perp", "hlPerp"], ["threshold", "uDecimal"], ["time", "dateTime"]],
      "nameAndDescription": [
        "{perp} above {threshold} at {time}?",
        "If the {perp} mark price at time of settlement is above {threshold} at {time}, Yes tokens pay out $1 each. Otherwise, No tokens pay out $1 each."
      ],
      "role": {"standaloneOutcome": {"sideNames": ["Yes", "No"]}},
      "registeredAt": 1785912700675
    },
    {
      "id": "sportsContestParticipant",
      "keywordToHint": [["participant", "string"]],
      "nameAndDescription": [
        "{participant}",
        "This outcome resolves to Yes if {participant} is the winner under the Contest Result or administrative-decision provisions of the parent question."
      ],
      "role": {"questionOutcome": {"parent": "sportsContestResult"}},
      "registeredAt": 1785919796967
    }
  ]
}
```


# outcomeVenuesOverview

List permissionless HIP-4 venues, their lifecycle, and sub-deployer permissions.

Returns every permissionless outcome venue with its activation lifecycle and currently effective sub-deployer permissions. Only executed actions are included — failed venue claims and failed grants never appear.

## POST Request

<table><thead><tr><th width="161">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"outcomeVenuesOverview"</code></td></tr><tr><td><code>isActive</code></td><td>boolean (optional)</td><td>Only active (<code>true</code>) or only deactivated (<code>false</code>) venues; absent returns both</td></tr><tr><td><code>limit</code></td><td>integer (optional)</td><td>Max venues returned, in <code>venueName</code> order. Default 20, maximum 100</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type": "outcomeVenuesOverview"}'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={'type': 'outcomeVenuesOverview'},
    headers={'Authorization': f"Bearer {os.environ['HYDROMANCER_API_KEY']}"},
)
print(response.json())
```

{% endtab %}
{% endtabs %}

## Response

<table><thead><tr><th width="240">Field</th><th width="150">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>venues</code></td><td>array</td><td>All venues, ordered by <code>venueName</code></td></tr><tr><td><code>venues[].venueName</code></td><td>string</td><td>Venue name claimed via <code>activateOutcomeDeployer</code> (2–4 lowercase ASCII letters)</td></tr><tr><td><code>venues[].deployer</code></td><td>string</td><td>Deployer address that owns the venue</td></tr><tr><td><code>venues[].activatedAt</code></td><td>integer or null</td><td>Latest successful activation, ms since epoch; <code>null</code> only if no activation was ever recorded for the venue</td></tr><tr><td><code>venues[].deactivatedAt</code></td><td>integer or null</td><td>Latest deactivation, ms since epoch; <code>null</code> if never deactivated</td></tr><tr><td><code>venues[].isActive</code></td><td>boolean</td><td><code>false</code> once a deactivation is more recent than the latest activation</td></tr><tr><td><code>venues[].subDeployers</code></td><td>array</td><td>Addresses holding currently effective permissions (grants minus later revocations)</td></tr><tr><td><code>venues[].subDeployers[].user</code></td><td>string</td><td>Sub-deployer address</td></tr><tr><td><code>venues[].subDeployers[].variants</code></td><td>array of string</td><td>Delegated action variants, e.g. <code>"registerStandaloneOutcomeFromTemplate"</code>, <code>"settleOutcome"</code>, <code>"settleQuestion"</code></td></tr></tbody></table>

```json
{
  "venues": [
    {
      "venueName": "out",
      "deployer": "0x0c46eb73fae2816f219fcf11f50d6d3c59b5819e",
      "activatedAt": 1787992549143,
      "deactivatedAt": null,
      "isActive": true,
      "subDeployers": [
        {
          "user": "0xf1923927d7d2847191fb7ef8b1a16028aa5ae754",
          "variants": [
            "registerAndAssociateNamedOutcomeFromTemplate",
            "registerQuestionFromTemplate",
            "registerStandaloneOutcomeFromTemplate",
            "settleOutcome",
            "settleQuestion"
          ]
        }
      ]
    }
  ]
}
```


# Vaults

**Retrieve vault summaries, user vault equities, and leading vault information.**

{% content-ref url="/pages/CIfLOHPP8TJ62O0nq3R1" %}
[vaultSummaries](/readme/rest-api/vaults/vaultsummaries)
{% endcontent-ref %}

{% content-ref url="/pages/Pafp3jOMa6vl1J72Onhf" %}
[userVaultEquities](/readme/rest-api/vaults/uservaultequities)
{% endcontent-ref %}

{% content-ref url="/pages/GIfmhm2IAiFBshRq0kIC" %}
[leadingVaults](/readme/rest-api/vaults/leadingvaults)
{% endcontent-ref %}


# vaultSummaries

Returns summary information for all vaults on the platform.

<table><thead><tr><th width="115">Field</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"vaultSummaries"</code></td></tr></tbody></table>

## Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "vaultSummaries"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'vaultSummaries'
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'vaultSummaries'
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field               | Type    | Description                         |
| ------------------- | ------- | ----------------------------------- |
| `name`              | string  | Vault name                          |
| `vaultAddress`      | string  | Vault Ethereum address              |
| `leader`            | string  | Vault leader address                |
| `tvl`               | string  | Total value locked                  |
| `isClosed`          | boolean | Whether the vault is closed         |
| `relationship`      | object  | Relationship type info              |
| `relationship.type` | string  | Relationship type (e.g. `"normal"`) |
| `createTimeMillis`  | int     | Vault creation timestamp (ms)       |

<details>

<summary>Response</summary>

```json
[
  {
    "name": "BlockChain OG",
    "vaultAddress": "0xb9612144b6783f43191c09a7e56333f805ae12dd",
    "leader": "0xc7c6cf1f1a5c5ccb025416b24bbfa678dc5922e7",
    "tvl": "101.0",
    "isClosed": false,
    "relationship": {
      "type": "normal"
    },
    "createTimeMillis": 1773644731666
  }
]
```

</details>


# userVaultEquities

Returns vault equity information for a specific user.

<table><thead><tr><th width="115">Field</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"userVaultEquities"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr></tbody></table>

## Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "userVaultEquities",
    "user": "0x0000000000000000000000000000000000000000"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'userVaultEquities',
        'user': '0x0000000000000000000000000000000000000000'
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'userVaultEquities',
    user: '0x0000000000000000000000000000000000000000'
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field          | Type   | Description                |
| -------------- | ------ | -------------------------- |
| `vaultAddress` | string | Vault Ethereum address     |
| `equity`       | string | User's equity in the vault |

<details>

<summary>Response</summary>

```json
[
  {
    "vaultAddress": "0xdfc24b077bc1425ad1dea75bcb6f8158e10df303",
    "equity": "742500.082809"
  }
]
```

</details>


# leadingVaults

Returns vaults that a user is leading.

<table><thead><tr><th width="115">Field</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"leadingVaults"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr></tbody></table>

## Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "leadingVaults",
    "user": "0x0000000000000000000000000000000000000000"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'leadingVaults',
        'user': '0x0000000000000000000000000000000000000000'
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'leadingVaults',
    user: '0x0000000000000000000000000000000000000000'
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response

Returns an array of vault objects for vaults the user is leading.


# Roles and agents

#### **Retrieving user's role**

Wallets on Hyperliquid can have different roles, such as agent wallets, subaccounts, vaults, and so on.

{% content-ref url="/pages/F4Va5CVFaWdDW0LDVyZr" %}
[userRole](/readme/rest-api/roles-and-agents/userrole)
{% endcontent-ref %}

#### **Retrieving user's API key names**

{% content-ref url="/pages/dizBn0zywwJ6SF2qIqLS" %}
[extraAgents](/readme/rest-api/roles-and-agents/extraagents)
{% endcontent-ref %}

#### **Retrieving multisigs by signer**

{% content-ref url="/pages/Sjc3uYygQLFiZv97V5cI" %}
[multisigsBySigner](/readme/rest-api/roles-and-agents/multisigsbysigner)
{% endcontent-ref %}


# userRole

Get the role of a user account.

Get the role of a user account.

## POST Request

<table><thead><tr><th width="161.9998779296875">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"userRole"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "userRole",
    "user": "0x0000000000000000000000000000000000000000"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'userRole',
        'user': '0x0000000000000000000000000000000000000000'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'userRole',
        user: '0x0000000000000000000000000000000000000000'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field  | Type   | Description                                             |
| ------ | ------ | ------------------------------------------------------- |
| `role` | string | Account role (e.g. `"user"`, `"subAccount"`, `"vault"`) |

<details>

<summary>Response</summary>

```json
{
    "role": "user"
}
```

</details>


# extraAgents

Get the extra agents (API wallets) for a user.

Get the extra agents (API wallets) for a user.

## POST Request

<table><thead><tr><th width="161.9998779296875">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"extraAgents"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "extraAgents",
    "user": "0x0000000000000000000000000000000000000000"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'extraAgents',
        'user': '0x0000000000000000000000000000000000000000'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'extraAgents',
        user: '0x0000000000000000000000000000000000000000'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field        | Type   | Description                      |
| ------------ | ------ | -------------------------------- |
| `name`       | string | Agent name                       |
| `address`    | string | Agent wallet address             |
| `validUntil` | int    | Expiry timestamp in milliseconds |

<details>

<summary>Response</summary>

```json
[
    {
        "name": "Agent 1",
        "address": "0x77deafccbb9ddbc5da3e8f5d066624265bdb2a74",
        "validUntil": 1775216111330
    },
    {
        "name": "Agent 2",
        "address": "0xfff6471954ad1bbe70f18e2fea9928fd7aba31ad",
        "validUntil": 1782653334723
    }
]
```

</details>


# multisigsBySigner

Get multisig accounts associated with an address.

Get all multisig accounts where an address is an authorized signer, plus the full signer set and threshold for each multisig account.

## POST Request

<table><thead><tr><th width="161.9998779296875">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"multiSigsBySigner"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "multiSigsBySigner",
    "user": "0x0000000000000000000000000000000000000000"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import os
import requests

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'multiSigsBySigner',
        'user': '0x0000000000000000000000000000000000000000'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'multiSigsBySigner',
        user: '0x0000000000000000000000000000000000000000'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field             | Type           | Description                                           |
| ----------------- | -------------- | ----------------------------------------------------- |
| `user`            | string         | Multisig account address                              |
| `authorizedUsers` | array\[string] | Addresses authorized to sign for the multisig account |
| `threshold`       | int            | Minimum number of authorized signatures required      |

<details>

<summary>Response</summary>

```json
[
  {
    "user": "0x1111111111111111111111111111111111111111",
    "authorizedUsers": [
      "0x0000000000000000000000000000000000000000",
      "0x2222222222222222222222222222222222222222"
    ],
    "threshold": 2
  }
]
```

</details>


# approvedBuilders

Returns the list of builder addresses a user has approved to charge builder fees.

<table><thead><tr><th width="115">Field</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"approvedBuilders"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>User Ethereum address (required)</td></tr></tbody></table>

## Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "approvedBuilders",
    "user": "0xd38809cc442fe4f10937c5988d2b723a15a89e5b"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'approvedBuilders',
        'user': '0xd38809cc442fe4f10937c5988d2b723a15a89e5b'
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'approvedBuilders',
    user: '0xd38809cc442fe4f10937c5988d2b723a15a89e5b'
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field  | Type  | Description                                                                       |
| ------ | ----- | --------------------------------------------------------------------------------- |
| (root) | array | List of approved builder Ethereum addresses (empty if the user has approved none) |

<details>

<summary>Response</summary>

```json
[
  "0xe966a12bf7b93838096e4519a684519ab22df618"
]
```

</details>


# Metadata

**Retrieve metadata about perpetual and spot markets, margin requirements, exchange status, available DEXes, and perp asset annotations and limits.**

{% content-ref url="/pages/hl0uXWbwFhkUVExFvgbj" %}
[meta](/readme/rest-api/metadata/meta)
{% endcontent-ref %}

{% content-ref url="/pages/w8F0Q7fQiYikI2579tpl" %}
[allPerpMetas](/readme/rest-api/metadata/allperpmetas)
{% endcontent-ref %}

{% content-ref url="/pages/CxeUQnY3fCBeiDGTUruE" %}
[spotMeta](/readme/rest-api/metadata/spotmeta)
{% endcontent-ref %}

{% content-ref url="/pages/Z5Kz1LIv1OLopA0Ie1wA" %}
[marginTable](/readme/rest-api/metadata/margintable)
{% endcontent-ref %}

{% content-ref url="/pages/44utyohbX9tVMMlYpWQN" %}
[exchangeStatus](/readme/rest-api/metadata/exchangestatus)
{% endcontent-ref %}

{% content-ref url="/pages/9eG7qcvh5edw8A8dctMW" %}
[perpDexs](/readme/rest-api/metadata/perpdexs)
{% endcontent-ref %}

{% content-ref url="/pages/jxPAmP2MhXvz0Nz77tqg" %}
[perpAnnotation](/readme/rest-api/metadata/perpannotation)
{% endcontent-ref %}

{% content-ref url="/pages/34mUlAQtcATPGFOqEhBE" %}
[perpCategories](/readme/rest-api/metadata/perpcategories)
{% endcontent-ref %}

{% content-ref url="/pages/M2OBDiDu098zowC43Bad" %}
[perpConciseAnnotations](/readme/rest-api/metadata/perpconciseannotations)
{% endcontent-ref %}

{% content-ref url="/pages/FLVprdA4MIoDtGyuiz1D" %}
[perpDexStatus](/readme/rest-api/metadata/perpdexstatus)
{% endcontent-ref %}

{% content-ref url="/pages/1zGdPp7VLKr0GtbSoIwK" %}
[perpDexLimits](/readme/rest-api/metadata/perpdexlimits)
{% endcontent-ref %}

{% content-ref url="/pages/NFhH2pVeGfI1N08YN3Sj" %}
[alignedQuoteTokenInfo](/readme/rest-api/metadata/alignedquotetokeninfo)
{% endcontent-ref %}


# meta

Returns metadata for perpetual markets including asset names, size decimals, and max leverage.

<table><thead><tr><th width="115">Field</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"meta"</code></td></tr><tr><td><code>dex</code></td><td>string</td><td>Perp DEX name (optional). Defaults to empty string for the first perp DEX.</td></tr></tbody></table>

## Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "meta"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'meta'
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'meta'
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field                     | Type    | Description                              |
| ------------------------- | ------- | ---------------------------------------- |
| `universe`                | array   | List of perpetual asset metadata objects |
| `universe[].name`         | string  | Asset symbol (e.g. `"BTC"`)              |
| `universe[].szDecimals`   | int     | Number of decimal places for size        |
| `universe[].maxLeverage`  | int     | Maximum allowed leverage                 |
| `universe[].onlyIsolated` | boolean | Whether only isolated margin is allowed  |

<details>

<summary>Response</summary>

```json
{
  "universe": [
    {
      "name": "BTC",
      "szDecimals": 5,
      "maxLeverage": 50,
      "onlyIsolated": false
    },
    {
      "name": "ETH",
      "szDecimals": 4,
      "maxLeverage": 50,
      "onlyIsolated": false
    }
  ]
}
```

</details>


# metaAndAssetCtxs

{% hint style="info" %}
This endpoint is currently **mainnet-only**.
{% endhint %}

Returns perpetual market metadata together with the per-asset trading context (prices, open interest, and 24h volume) in a single request.

<table><thead><tr><th width="115">Field</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"metaAndAssetCtxs"</code></td></tr><tr><td><code>dex</code></td><td>string</td><td>Perp DEX name (optional). Defaults to empty string for the first perp DEX; pass a builder-deployed DEX name for a HIP-3 market.</td></tr></tbody></table>

## Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept-Encoding: gzip" \
  -d '{
    "type": "metaAndAssetCtxs"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'metaAndAssetCtxs'
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'metaAndAssetCtxs'
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

The response can be large (\~50 KB for the full native universe). Send `Accept-Encoding: gzip` (or `br`) to receive it compressed.

***

## Response Fields

The response is a two-element array: `[meta, assetCtxs]`.

`meta` is identical to the [meta](/readme/rest-api/metadata/meta) endpoint (`universe`, `marginTables`, `collateralToken`).

`assetCtxs` is an array of per-asset context objects in the same order as `meta.universe`, so `assetCtxs[i]` corresponds to `meta.universe[i]`. An asset with no cached context is returned with null fields, keeping the array aligned with the universe.

| Field          | Type   | Description                                                              |
| -------------- | ------ | ------------------------------------------------------------------------ |
| `oraclePx`     | string | Oracle price                                                             |
| `markPx`       | string | Mark price                                                               |
| `midPx`        | string | Mid price; `null` when there is no book                                  |
| `impactPxs`    | array  | `[impact bid, impact ask]`; `null` when unavailable                      |
| `openInterest` | string | Open interest, in base units                                             |
| `dayNtlVlm`    | string | 24-hour notional volume (sum of price × size over the trailing 24 hours) |
| `dayBaseVlm`   | string | 24-hour base volume (sum of size over the trailing 24 hours)             |

<details>

<summary>Response</summary>

```json
[
  {
    "universe": [
      {
        "name": "BTC",
        "szDecimals": 5,
        "maxLeverage": 40,
        "onlyIsolated": false
      }
    ],
    "marginTables": [],
    "collateralToken": 0
  },
  [
    {
      "oraclePx": "63961",
      "markPx": "63970",
      "midPx": "63965.5",
      "impactPxs": ["63960", "63971"],
      "openInterest": "37318.54584",
      "dayNtlVlm": "1690219500.99709",
      "dayBaseVlm": "26703.40439"
    }
  ]
]
```

</details>


# spotMeta

Returns metadata for spot markets including token names, size decimals, and trading pair information.

<table><thead><tr><th width="115">Field</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"spotMeta"</code></td></tr></tbody></table>

## Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "spotMeta"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'spotMeta'
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'spotMeta'
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field                                         | Type    | Description                                         |
| --------------------------------------------- | ------- | --------------------------------------------------- |
| `universe`                                    | array   | List of spot market metadata objects                |
| `universe[].tokens`                           | array   | Token pair `[base, quote]` indices                  |
| `universe[].name`                             | string  | Market name (e.g. `"HYPE"`)                         |
| `universe[].index`                            | int     | Market index                                        |
| `universe[].isCanonical`                      | boolean | Whether this is the canonical spot market           |
| `tokens`                                      | array   | List of token metadata objects                      |
| `tokens[].name`                               | string  | Token symbol (e.g. `"USDC"`)                        |
| `tokens[].szDecimals`                         | int     | Number of decimal places for size                   |
| `tokens[].weiDecimals`                        | int     | Number of wei decimals                              |
| `tokens[].index`                              | int     | Token index                                         |
| `tokens[].tokenId`                            | string  | Token identifier                                    |
| `tokens[].isCanonical`                        | boolean | Whether this is the canonical token                 |
| `tokens[].evmContract`                        | object? | EVM contract details, `null` if not deployed on EVM |
| `tokens[].evmContract.address`                | string  | EVM contract address                                |
| `tokens[].evmContract.evm_extra_wei_decimals` | int     | Extra wei decimals for EVM conversion               |
| `tokens[].fullName`                           | string? | Full token name, `null` if not set                  |
| `tokens[].deployerTradingFeeShare`            | string  | Deployer's share of trading fees                    |

<details>

<summary>Response</summary>

```json
{
  "universe": [
    {
      "tokens": [0, 1],
      "name": "PURR/USDC",
      "index": 0,
      "isCanonical": true
    }
  ],
  "tokens": [
    {
      "name": "USDC",
      "szDecimals": 8,
      "weiDecimals": 8,
      "index": 0,
      "tokenId": "0x6d1e7cde53ba9467b783cb7c530ce054",
      "isCanonical": true,
      "evmContract": {
        "address": "0x6b9e773128f453f5c2c60935ee2de2cbc5390a24",
        "evm_extra_wei_decimals": -2
      },
      "fullName": null,
      "deployerTradingFeeShare": "0.0"
    },
    {
      "name": "PURR",
      "szDecimals": 0,
      "weiDecimals": 5,
      "index": 1,
      "tokenId": "0xc1fb593aeffbeb02f85e0308e9956a90",
      "isCanonical": true,
      "evmContract": {
        "address": "0x9b498c3c8a0b8cd8ba1d9851d40d186f1872b44e",
        "evm_extra_wei_decimals": 13
      },
      "fullName": null,
      "deployerTradingFeeShare": "0.0"
    }
  ]
}
```

</details>


# marginTable

Returns the margin requirements table for a specific perpetual asset by index.

<table><thead><tr><th width="115">Field</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"marginTable"</code></td></tr><tr><td><code>id</code></td><td>int</td><td>Asset index (required)</td></tr></tbody></table>

## Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "marginTable",
    "id": 1
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'marginTable',
        'id': 1
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'marginTable',
    id: 1
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field                       | Type   | Description                                        |
| --------------------------- | ------ | -------------------------------------------------- |
| `description`               | string | Description of the margin table                    |
| `marginTiers`               | array  | List of margin tier objects                        |
| `marginTiers[].lowerBound`  | string | Lower bound of the notional position for this tier |
| `marginTiers[].maxLeverage` | int    | Maximum leverage allowed at this tier              |

<details>

<summary>Response</summary>

```json
{
  "description": "",
  "marginTiers": [
    {
      "lowerBound": "0.0",
      "maxLeverage": 1
    }
  ]
}
```

</details>


# perpDexs

Returns the list of all available perpetual DEXes.

<table><thead><tr><th width="115">Field</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"perpDexs"</code></td></tr></tbody></table>

## Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "perpDexs"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'perpDexs'
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'perpDexs'
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field                                | Type    | Description                                                                                 |
| ------------------------------------ | ------- | ------------------------------------------------------------------------------------------- |
| (root)                               | array   | Array where index 0 is `null` (the native/first DEX) and subsequent entries are DEX objects |
| `[n].name`                           | string  | Short DEX identifier (e.g. `"xyz"`)                                                         |
| `[n].fullName`                       | string  | Full DEX display name                                                                       |
| `[n].deployer`                       | string  | Deployer Ethereum address                                                                   |
| `[n].oracleUpdater`                  | string? | Oracle updater address, `null` if not set                                                   |
| `[n].feeRecipient`                   | string  | Fee recipient address                                                                       |
| `[n].assetToStreamingOiCap`          | array   | Array of `[asset, cap]` pairs for streaming open interest caps                              |
| `[n].subDeployers`                   | array   | Array of `[permission, [addresses]]` pairs                                                  |
| `[n].deployerFeeScale`               | string  | Deployer fee scale factor                                                                   |
| `[n].lastDeployerFeeScaleChangeTime` | string  | Timestamp of last fee scale change                                                          |
| `[n].assetToFundingMultiplier`       | array   | Array of `[asset, multiplier]` pairs                                                        |
| `[n].assetToFundingInterestRate`     | array   | Array of `[asset, rate]` pairs for custom funding interest rates                            |

<details>

<summary>Response</summary>

```json
[
  null,
  {
    "name": "xyz",
    "fullName": "XYZ",
    "deployer": "0x88806a71d74ad0a510b350545c9ae490912f0888",
    "oracleUpdater": null,
    "feeRecipient": "0x9cd0a696c7cbb9d44de99268194cb08e5684e5fe",
    "assetToStreamingOiCap": [
      ["xyz:NVDA", "250000000.0"],
      ["xyz:GOLD", "500000000.0"]
    ],
    "subDeployers": [
      ["registerAsset", ["0x7d16f116d252db609c56d27d6c9605eb03e16657"]],
      ["setOracle", ["0x1234567890545d1df9ee64b35fdd16966e08acec"]]
    ],
    "deployerFeeScale": "1.0",
    "lastDeployerFeeScaleChangeTime": "1970-01-01T00:00:00",
    "assetToFundingMultiplier": [
      ["xyz:NVDA", "0.5"],
      ["xyz:GOLD", "0.5"]
    ],
    "assetToFundingInterestRate": [
      ["xyz:EUR", "0.0"],
      ["xyz:JPY", "0.0"]
    ]
  }
]
```

</details>


# allPerpMetas

Returns the perpetuals metadata — universe definitions and margin tables — for **every** perp DEX in a single response. The first element is the native Hyperliquid perp DEX; subsequent elements are builder-deployed (HIP-3) perp DEXes, in the same order as [perpDexs](/readme/rest-api/metadata/perpdexs).

For the metadata of a single DEX, use [meta](/readme/rest-api/metadata/meta) with the `dex` field.

{% hint style="info" %}
This endpoint returns the full universe and margin tables across all DEXes and is correspondingly heavier — it costs **10 points** per request (vs 2 for `meta`). See [Rate limits and user limits](/readme/rest-api/rate-limits-and-user-limits).
{% endhint %}

<table><thead><tr><th width="115">Field</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"allPerpMetas"</code></td></tr></tbody></table>

## Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "allPerpMetas"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'allPerpMetas'
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'allPerpMetas'
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field                               | Type   | Description                                                                                                       |
| ----------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------- |
| (root)                              | array  | One entry per perp DEX. Index 0 is the native Hyperliquid perp DEX; later entries are builder-deployed perp DEXes |
| `[n].universe`                      | array  | List of perp asset definitions for this DEX                                                                       |
| `[n].universe[].name`               | string | Asset name (with DEX prefix for builder-deployed perps)                                                           |
| `[n].universe[].szDecimals`         | int    | Number of decimals for the size field                                                                             |
| `[n].universe[].maxLeverage`        | int    | Maximum leverage for the asset                                                                                    |
| `[n].universe[].marginTableId`      | int    | Margin table id referenced in `marginTables`                                                                      |
| `[n].universe[].isDelisted`         | bool?  | Present and `true` if the asset is delisted                                                                       |
| `[n].marginTables`                  | array  | List of `[marginTableId, marginTable]` pairs for this DEX                                                         |
| `[n].marginTables[][0]`             | int    | Margin table id                                                                                                   |
| `[n].marginTables[][1].description` | string | Description of the margin table                                                                                   |
| `[n].marginTables[][1].marginTiers` | array  | List of `{ lowerBound, maxLeverage }` tiers                                                                       |
| `[n].collateralToken`               | int    | Token index used as collateral for this DEX                                                                       |

<details>

<summary>Response (trimmed)</summary>

```json
[
  {
    "universe": [
      { "szDecimals": 5, "name": "BTC", "maxLeverage": 40, "marginTableId": 56 },
      { "szDecimals": 4, "name": "ETH", "maxLeverage": 25, "marginTableId": 55 }
    ],
    "marginTables": [
      [
        50,
        {
          "description": "",
          "marginTiers": [
            { "lowerBound": "0.0", "maxLeverage": 50 }
          ]
        }
      ]
    ],
    "collateralToken": 0
  }
]
```

</details>


# perpAnnotation

Returns the human-readable annotation (category, description, and keywords) for a single perpetual asset.

<table><thead><tr><th width="115">Field</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"perpAnnotation"</code></td></tr><tr><td><code>coin</code></td><td>string</td><td>Perp asset name, including the DEX prefix for builder-deployed perps (e.g. <code>"xyz:TSLA"</code>). Required. Only perp assets are accepted — spot and outcome markets are rejected.</td></tr></tbody></table>

## Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "perpAnnotation",
    "coin": "xyz:TSLA"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'perpAnnotation',
        'coin': 'xyz:TSLA'
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'perpAnnotation',
    coin: 'xyz:TSLA'
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response Fields

Returns `null` if the asset has no annotation.

| Field         | Type   | Description                                                                        |
| ------------- | ------ | ---------------------------------------------------------------------------------- |
| `category`    | string | Asset category (e.g. `"stocks"`, `"crypto"`, `"commodities"`, `"indices"`, `"FX"`) |
| `description` | string | Human-readable description of the underlying asset                                 |
| `displayName` | string | Display name for the asset                                                         |
| `keywords`    | array? | Optional list of search keywords                                                   |

<details>

<summary>Response</summary>

```json
{
  "category": "stocks",
  "description": "TSLA tracks the value of 1 share of common stock in Tesla, Inc. Tesla designs and manufactures electric vehicles, battery energy storage systems, and solar products. The company is a global leader in EV production and autonomous driving technology.",
  "displayName": "TSLA",
  "keywords": ["tesla", "ev"]
}
```

</details>


# batchPerpAnnotations

Get human-readable annotations for multiple perpetual assets in a single request.

Returns the human-readable annotation (category, description, display name, and keywords) for multiple perpetual assets in a single request. This is the batched form of [perpAnnotation](/readme/rest-api/metadata/perpannotation) — results are returned as an object keyed by coin.

## POST Request

<table><thead><tr><th width="163">Field</th><th width="135">Type</th><th width="471">Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"batchPerpAnnotations"</code></td></tr><tr><td><code>coins</code></td><td>array</td><td>Array of perp asset names, including the DEX prefix for builder-deployed perps (e.g. <code>"xyz:TSLA"</code>). Required, non-empty. Only perp assets are accepted — spot and outcome markets are rejected. Duplicates are de-duplicated.</td></tr></tbody></table>

### Limits

You can query up to **100 coins** at once. Requests exceeding this are rejected with a 400 error.

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "batchPerpAnnotations",
    "coins": ["xyz:TSLA", "xyz:NVDA"]
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'batchPerpAnnotations',
        'coins': ['xyz:TSLA', 'xyz:NVDA']
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'batchPerpAnnotations',
    coins: ['xyz:TSLA', 'xyz:NVDA']
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field          | Type   | Description                                                                                                                                                                                                                               |
| -------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `annotations`  | object | Map of `coin` → annotation payload. Each value is the same object returned by [perpAnnotation](/readme/rest-api/metadata/perpannotation) (`category`, `description`, `displayName`, `keywords`), or `null` if the perp has no annotation. |
| `failed_coins` | array  | Coins whose underlying request failed (transport/HTTP error). Distinct from a successful `null` annotation.                                                                                                                               |

A coin with no annotation appears in `annotations` with a `null` value — it is **not** a failure. Only coins whose node request errored land in `failed_coins`.

<details>

<summary>Response</summary>

```json
{
  "annotations": {
    "xyz:TSLA": {
      "category": "stocks",
      "description": "TSLA tracks the value of 1 share of common stock in Tesla, Inc.",
      "displayName": "TSLA",
      "keywords": ["tesla", "ev"]
    },
    "xyz:NVDA": {
      "category": "stocks",
      "description": "NVDA tracks the value of 1 share of common stock in NVIDIA Corporation.",
      "displayName": "NVDA",
      "keywords": ["nvidia", "gpu", "ai"]
    }
  },
  "failed_coins": []
}
```

</details>


# perpCategories

Returns the category for every annotated perpetual asset as a list of `[coin, category]` pairs.

<table><thead><tr><th width="115">Field</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"perpCategories"</code></td></tr></tbody></table>

## Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "perpCategories"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'perpCategories'
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'perpCategories'
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field    | Type   | Description                                                   |
| -------- | ------ | ------------------------------------------------------------- |
| (root)   | array  | Array of `[coin, category]` pairs                             |
| `[n][0]` | string | Perp asset name (with DEX prefix for builder-deployed perps)  |
| `[n][1]` | string | Asset category (e.g. `"crypto"`, `"stocks"`, `"commodities"`) |

<details>

<summary>Response</summary>

```json
[
  ["flx:BTC", "crypto"],
  ["flx:COIN", "stocks"],
  ["flx:COPPER", "commodities"]
]
```

</details>


# perpConciseAnnotations

Returns concise annotations for every annotated perpetual asset as a list of `[coin, annotation]` pairs. Each annotation carries the category plus optional display name and keywords — the description is omitted (use [perpAnnotation](/readme/rest-api/metadata/perpannotation) for the full description of a single asset).

<table><thead><tr><th width="115">Field</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"perpConciseAnnotations"</code></td></tr></tbody></table>

## Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "perpConciseAnnotations"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'perpConciseAnnotations'
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'perpConciseAnnotations'
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field                | Type    | Description                                                  |
| -------------------- | ------- | ------------------------------------------------------------ |
| (root)               | array   | Array of `[coin, annotation]` pairs                          |
| `[n][0]`             | string  | Perp asset name (with DEX prefix for builder-deployed perps) |
| `[n][1].category`    | string  | Asset category                                               |
| `[n][1].displayName` | string? | Optional display name                                        |
| `[n][1].keywords`    | array?  | Optional list of search keywords                             |

<details>

<summary>Response</summary>

```json
[
  ["flx:BTC", { "category": "crypto" }],
  ["flx:COIN", { "category": "stocks" }],
  ["para:AVGO", { "category": "stocks", "keywords": ["broadcom", "ai"] }],
  ["para:BTCD", { "category": "crypto", "displayName": "BTC.D", "keywords": ["dominance", "index"] }]
]
```

</details>


# perpDexStatus

Returns the status of a builder-deployed (HIP-3) perp DEX, including its total net deposits.

<table><thead><tr><th width="115">Field</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"perpDexStatus"</code></td></tr><tr><td><code>dex</code></td><td>string</td><td>Perp DEX name (e.g. <code>"xyz"</code>). Required. An empty string selects the native Hyperliquid perp DEX.</td></tr></tbody></table>

## Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "perpDexStatus",
    "dex": "xyz"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'perpDexStatus',
        'dex': 'xyz'
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'perpDexStatus',
    dex: 'xyz'
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field             | Type   | Description                     |
| ----------------- | ------ | ------------------------------- |
| `totalNetDeposit` | string | Total net deposits into the DEX |

<details>

<summary>Response</summary>

```json
{
  "totalNetDeposit": "825489811.4041969776"
}
```

</details>


# perpDexLimits

Returns the open-interest and transfer limits for a builder-deployed (HIP-3) perp DEX, including the per-asset open-interest caps.

<table><thead><tr><th width="115">Field</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"perpDexLimits"</code></td></tr><tr><td><code>dex</code></td><td>string</td><td>Perp DEX name (e.g. <code>"xyz"</code>). Required. An empty string selects the native Hyperliquid perp DEX.</td></tr></tbody></table>

## Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "perpDexLimits",
    "dex": "xyz"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'perpDexLimits',
        'dex': 'xyz'
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'perpDexLimits',
    dex: 'xyz'
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response Fields

Returns `null` for a DEX that has no configured limits.

| Field            | Type   | Description                                                           |
| ---------------- | ------ | --------------------------------------------------------------------- |
| `totalOiCap`     | string | Total open-interest cap across the DEX                                |
| `oiSzCapPerPerp` | string | Open-interest size cap per perp                                       |
| `maxTransferNtl` | string | Maximum transfer notional                                             |
| `coinToOiCap`    | array  | Array of `[coin, oiCap]` pairs giving the per-asset open-interest cap |

<details>

<summary>Response (trimmed)</summary>

```json
{
  "totalOiCap": "6000000000.0",
  "oiSzCapPerPerp": "20000000000.0",
  "maxTransferNtl": "2000000000.0",
  "coinToOiCap": [
    ["xyz:AAPL", "100000000.0"],
    ["xyz:ALUMINIUM", "25000000.0"]
  ]
}
```

</details>


# alignedQuoteTokenInfo

Returns alignment and yield info for a quote token (e.g. USDH) by its token index. Returns `null` if the token is not an aligned quote token.

<table><thead><tr><th width="115">Field</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"alignedQuoteTokenInfo"</code></td></tr><tr><td><code>token</code></td><td>int</td><td>Token index (required)</td></tr></tbody></table>

## Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "alignedQuoteTokenInfo",
    "token": 360
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'alignedQuoteTokenInfo',
        'token': 360
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'alignedQuoteTokenInfo',
    token: 360
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response Fields

Returns `null` if the token is not an aligned quote token.

| Field              | Type   | Description                                                  |
| ------------------ | ------ | ------------------------------------------------------------ |
| `isAligned`        | bool   | Whether the token is currently aligned                       |
| `firstAlignedTime` | int    | Timestamp (ms) the token first became aligned                |
| `evmMintedSupply`  | string | Supply minted on the EVM                                     |
| `dailyAmountOwed`  | array  | Array of `[date, amount]` pairs giving the daily amount owed |
| `predictedRate`    | string | Predicted yield rate                                         |

<details>

<summary>Response (trimmed)</summary>

```json
{
  "isAligned": false,
  "firstAlignedTime": 1763817013608,
  "evmMintedSupply": "57184006.2899999991",
  "dailyAmountOwed": [
    ["2026-04-12", "4016.91339453"],
    ["2026-04-13", "4039.92786086"]
  ],
  "predictedRate": "0.03096284"
}
```

</details>


# exchangeStatus

Returns the current status of the exchange.

<table><thead><tr><th width="115">Field</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"exchangeStatus"</code></td></tr></tbody></table>

## Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "exchangeStatus"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'exchangeStatus'
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'exchangeStatus'
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field             | Type    | Description                                         |
| ----------------- | ------- | --------------------------------------------------- |
| `specialStatuses` | object? | Special status flags, `null` under normal operation |
| `time`            | int     | Current exchange timestamp (ms)                     |

<details>

<summary>Response</summary>

```json
{
  "specialStatuses": null,
  "time": 1773647974412
}
```

</details>


# Token deployment

#### **Retrieve spot deploy state**

{% content-ref url="/pages/TJtNyimvXITLL6arOeWI" %}
[spotDeployState](/readme/rest-api/token-deployment/spotdeploystate)
{% endcontent-ref %}

#### **Retrieve perp deploy auction status**

{% content-ref url="/pages/zrsmMq6PlXlbx277ixAY" %}
[perpDeployAuctionStatus](/readme/rest-api/token-deployment/perpdeployauctionstatus)
{% endcontent-ref %}


# spotDeployState

Get the spot deploy state for a user.

Get the spot deploy state for a user.

## POST Request

<table><thead><tr><th width="161.9998779296875">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"spotDeployState"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "spotDeployState",
    "user": "0x0000000000000000000000000000000000000000"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'spotDeployState',
        'user': '0x0000000000000000000000000000000000000000'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'spotDeployState',
        user: '0x0000000000000000000000000000000000000000'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field                                   | Type    | Description                               |
| --------------------------------------- | ------- | ----------------------------------------- |
| `states`                                | array   | List of spot deploy states                |
| `states[].token`                        | int     | Token index                               |
| `states[].spec`                         | object  | Token spec                                |
| `states[].spec.name`                    | string  | Token name                                |
| `states[].spec.szDecimals`              | int     | Size decimals                             |
| `states[].spec.weiDecimals`             | int     | Wei decimals                              |
| `states[].fullName`                     | string  | Full token name                           |
| `states[].spots`                        | array   | Spot pair indices                         |
| `states[].maxSupply`                    | int     | Maximum supply                            |
| `states[].hyperliquidityGenesisBalance` | string  | Hyperliquidity genesis balance            |
| `states[].totalGenesisBalanceWei`       | string  | Total genesis balance in wei              |
| `states[].userGenesisBalances`          | array   | List of \[address, balance] pairs         |
| `states[].existingTokenGenesisBalances` | array   | List of \[tokenIndex, balance] pairs      |
| `gasAuction`                            | object  | Gas auction state                         |
| `gasAuction.startTimeSeconds`           | int     | Auction start time (unix seconds)         |
| `gasAuction.durationSeconds`            | int     | Auction duration in seconds               |
| `gasAuction.startGas`                   | string  | Starting gas price                        |
| `gasAuction.currentGas`                 | string? | Current gas price (null if auction ended) |
| `gasAuction.endGas`                     | string  | Ending gas price                          |

<details>

<summary>Response (truncated)</summary>

```json
{
    "states": [
        {
            "token": 150,
            "spec": {
                "name": "HYPE",
                "szDecimals": 2,
                "weiDecimals": 8
            },
            "fullName": "Hyperliquid",
            "spots": [107],
            "maxSupply": 1000000000,
            "hyperliquidityGenesisBalance": "120000",
            "totalGenesisBalanceWei": "100000000000000000",
            "userGenesisBalances": [],
            "existingTokenGenesisBalances": []
        }
    ],
    "gasAuction": {
        "startTimeSeconds": 1733929200,
        "durationSeconds": 111600,
        "startGas": "181305.90046",
        "currentGas": null,
        "endGas": "181291.247358"
    }
}
```

</details>


# perpDeployAuctionStatus

Get the current perp deploy auction status.

Get the current perp deploy auction status.

## POST Request

<table><thead><tr><th width="161.9998779296875">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"perpDeployAuctionStatus"</code></td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "perpDeployAuctionStatus"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'perpDeployAuctionStatus'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'perpDeployAuctionStatus'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field              | Type    | Description                                     |
| ------------------ | ------- | ----------------------------------------------- |
| `startTimeSeconds` | int     | Auction start time (unix seconds)               |
| `durationSeconds`  | int     | Auction duration in seconds                     |
| `startGas`         | string  | Starting gas price                              |
| `currentGas`       | string? | Current gas price (null if auction ended)       |
| `endGas`           | string? | Ending gas price (null if auction still active) |

<details>

<summary>Response</summary>

```json
{
    "startTimeSeconds": 1773658800,
    "durationSeconds": 111600,
    "startGas": "1000.0",
    "currentGas": "988.88346326",
    "endGas": null
}
```

</details>


# spotPairDeployAuctionStatus

Returns the current status of the spot trading-pair deploy auction, including timing and gas pricing.

<table><thead><tr><th width="115">Field</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"spotPairDeployAuctionStatus"</code></td></tr></tbody></table>

## Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "spotPairDeployAuctionStatus"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'spotPairDeployAuctionStatus'
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'spotPairDeployAuctionStatus'
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field              | Type    | Description                                                   |
| ------------------ | ------- | ------------------------------------------------------------- |
| `startTimeSeconds` | int     | Auction start time (unix seconds)                             |
| `durationSeconds`  | int     | Auction duration in seconds                                   |
| `startGas`         | string  | Gas price at the start of the auction                         |
| `currentGas`       | string  | Current gas price                                             |
| `endGas`           | string? | Gas price at the end of the auction, `null` while in progress |

<details>

<summary>Response</summary>

```json
{
  "startTimeSeconds": 1780354800,
  "durationSeconds": 111600,
  "startGas": "500.0",
  "currentGas": "500.0",
  "endGas": null
}
```

</details>


# Borrow / Lend

**Retrieve borrow/lend reserve state and per-user borrow/lend positions.**

{% content-ref url="/pages/gOOz2jhJ7rEYWrh4U5g5" %}
[allBorrowLendReserveStates](/readme/rest-api/borrow-lend/allborrowlendreservestates)
{% endcontent-ref %}

{% content-ref url="/pages/QXPzQkKLVY6RqAkTTrk0" %}
[borrowLendReserveState](/readme/rest-api/borrow-lend/borrowlendreservestate)
{% endcontent-ref %}

{% content-ref url="/pages/xdFfIvKEPJavJmKjME2F" %}
[borrowLendUserState](/readme/rest-api/borrow-lend/borrowlenduserstate)
{% endcontent-ref %}


# allBorrowLendReserveStates

Returns the borrow/lend reserve state for every token reserve as a list of `[tokenIndex, reserveState]` pairs.

<table><thead><tr><th width="115">Field</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"allBorrowLendReserveStates"</code></td></tr></tbody></table>

## Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "allBorrowLendReserveStates"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'allBorrowLendReserveStates'
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'allBorrowLendReserveStates'
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field                     | Type   | Description                                 |
| ------------------------- | ------ | ------------------------------------------- |
| (root)                    | array  | Array of `[tokenIndex, reserveState]` pairs |
| `[n][0]`                  | int    | Token index                                 |
| `[n][1].borrowYearlyRate` | string | Annualized borrow rate                      |
| `[n][1].supplyYearlyRate` | string | Annualized supply rate                      |
| `[n][1].balance`          | string | Reserve balance                             |
| `[n][1].utilization`      | string | Utilization ratio (borrowed / supplied)     |
| `[n][1].oraclePx`         | string | Oracle price of the token                   |
| `[n][1].ltv`              | string | Loan-to-value ratio                         |
| `[n][1].totalSupplied`    | string | Total supplied to the reserve               |
| `[n][1].totalBorrowed`    | string | Total borrowed from the reserve             |

<details>

<summary>Response (trimmed)</summary>

```json
[
  [
    0,
    {
      "borrowYearlyRate": "0.05",
      "supplyYearlyRate": "0.0141878137",
      "balance": "75035169.4813607037",
      "utilization": "0.3152847491",
      "oraclePx": "1.0",
      "ltv": "0.0",
      "totalSupplied": "109585941.8306342065",
      "totalBorrowed": "34550776.179527849"
    }
  ]
]
```

</details>


# borrowLendReserveState

Returns the borrow/lend reserve state for a single token by its token index.

<table><thead><tr><th width="115">Field</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"borrowLendReserveState"</code></td></tr><tr><td><code>token</code></td><td>int</td><td>Token index (required)</td></tr></tbody></table>

## Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "borrowLendReserveState",
    "token": 0
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'borrowLendReserveState',
        'token': 0
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'borrowLendReserveState',
    token: 0
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field              | Type   | Description                             |
| ------------------ | ------ | --------------------------------------- |
| `borrowYearlyRate` | string | Annualized borrow rate                  |
| `supplyYearlyRate` | string | Annualized supply rate                  |
| `balance`          | string | Reserve balance                         |
| `utilization`      | string | Utilization ratio (borrowed / supplied) |
| `oraclePx`         | string | Oracle price of the token               |
| `ltv`              | string | Loan-to-value ratio                     |
| `totalSupplied`    | string | Total supplied to the reserve           |
| `totalBorrowed`    | string | Total borrowed from the reserve         |

<details>

<summary>Response</summary>

```json
{
  "borrowYearlyRate": "0.05",
  "supplyYearlyRate": "0.0141878137",
  "balance": "75035169.4813607037",
  "utilization": "0.3152847491",
  "oraclePx": "1.0",
  "ltv": "0.0",
  "totalSupplied": "109585941.8306342065",
  "totalBorrowed": "34550776.179527849"
}
```

</details>


# borrowLendUserState

Returns a user's borrow/lend positions and account health.

<table><thead><tr><th width="115">Field</th><th width="177">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"borrowLendUserState"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>User Ethereum address (required)</td></tr></tbody></table>

## Request

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "borrowLendUserState",
    "user": "0xd38809cc442fe4f10937c5988d2b723a15a89e5b"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os
import json

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'borrowLendUserState',
        'user': '0xd38809cc442fe4f10937c5988d2b723a15a89e5b'
    },
    headers={
        'Authorization': f'Bearer {os.environ["HYDROMANCER_API_KEY"]}',
        'Content-Type': 'application/json'
    }
)
print(json.dumps(response.json(), indent=2))
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post(
  'https://api.hydromancer.xyz/info',
  {
    type: 'borrowLendUserState',
    user: '0xd38809cc442fe4f10937c5988d2b723a15a89e5b'
  },
  {
    headers: {
      'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
      'Content-Type': 'application/json'
    }
  }
);

console.log(JSON.stringify(response.data, null, 2));
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field          | Type    | Description                                                                                               |
| -------------- | ------- | --------------------------------------------------------------------------------------------------------- |
| `tokenToState` | array   | Array of `[tokenIndex, state]` pairs describing the user's per-token borrow/lend position (empty if none) |
| `health`       | string  | Account health status (e.g. `"healthy"`)                                                                  |
| `healthFactor` | string? | Account health factor, `null` when the user has no borrow/lend position                                   |

<details>

<summary>Response</summary>

```json
{
  "tokenToState": [],
  "health": "healthy",
  "healthFactor": null
}
```

</details>


# Staking

#### **Retrieve staking overview (all validators)**

{% content-ref url="/pages/5gIvk65W9247e8zuRCP3" %}
[stakingOverview](/readme/rest-api/staking/stakingoverview)
{% endcontent-ref %}

#### **Retrieve staker list for a validator**

{% content-ref url="/pages/9mTJ95ETVdfQlFJZYny4" %}
[stakingValidatorStakers](/readme/rest-api/staking/stakingvalidatorstakers)
{% endcontent-ref %}

#### **Retrieve historical staking events**

{% content-ref url="/pages/nLIUwUS6L7iUf03HSXC4" %}
[stakingEvents](/readme/rest-api/staking/stakingevents)
{% endcontent-ref %}

#### **Retrieve global staking summary (per-user balances)**

{% content-ref url="/pages/zyQPzQv8XlDa3JVQAqbU" %}
[globalStakingSummary](/readme/rest-api/staking/globalstakingsummary)
{% endcontent-ref %}


# stakingOverview

Get a summary of all validators and their staking stats.

### Overview

Returns the staking overview from the latest ABCI snapshot. Includes all validators with their total delegated amounts, effective stake, commission, and jailed status. Per-staker detail is omitted for performance -- use `stakingValidatorStakers` for that.

### Request

* **Endpoint**: `POST /info`

```json
{
  "type": "stakingOverview"
}
```

### Response

```json
{
  "timestamp_ms": 1776010486341,
  "total_staked": "435244277.12345678",
  "validator_count": 30,
  "delegator_count": 49271,
  "validators": [
    {
      "address": "0x43e9abea1910387c4292bca4b94de81462f8a251",
      "name": "Hyper Foundation",
      "description": "Official Hyper Foundation validator",
      "commission_bps": 0,
      "total_delegated": "241305342.6257348",
      "effective_stake": "241305342.6257348",
      "staker_count": 12345,
      "is_jailed": false
    }
  ]
}
```

### Response Fields

| Field             | Type   | Description                                              |
| ----------------- | ------ | -------------------------------------------------------- |
| `timestamp_ms`    | number | Snapshot timestamp in milliseconds                       |
| `total_staked`    | string | Total HYPE staked across all validators (decimal string) |
| `validator_count` | number | Number of active validators                              |
| `delegator_count` | number | Unique delegator count across all validators             |
| `validators`      | array  | Validator list, sorted by `total_delegated` descending   |

#### Validator Fields

| Field             | Type           | Description                                             |
| ----------------- | -------------- | ------------------------------------------------------- |
| `address`         | string         | Validator address                                       |
| `name`            | string         | Validator display name                                  |
| `description`     | string         | Validator description                                   |
| `commission_bps`  | number         | Commission in basis points (e.g. 400 = 4%)              |
| `total_delegated` | string         | Total HYPE delegated to this validator (decimal string) |
| `effective_stake` | string \| null | Effective stake used for consensus                      |
| `staker_count`    | number         | Number of delegators to this validator                  |
| `is_jailed`       | boolean        | Whether the validator is currently jailed               |


# stakingValidatorStakers

Get the full staker list for a specific validator.

### Overview

Returns the list of all delegators for a specific validator, sorted by delegation amount descending. Includes the validator's metadata and the snapshot timestamp.

### Request

* **Endpoint**: `POST /info`

```json
{
  "type": "stakingValidatorStakers",
  "validator": "0x000000000056f99d36b6f2e0c51fd41496bbacb8"
}
```

| Parameter   | Type   | Required | Description                          |
| ----------- | ------ | -------- | ------------------------------------ |
| `validator` | string | Yes      | Validator address (case-insensitive) |

### Response

```json
{
  "timestamp_ms": 1776010486341,
  "address": "0x000000000056f99d36b6f2e0c51fd41496bbacb8",
  "name": "ValiDAO",
  "description": "The People's Validator...",
  "commission_bps": 400,
  "total_delegated": "10057.57964234",
  "effective_stake": "10057.57964234",
  "staker_count": 1234,
  "is_jailed": false,
  "stakers": [
    {
      "address": "0xabc123...",
      "amount": "5000.12345678"
    }
  ]
}
```

### Response Fields

Includes all fields from `stakingOverview` validator objects, plus:

| Field               | Type   | Description                                     |
| ------------------- | ------ | ----------------------------------------------- |
| `stakers`           | array  | List of delegators, sorted by amount descending |
| `stakers[].address` | string | Delegator wallet address                        |
| `stakers[].amount`  | string | Delegated HYPE amount (decimal string)          |

### Errors

| Status | Condition                                             |
| ------ | ----------------------------------------------------- |
| 400    | Missing `validator` field                             |
| 404    | Validator not found or staking snapshot not available |


# validatorAprHistory

Query a validator's weekly net staking APR and rewards distributed to delegators.

Returns a validator's weekly delegator APR — both **net** (what delegators earn, after the validator's commission) and **gross** (the validator's pre-commission rate) — one entry per week (Monday-start, UTC), newest first. Both are simple (non-compounded) annualized rates expressed as raw fractions (`0.182` = 18.2%):

* `netApr` = `sum(weekly delegation rewards) / sum(weekly staked) × 365`
* `grossApr` = `(delegation + commission rewards) / sum(weekly staked) × 365` — the implied fee for the week is `1 − netApr/grossApr`

`totalDelegatorRewards` is the net HYPE distributed to delegators that week.

Values are recomputed once per day, shortly after the midnight-UTC reward distribution; the most recent (in-progress) week is partial until it closes.

**Data availability:** From 1 August 2025.

## POST Request

<table><thead><tr><th width="161.9998779296875">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"validatorAprHistory"</code></td></tr><tr><td><code>validator</code></td><td>string</td><td>Validator address (0x-prefixed, 42 characters)</td></tr><tr><td><code>startTime</code></td><td>number</td><td>(Optional) Earliest week time in ms (inclusive)</td></tr><tr><td><code>endTime</code></td><td>number</td><td>(Optional) Latest week time in ms (inclusive); must be ≥ <code>startTime</code></td></tr><tr><td><code>limit</code></td><td>number</td><td>(Optional) Max weeks to return. Default 12, max 100.</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "validatorAprHistory",
    "validator": "0x5ac99df645f3414876c816caf18b2d234024b487"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'validatorAprHistory',
        'validator': '0x5ac99df645f3414876c816caf18b2d234024b487'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post('https://api.hydromancer.xyz/info', {
    type: 'validatorAprHistory',
    validator: '0x5ac99df645f3414876c816caf18b2d234024b487'
}, {
    headers: {
        'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
        'Content-Type': 'application/json'
    }
});

console.log(response.data);
```

{% endtab %}
{% endtabs %}

***

## Response

Array of weekly entries, sorted by week descending.

| Field                   | Type   | Description                                                                                      |
| ----------------------- | ------ | ------------------------------------------------------------------------------------------------ |
| `week`                  | number | Week-start timestamp in milliseconds (Monday 00:00 UTC)                                          |
| `netApr`                | number | Net-of-commission delegator APR, raw fraction (`0.0213` = 2.13%); simple, non-compounded         |
| `grossApr`              | number | Pre-commission APR (the validator's raw rate), raw fraction; implied fee = `1 − netApr/grossApr` |
| `totalDelegatorRewards` | string | Net HYPE distributed to this validator's delegators during the week                              |

<details>

<summary>Response</summary>

```json
[
    {
        "week": 1781481600000,
        "netApr": 0.0213,
        "grossApr": 0.0224,
        "totalDelegatorRewards": "2123.45000000"
    },
    {
        "week": 1780876800000,
        "netApr": 0.0224,
        "grossApr": 0.0224,
        "totalDelegatorRewards": "2231.10000000"
    }
]
```

</details>


# stakingEvents

Query historical staking events (delegate, undelegate, withdrawal).

### Overview

Returns historical staking events from ClickHouse. Supports filtering by user, validator, event type, and time range.

### Request

* **Endpoint**: `POST /info`

```json
{
  "type": "stakingEvents",
  "user": "0xabc123...",
  "validator": "0x000000000056f99d36b6f2e0c51fd41496bbacb8",
  "eventType": "delegate",
  "startTime": 1694764800000,
  "endTime": 1694851200000,
  "limit": 500
}
```

| Parameter   | Type   | Required | Description                                          |
| ----------- | ------ | -------- | ---------------------------------------------------- |
| `user`      | string | No       | Filter by user address                               |
| `validator` | string | No       | Filter by validator address                          |
| `eventType` | string | No       | Filter by event type (e.g. `delegate`, `undelegate`) |
| `startTime` | number | No       | Start time in milliseconds                           |
| `endTime`   | number | No       | End time in milliseconds                             |
| `limit`     | number | No       | Max results (default 500, max 2000)                  |

### Response

```json
[
  {
    "time": 1694764800000,
    "hash": "0xabc123...",
    "eventType": "delegate",
    "txIndex": 0,
    "user": "0xabc123...",
    "validator": "0x000000000056f99d36b6f2e0c51fd41496bbacb8",
    "amount": "1000.0",
    "currency": "HYPE",
    "isFinalized": true,
    "isUndelegate": false
  }
]
```

### Response Fields

| Field          | Type           | Description                           |
| -------------- | -------------- | ------------------------------------- |
| `time`         | number         | Event timestamp in milliseconds       |
| `hash`         | string         | Transaction hash                      |
| `eventType`    | string         | Type of staking event                 |
| `txIndex`      | number         | Transaction index within block        |
| `user`         | string         | User address                          |
| `validator`    | string         | Validator address                     |
| `amount`       | string \| null | HYPE amount (decimal string)          |
| `currency`     | string         | Currency (always `HYPE`)              |
| `isFinalized`  | boolean        | Whether the event is finalized        |
| `isUndelegate` | boolean        | Whether this is an undelegation event |


# globalStakingSummary

Get per-user staking balances across all of Hyperliquid — delegated, pending unstake, and available staking balance.

### Overview

Returns a user-centric global staking snapshot with three balance types per user. Sorted by staked balance descending. Updated roughly every 10 minutes.

### Request

* **Endpoint**: `POST /info`

```json
{
  "type": "globalStakingSummary"
}
```

### Response Headers

* `x-payload-format: msgpack`

### Data Format

**Format**: MessagePack

**Structure** — a positional array of 4 elements `[i, t, s, a]`:

```json
[
  "20260413_957200000",              // [0] Snapshot ID
  1776010486341,                     // [1] Timestamp (ms)
  [                                  // [2] Staking tuples (parallel with addresses)
    [241305342.63, 0.0, 0.0],
    [18308351.73, 404753.12, 99284.89]
  ],
  [                                  // [3] Addresses (parallel with staking tuples)
    "0x43e9abea1910387c4292bca4b94de81462f8a251",
    "0x393d0b87ed38fc779fd9611144ae649ba6082109"
  ]
]
```

**Staking Tuple Format** — each entry in `s` contains 3 values in order:

```
staked_balance      // HYPE delegated to validators (sum across all validators)
pending_unstake     // HYPE in the 7-day undelegation queue
staking_balance     // HYPE available in staking system (not delegated, not pending)
```

All amounts are in HYPE. The three fields are non-overlapping.

<details>

<summary>Dependencies</summary>

**JavaScript**

* **msgpack**: For decoding (e.g., `@msgpack/msgpack`)

**Python**

* **msgpack**: For decoding (e.g., `msgpack`)

</details>

### Implementation examples

**Note**: Make sure to set **HYDROMANCER\_API\_KEY** in your .env file

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const axios = require('axios');
const { decode } = require('@msgpack/msgpack');
require('dotenv').config();

async function getGlobalStakingSummary() {
    const response = await axios.post(
        `${process.env.HYDROMANCER_API_URL || 'https://api.hydromancer.xyz'}/info`,
        { type: 'globalStakingSummary' },
        {
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`
            },
            responseType: 'arraybuffer'
        }
    );

    const [snapshotId, timestamp, stakingTuples, addresses] = decode(response.data);

    console.log(`Snapshot: ${snapshotId}, users: ${addresses.length}`);

    // Example: find top 5 by staked balance
    for (let i = 0; i < Math.min(5, addresses.length); i++) {
        const [staked, pending, available] = stakingTuples[i];
        console.log(`${addresses[i]}: staked=${staked}, pending=${pending}, available=${available}`);
    }
}

getGlobalStakingSummary().catch(console.error);
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import msgpack
import os
from dotenv import load_dotenv

load_dotenv()

def get_global_staking_summary():
    base_url = os.getenv('HYDROMANCER_API_URL', 'https://api.hydromancer.xyz')
    api_key = os.getenv('HYDROMANCER_API_KEY')

    response = requests.post(
        f'{base_url}/info',
        json={'type': 'globalStakingSummary'},
        headers={
            'Content-Type': 'application/json',
            'Authorization': f'Bearer {api_key}'
        }
    )
    response.raise_for_status()

    snapshot_id, timestamp, staking_tuples, addresses = msgpack.unpackb(
        response.content, raw=False
    )

    print(f"Snapshot: {snapshot_id}, users: {len(addresses)}")

    # Example: find top 5 by staked balance
    for i in range(min(5, len(addresses))):
        staked, pending, available = staking_tuples[i]
        print(f"{addresses[i]}: staked={staked}, pending={pending}, available={available}")

if __name__ == '__main__':
    get_global_staking_summary()
```

{% endtab %}
{% endtabs %}

### Rate Limits

* **Points cost**: 1
* **Window**: 5 requests per 10 minutes

### Errors

| Status | Condition                  |
| ------ | -------------------------- |
| 404    | Snapshot not available yet |
| 500    | Server error               |


# Delegations

#### **Retrieve user's staking delegations**

{% content-ref url="/pages/ZPLCA5KoBYbQ8WBrGwWJ" %}
[delegations](/readme/rest-api/delegations/delegations)
{% endcontent-ref %}

#### **Retrieve delegator summary**

{% content-ref url="/pages/ViSAXacoeR8PMDEF9EdX" %}
[delegatorSummary](/readme/rest-api/delegations/delegatorsummary)
{% endcontent-ref %}

#### **Retrieve delegator history**

{% content-ref url="/pages/cycdXzHav05cYMEzNMIz" %}
[delegatorHistory](/readme/rest-api/delegations/delegatorhistory)
{% endcontent-ref %}

#### **Retrieve max builder fee**

{% content-ref url="/pages/XgEulu0gGi3pMoqykonJ" %}
[maxBuilderFee](/readme/rest-api/delegations/maxbuilderfee)
{% endcontent-ref %}

#### **Retrieve validator L1 votes**

{% content-ref url="/pages/lXyAO8l4Yx0QKqi8eE12" %}
[validatorL1Votes](/readme/rest-api/delegations/validatorl1votes)
{% endcontent-ref %}


# delegations

Get delegation information for a user.

## POST Request

<table><thead><tr><th width="161.9998779296875">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"delegations"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "delegations",
    "user": "0x0000000000000000000000000000000000000000"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'delegations',
        'user': '0x0000000000000000000000000000000000000000'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'delegations',
        user: '0x0000000000000000000000000000000000000000'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field                  | Type   | Description                      |
| ---------------------- | ------ | -------------------------------- |
| `validator`            | string | Validator address                |
| `amount`               | string | Delegated amount                 |
| `lockedUntilTimestamp` | int    | Unlock timestamp in milliseconds |

<details>

<summary>Response</summary>

```json
[
    {
        "validator": "0x420a4ed7b6bb361da586868adec2f2bb9ab75e66",
        "amount": "305.27602401",
        "lockedUntilTimestamp": 1768061059908
    },
    {
        "validator": "0x497beec89958848126c2ea65934ce430e1410ad2",
        "amount": "217.26663138",
        "lockedUntilTimestamp": 1753148985995
    }
]
```

</details>


# delegatorSummary

Get a summary of a user's delegation status.

Get a summary of a user's delegation status.

## POST Request

<table><thead><tr><th width="161.9998779296875">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"delegatorSummary"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "delegatorSummary",
    "user": "0x0000000000000000000000000000000000000000"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'delegatorSummary',
        'user': '0x0000000000000000000000000000000000000000'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'delegatorSummary',
        user: '0x0000000000000000000000000000000000000000'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response Fields

| Field                    | Type   | Description                      |
| ------------------------ | ------ | -------------------------------- |
| `delegated`              | string | Total amount currently delegated |
| `undelegated`            | string | Total amount undelegated         |
| `totalPendingWithdrawal` | string | Total amount pending withdrawal  |
| `nPendingWithdrawals`    | int    | Number of pending withdrawals    |

<details>

<summary>Response</summary>

```json
{
    "delegated": "1518.74003972",
    "undelegated": "0.0",
    "totalPendingWithdrawal": "0.0",
    "nPendingWithdrawals": 0
}
```

</details>


# delegatorHistory

Query a user's staking history (delegations, deposits, withdrawals).

Returns a user's staking event history, mirroring Hyperliquid's `delegatorHistory` endpoint format. Includes delegation, deposit, and withdrawal events.

**Data availability:** Events from **2025-07-27** onwards.

## POST Request

<table><thead><tr><th width="161.9998779296875">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"delegatorHistory"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr><tr><td><code>limit</code></td><td>number</td><td>(Optional) Max results to return. Default 500, max 2000.</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "delegatorHistory",
    "user": "0x5aeb1821f596d2d9ffe182d3f914b274a80511cc"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'delegatorHistory',
        'user': '0x5aeb1821f596d2d9ffe182d3f914b274a80511cc'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

try {
    const response = await axios.post('https://api.hydromancer.xyz/info', {
        type: 'delegatorHistory',
        user: '0x5aeb1821f596d2d9ffe182d3f914b274a80511cc'
    }, {
        headers: {
            'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
            'Content-Type': 'application/json'
        }
    });

    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
```

{% endtab %}
{% endtabs %}

***

## Response

Returns an array of staking events, sorted by time descending (most recent first). Each event has a `delta` object whose key indicates the event type.

### Delta types

#### `delegate` — Delegation or undelegation

| Field          | Type    | Description                                   |
| -------------- | ------- | --------------------------------------------- |
| `validator`    | string  | Validator address                             |
| `amount`       | string  | Amount delegated/undelegated (decimal string) |
| `isUndelegate` | boolean | `true` if undelegating, `false` if delegating |

#### `cDeposit` — Staking deposit

| Field    | Type   | Description                       |
| -------- | ------ | --------------------------------- |
| `amount` | string | Amount deposited (decimal string) |

#### `withdrawal` — Staking withdrawal

| Field    | Type   | Description                       |
| -------- | ------ | --------------------------------- |
| `amount` | string | Amount withdrawn (decimal string) |
| `phase`  | string | `"initiated"` or `"finalized"`    |

### Common fields

| Field   | Type   | Description                                 |
| ------- | ------ | ------------------------------------------- |
| `time`  | number | Event timestamp in milliseconds             |
| `hash`  | string | Transaction hash                            |
| `delta` | object | Event-specific data (see delta types above) |

<details>

<summary>Response</summary>

```json
[
    {
        "time": 1744312029183,
        "hash": "0xbe9abb84c0864034c0140438d84d29020193006a5b895f06626366d77f8a1a1f",
        "delta": {
            "delegate": {
                "validator": "0xa82fe73bbd768bc15d1ef2f6142a21ff8bd762ad",
                "amount": "87287.26",
                "isUndelegate": true
            }
        }
    },
    {
        "time": 1744312029183,
        "hash": "0xeaa8034e7059d23aec210438d881700202f500340b5cf10c8e70aea12f5dac25",
        "delta": {
            "withdrawal": {
                "amount": "351237.19",
                "phase": "initiated"
            }
        }
    }
]
```

</details>


# delegatorRewards

Query a user's daily HYPE staking rewards (delegation + commission).

Is a superset of Hyperliquid's delegatorRewards. Includes on top the hype mark price at time of reward distribution and total amount of hype staked.&#x20;

Now also possible to be queried per validator so you can track exactly how each validator is performing.

**Data availability:** From 1 August 2025.

## POST Request

<table><thead><tr><th width="161.9998779296875">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"delegatorRewards"</code></td></tr><tr><td><code>user</code></td><td>string</td><td>Ethereum address (0x-prefixed, 42 characters)</td></tr><tr><td><code>validator</code></td><td>string</td><td>(Optional) Restrict to rewards from this validator only (0x-prefixed). Omit to sum across all validators.</td></tr><tr><td><code>startTime</code></td><td>number</td><td>(Optional) Earliest distribution time in ms (inclusive)</td></tr><tr><td><code>endTime</code></td><td>number</td><td>(Optional) Latest distribution time in ms (inclusive)</td></tr><tr><td><code>limit</code></td><td>number</td><td>(Optional) Max results to return. Default 500, max 2000.</td></tr></tbody></table>

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "delegatorRewards",
    "user": "0x2a618f4f3f089c873af8cb674db2e43ae123d1cc"
  }'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import os

response = requests.post(
    'https://api.hydromancer.xyz/info',
    json={
        'type': 'delegatorRewards',
        'user': '0x2a618f4f3f089c873af8cb674db2e43ae123d1cc'
    },
    headers={
        'Authorization': f'Bearer {os.environ.get("HYDROMANCER_API_KEY")}',
        'Content-Type': 'application/json'
    }
)

print(response.json())
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
import axios from 'axios';

const response = await axios.post('https://api.hydromancer.xyz/info', {
    type: 'delegatorRewards',
    user: '0x2a618f4f3f089c873af8cb674db2e43ae123d1cc'
}, {
    headers: {
        'Authorization': `Bearer ${process.env.HYDROMANCER_API_KEY}`,
        'Content-Type': 'application/json'
    }
});

console.log(response.data);
```

{% endtab %}
{% endtabs %}

***

## Response

Array of reward entries, one per (day, source), sorted by time descending. `totalAmount` is HYPE, summed across all validators contributing to that day's distribution for the user — or, when the `validator` field is set, scoped to that single validator.

| Field          | Type           | Description                                                                                                         |
| -------------- | -------------- | ------------------------------------------------------------------------------------------------------------------- |
| `time`         | number         | Distribute-tick timestamp in milliseconds (first block at or after 00:00 UTC of the distribution day)               |
| `source`       | string         | `"delegation"` or `"commission"`                                                                                    |
| `totalAmount`  | string         | HYPE reward, summed across all contributing validators                                                              |
| `stakedAmount` | string \| null | HYPE staked to the contributing validators at the tick, summed. `null` for `commission` rows (not a stake position) |
| `hypePrice`    | string \| null | HYPE/USDC oracle price at the tick. `null` when no oracle price is available                                        |

<details>

<summary>Response</summary>

```json
[
    {
        "time": 1745452800000,
        "source": "delegation",
        "totalAmount": "4.04380675",
        "stakedAmount": "12500.00",
        "hypePrice": "18.42"
    },
    {
        "time": 1745366400000,
        "source": "commission",
        "totalAmount": "0.91200000",
        "stakedAmount": null,
        "hypePrice": "18.39"
    }
]
```

</details>




---

[Next Page](/llms-full.txt/1)

