ZetariumZetariumDex

Market Data (Public)

Symbols, ticker, depth, klines, funding rate, leaderboard.

All endpoints in this section are public — no X-API-KEY and no signature required. Responses are CDN-cacheable.

GET /v2/symbols

Active futures symbols.

{ "ok": true, "symbols": ["BTCUSDT", "ETHUSDT"] }

Example

curl "$BASE_URL/v2/symbols"
const { symbols } = await fetch(`${BASE_URL}/v2/symbols`).then((r) => r.json());
symbols = requests.get(f"{BASE_URL}/v2/symbols").json()["symbols"]
res, _ := http.Get(BaseURL + "/v2/symbols")
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
let symbols = reqwest::get(format!("{BASE_URL}/v2/symbols")).await?.json::<Value>().await?;
$symbols = json_decode(file_get_contents(BASE_URL . '/v2/symbols'), true);

GET /v2/ticker/24hr

24-hour ticker statistics.

Query (optional)

  • symbol — single symbol; omit for all cached tickers.

Response — always returns a tickers array (single-element when filtered):

{
  "ok": true,
  "tickers": [
    {
      "symbol": "BTCUSDT",
      "lastPrice": "30100",
      "priceChange": "150",
      "priceChangePercent": "0.5",
      "highPrice": "30500",
      "lowPrice": "29800",
      "volume": "12345.67",
      "quoteVolume": "370000000"
    }
  ]
}

There is no singular ticker field — even a single-symbol query returns an array. Code defensively for the array shape.

Example

curl "$BASE_URL/v2/ticker/24hr?symbol=BTCUSDT"
const { tickers } = await fetch(
  `${BASE_URL}/v2/ticker/24hr?symbol=BTCUSDT`,
).then((r) => r.json());
tickers = requests.get(f"{BASE_URL}/v2/ticker/24hr",
                       params={"symbol": "BTCUSDT"}).json()["tickers"]
res, _ := http.Get(BaseURL + "/v2/ticker/24hr?symbol=BTCUSDT")
let tickers = reqwest::get(format!("{BASE_URL}/v2/ticker/24hr?symbol=BTCUSDT"))
    .await?.json::<Value>().await?;
$tickers = json_decode(file_get_contents(
    BASE_URL . '/v2/ticker/24hr?symbol=BTCUSDT'
), true);

GET /v2/depth

Top-of-book order book.

Query

  • symbol (required)
  • limit (default 100) — top N bids and asks.

Response — top-level bids / asks; no lastUpdateId (driven by the venue cache):

{
  "ok": true,
  "bids": [
    ["78011.9", "3.4272"],
    ["78011.8", "0.3876"]
  ],
  "asks": [
    ["78012.0", "0.5123"],
    ["78012.1", "1.2456"]
  ]
}

Each entry is a [price, quantity] string array.

Example

curl "$BASE_URL/v2/depth?symbol=BTCUSDT&limit=20"
const depth = await fetch(
  `${BASE_URL}/v2/depth?symbol=BTCUSDT&limit=20`,
).then((r) => r.json());
depth = requests.get(f"{BASE_URL}/v2/depth",
                     params={"symbol": "BTCUSDT", "limit": 20}).json()
res, _ := http.Get(BaseURL + "/v2/depth?symbol=BTCUSDT&limit=20")
let depth = reqwest::get(format!("{BASE_URL}/v2/depth?symbol=BTCUSDT&limit=20"))
    .await?.json::<Value>().await?;
$depth = json_decode(file_get_contents(
    BASE_URL . '/v2/depth?symbol=BTCUSDT&limit=20'
), true);

GET /v2/trades

Recent market trades.

Querysymbol (required), limit (default 20).

{
  "ok": true,
  "trades": [
    {
      "id": 0,
      "price": "78012.0",
      "qty": "0.695",
      "time": 1777217777950,
      "isBuyerMaker": false
    }
  ]
}

Example

curl "$BASE_URL/v2/trades?symbol=BTCUSDT&limit=20"
const trades = await fetch(
  `${BASE_URL}/v2/trades?symbol=BTCUSDT&limit=20`,
).then((r) => r.json());
trades = requests.get(f"{BASE_URL}/v2/trades",
                      params={"symbol": "BTCUSDT", "limit": 20}).json()
res, _ := http.Get(BaseURL + "/v2/trades?symbol=BTCUSDT&limit=20")
let trades = reqwest::get(format!("{BASE_URL}/v2/trades?symbol=BTCUSDT&limit=20"))
    .await?.json::<Value>().await?;
$trades = json_decode(file_get_contents(
    BASE_URL . '/v2/trades?symbol=BTCUSDT&limit=20'
), true);

GET /v2/funding-rate

Current funding rate.

Querysymbol (required).

Response

{ "ok": true, "symbol": "BTCUSDT", "fundingRate": "0.0001" }

If the rate is not yet cached:

{ "ok": true, "symbol": "BTCUSDT", "fundingRate": null }

Example

curl "$BASE_URL/v2/funding-rate?symbol=BTCUSDT"
const fr = await fetch(`${BASE_URL}/v2/funding-rate?symbol=BTCUSDT`)
  .then((r) => r.json());
fr = requests.get(f"{BASE_URL}/v2/funding-rate",
                  params={"symbol": "BTCUSDT"}).json()
res, _ := http.Get(BaseURL + "/v2/funding-rate?symbol=BTCUSDT")
let fr = reqwest::get(format!("{BASE_URL}/v2/funding-rate?symbol=BTCUSDT"))
    .await?.json::<Value>().await?;
$fr = json_decode(file_get_contents(
    BASE_URL . '/v2/funding-rate?symbol=BTCUSDT'
), true);

GET /v2/klines

OHLCV candles.

ParameterFormat
symbolstring, required
interval1m 3m 5m 15m 30m 1h 2h 4h 6h 8h 12h 1d 3d 1w 1M
limitdefault 300

The legacy startTime / endTime query params are accepted by the validator but silently ignored — the upstream venue cache does not support time-range queries on klines. Always paginate by limit from the most-recent candle backwards. Server-side fix tracked under the known-limitations page.

Response

{
  "ok": true,
  "data": [
    [
      1714123456789,
      "30000",
      "30100",
      "29950",
      "30050",
      "1234.56",
      1714123516789,
      "37000000",
      100,
      "600",
      "18000000",
      "0"
    ]
  ]
}

Positional array (Binance-compatible shape):

[ openTime, open, high, low, close, volume, closeTime, quoteVolume, trades, takerBuyBase, takerBuyQuote, ignore ]

Example

curl "$BASE_URL/v2/klines?symbol=BTCUSDT&interval=1m&limit=200"
const { data } = await fetch(
  `${BASE_URL}/v2/klines?symbol=BTCUSDT&interval=1m&limit=200`,
).then((r) => r.json());
klines = requests.get(f"{BASE_URL}/v2/klines",
    params={"symbol": "BTCUSDT", "interval": "1m", "limit": 200}).json()["data"]
res, _ := http.Get(BaseURL + "/v2/klines?symbol=BTCUSDT&interval=1m&limit=200")
let klines = reqwest::get(format!(
    "{BASE_URL}/v2/klines?symbol=BTCUSDT&interval=1m&limit=200"
)).await?.json::<Value>().await?;
$klines = json_decode(file_get_contents(
    BASE_URL . '/v2/klines?symbol=BTCUSDT&interval=1m&limit=200'
), true);

GET /v2/leaderboard

Query

  • typevolume | referrals | commission
  • limit — default 20, max 100
  • period7d | 30d | all (default all)

period only accepts 7d, 30d, or all. Sending daily, weekly, or monthly (the old enum) returns 400 from validation.

Response — entry shape varies by type:

// type=volume
{
  "ok": true,
  "type": "volume",
  "period": "all",
  "data": [
    { "rank": 1, "accountId": "cmnw...", "walletAddress": "0x...", "volume": "1234567.89" }
  ]
}

// type=referrals
{
  "ok": true,
  "type": "referrals",
  "period": "all",
  "data": [
    { "rank": 1, "userId": "cmus...", "walletAddress": "0x...", "referralCount": 42 }
  ]
}

// type=commission
{
  "ok": true,
  "type": "commission",
  "period": "all",
  "data": [
    { "rank": 1, "userId": "cmus...", "walletAddress": "0x...", "totalCommission": "5400.25" }
  ]
}

Note the per-type field set: volume exposes accountId + volume, the other two expose userId + their own metric. Wallet address is included on every variant.

Example

curl "$BASE_URL/v2/leaderboard?type=volume&period=7d&limit=20"
const lb = await fetch(
  `${BASE_URL}/v2/leaderboard?type=volume&period=7d&limit=20`,
).then((r) => r.json());
lb = requests.get(f"{BASE_URL}/v2/leaderboard",
    params={"type": "volume", "period": "7d", "limit": 20}).json()
res, _ := http.Get(BaseURL + "/v2/leaderboard?type=volume&period=7d&limit=20")
let lb = reqwest::get(format!(
    "{BASE_URL}/v2/leaderboard?type=volume&period=7d&limit=20"
)).await?.json::<Value>().await?;
$lb = json_decode(file_get_contents(
    BASE_URL . '/v2/leaderboard?type=volume&period=7d&limit=20'
), true);

GET /v2/platform/tokens

(chainId, asset) → decimals registry, used when building EIP-712 signatures.

{
  "ok": true,
  "hash": "6c280be2f623082e",
  "tokens": [
    { "chainId": 56, "asset": "USDT", "decimals": 18, "contractAddress": "0x55d3..." },
    { "chainId": 1,  "asset": "USDT", "decimals": 6,  "contractAddress": "0xdAC1..." }
  ]
}

HeadersETag: "<hash>", Cache-Control: public, max-age=300 (5-minute cache + revalidate).

Example

curl "$BASE_URL/v2/platform/tokens"
const { tokens } = await fetch(`${BASE_URL}/v2/platform/tokens`)
  .then((r) => r.json());
tokens = requests.get(f"{BASE_URL}/v2/platform/tokens").json()["tokens"]
res, _ := http.Get(BaseURL + "/v2/platform/tokens")
let tokens = reqwest::get(format!("{BASE_URL}/v2/platform/tokens"))
    .await?.json::<Value>().await?;
$tokens = json_decode(file_get_contents(BASE_URL . '/v2/platform/tokens'), true);

GET /v2/platform/status

Feature flags.

{
  "ok": true,
  "features": {
    "referral": true,
    "trading": true,
    "deposits": true,
    "withdrawals": true
  }
}

Example

curl "$BASE_URL/v2/platform/status"
const { features } = await fetch(`${BASE_URL}/v2/platform/status`)
  .then((r) => r.json());
features = requests.get(f"{BASE_URL}/v2/platform/status").json()["features"]
res, _ := http.Get(BaseURL + "/v2/platform/status")
let status = reqwest::get(format!("{BASE_URL}/v2/platform/status"))
    .await?.json::<Value>().await?;
$status = json_decode(file_get_contents(BASE_URL . '/v2/platform/status'), true);

GET /health

Liveness probe.

{ "ok": true, "service": "api" }

Example

curl "$BASE_URL/health"
const health = await fetch(`${BASE_URL}/health`).then((r) => r.json());
health = requests.get(f"{BASE_URL}/health").json()
res, _ := http.Get(BaseURL + "/health")
let health = reqwest::get(format!("{BASE_URL}/health")).await?.json::<Value>().await?;
$health = json_decode(file_get_contents(BASE_URL . '/health'), true);

On this page