ZetariumZetariumDex

Account

Balance, positions, exposure, transfer history, PnL.

Code samples assume the signed-request helper from Endpoints / Overview → Client setup.

GET /v2/futures/balance

Futures wallet balance.

AuthAPI_KEY (READ_ONLY+)
Rate limitdefault 1000/min

Query

  • subAccountId (optional, string) — Specific sub-account. Omit for the user's primary sub.

Response

{
  "ok": true,
  "balances": {
    "assets": [
      {
        "asset": "USDT",
        "walletBalance": "1234.56",
        "availableBalance": "1100.45",
        "marginBalance": "1234.56",
        "unrealizedProfit": "12.34",
        "crossWalletBalance": "1234.56"
      }
    ]
  }
}

Errors403 Unauthorized subAccountId (sub does not belong to caller); 400 No sub account found.

Example

TS=$(($(date +%s) * 1000)); QUERY="timestamp=${TS}"
SIG=$(sign "$SECRET" "$QUERY")
curl -H "X-API-KEY: $API_KEY" "$BASE_URL/v2/futures/balance?${QUERY}&signature=${SIG}"
const balance = await signedRequest('GET', '/v2/futures/balance');
console.log(balance);
balance = signed_request("GET", "/v2/futures/balance").json()
print(balance)
body, _ := zdex.SignedRequest("GET", "/v2/futures/balance", nil, nil)
fmt.Println(string(body))
let balance = signed_request(reqwest::Method::GET, "/v2/futures/balance", &[], None).await?;
println!("{balance}");
$balance = signed_request('GET', '/v2/futures/balance');
print_r($balance);

GET /v2/positions

Open positions for the authenticated account.

AuthAPI_KEY
Rate limitdefault

Query

  • status (optional) — OPEN (default) | CLOSED.

Response

{
  "ok": true,
  "positions": [
    {
      "id": "cmod...",
      "accountId": "cmnw...",
      "venuePositionId": "...",
      "symbol": "BTCUSDT",
      "quantity": "0.5",
      "avgEntryPrice": "30000",
      "markPrice": "30100",
      "liquidationPrice": "27500",
      "unrealizedPnl": "50",
      "realizedPnl": "0",
      "fundingFee": "-0.05",
      "initialMargin": "300",
      "maintenanceMargin": "75",
      "leverage": 10,
      "marginMode": "CROSSED",
      "positionSide": "LONG",
      "status": "OPEN",
      "closeReason": null,
      "closedAt": null,
      "updatedAt": "2026-04-26T..."
    }
  ]
}

Notes

  • quantity > 0LONG; quantity < 0SHORT.
  • Returns all positions on your account; status is a filter. Other users' positions are never visible (audit fix C-5).
  • The legacy ?accountId=X query parameter is ignored — kept disabled for security.

Example

TS=$(($(date +%s) * 1000))
QUERY="status=OPEN&timestamp=${TS}"   # alphabetical
SIG=$(sign "$SECRET" "$QUERY")
curl -H "X-API-KEY: $API_KEY" "$BASE_URL/v2/positions?${QUERY}&signature=${SIG}"
const positions = await signedRequest('GET', '/v2/positions', {
  params: { status: 'OPEN' },
});
positions = signed_request("GET", "/v2/positions", params={"status": "OPEN"}).json()
body, _ := zdex.SignedRequest("GET", "/v2/positions",
    map[string]string{"status": "OPEN"}, nil)
let positions = signed_request(
    reqwest::Method::GET,
    "/v2/positions",
    &[("status", "OPEN")],
    None,
).await?;
$positions = signed_request('GET', '/v2/positions', ['status' => 'OPEN']);

GET /v2/risk/exposure

Gross exposure across open positions.

AuthAPI_KEY

Response

{
  "ok": true,
  "grossExposure": "15000.50",
  "positions": [/* same Position[] format */]
}

grossExposure = sum(|qty|) over open positions. PnL is computed with the same formatPositions logic.

Example

TS=$(($(date +%s) * 1000)); QUERY="timestamp=${TS}"
SIG=$(sign "$SECRET" "$QUERY")
curl -H "X-API-KEY: $API_KEY" "$BASE_URL/v2/risk/exposure?${QUERY}&signature=${SIG}"
const exposure = await signedRequest('GET', '/v2/risk/exposure');
exposure = signed_request("GET", "/v2/risk/exposure").json()
body, _ := zdex.SignedRequest("GET", "/v2/risk/exposure", nil, nil)
let exposure = signed_request(reqwest::Method::GET, "/v2/risk/exposure", &[], None).await?;
$exposure = signed_request('GET', '/v2/risk/exposure');

GET /v2/me/transfers

Deposit / withdraw history.

AuthAPI_KEY

Query

  • skip (optional, int) — pagination offset.
  • take (optional, int, max 100) — page size.
  • type (optional) — "deposit" | "withdraw" | "all" (default).

Response

{
  "ok": true,
  "transfers": [
    {
      "id": "...",
      "asset": "USDT",
      "amount": "100",
      "transferType": 1,
      "status": "SUCCESS",
      "venueTransferId": "0xabc...",
      "createdAt": "...",
      "updatedAt": "..."
    }
  ],
  "total": 42
}

transferType: 1 = deposit, 2 = withdraw.

status is one of PENDING | PROCESSING | SUBMITTED | SUCCESS | CONFIRMED | FAILED | CANCELLED. SUCCESS and CONFIRMED are both terminal-success states (the venue uses both interchangeably across deposit / withdraw paths). Treat FAILED and CANCELLED as terminal failures; everything else is in-flight.

Example

TS=$(($(date +%s) * 1000))
QUERY="take=20&timestamp=${TS}&type=deposit"   # alphabetical
SIG=$(sign "$SECRET" "$QUERY")
curl -H "X-API-KEY: $API_KEY" "$BASE_URL/v2/me/transfers?${QUERY}&signature=${SIG}"
const transfers = await signedRequest('GET', '/v2/me/transfers', {
  params: { type: 'deposit', take: 20 },
});
transfers = signed_request("GET", "/v2/me/transfers",
                           params={"type": "deposit", "take": 20}).json()
body, _ := zdex.SignedRequest("GET", "/v2/me/transfers",
    map[string]string{"type": "deposit", "take": "20"}, nil)
let transfers = signed_request(
    reqwest::Method::GET,
    "/v2/me/transfers",
    &[("type", "deposit"), ("take", "20")],
    None,
).await?;
$transfers = signed_request('GET', '/v2/me/transfers',
    ['type' => 'deposit', 'take' => 20]);

GET /v2/me/activities

Unified activity feed (orders + executions + transfers).

AuthAPI_KEY

Query

  • skip, take — pagination.

Response

{
  "ok": true,
  "data": [
    { "type": "ORDER",     "id": "...", "data": { /* Order */ },     "ts": "2026-04-26T12:34:56.789Z" },
    { "type": "EXECUTION", "id": "...", "data": { /* Execution */ }, "ts": "2026-04-26T12:34:55.000Z" },
    { "type": "TRANSFER",  "id": "...", "data": { /* Transfer */ },  "ts": "2026-04-26T12:00:00.000Z" }
  ],
  "total": 355,
  "totals": {
    "totalBuyVolume": "12000.50",
    "totalSellVolume": "9800.25",
    "totalBuyCount": 142,
    "totalSellCount": 113,
    "totalOrderBuyCount": 162,
    "totalOrderSellCount": 130,
    "totalDeposits": "5000.00",
    "totalWithdrawals": "1200.00",
    "totalDepositCount": 3,
    "totalWithdrawalCount": 1
  }
}

The feed entries live under data (not activities). ts is an ISO-8601 string (Date serialized), not a millisecond epoch. totals is an aggregate ledger across the account, not a count of returned entries — it does not change with skip/take.

Designed for UI feeds. For programmatic access, prefer the dedicated GET /v2/orders, GET /v2/futures/myTrades, and GET /v2/me/transfers endpoints separately.

Example

TS=$(($(date +%s) * 1000))
QUERY="take=50&timestamp=${TS}"
SIG=$(sign "$SECRET" "$QUERY")
curl -H "X-API-KEY: $API_KEY" "$BASE_URL/v2/me/activities?${QUERY}&signature=${SIG}"
const activities = await signedRequest('GET', '/v2/me/activities', {
  params: { take: 50 },
});
activities = signed_request("GET", "/v2/me/activities", params={"take": 50}).json()
body, _ := zdex.SignedRequest("GET", "/v2/me/activities",
    map[string]string{"take": "50"}, nil)
let activities = signed_request(
    reqwest::Method::GET, "/v2/me/activities", &[("take", "50")], None,
).await?;
$activities = signed_request('GET', '/v2/me/activities', ['take' => 50]);

GET /v2/account/pnl-history

PnL / volume / trade-count series, bucketed by day, week, or month, with running totals.

AuthAPI_KEY

Query

  • perioddaily | weekly | monthly (default daily).
  • limit — number of buckets to return, default 30.

Response

{
  "ok": true,
  "history": [
    {
      "date": "2026-04-26",
      "pnl": -1.23,
      "volume": 5400.00,
      "trades": 18
    }
  ],
  "summary": {
    "totalPnl": -34.5,
    "totalVolume": 98750.0,
    "totalTrades": 412
  }
}

The bucket key is in date:

  • dailyYYYY-MM-DD
  • weeklyYYYY-MM-DD of the week start (Sunday)
  • monthlyYYYY-MM

pnl, volume and summary.* are returned as JSON numbers (not strings) — this endpoint pre-dates the string-decimals convention and is based on a 1000-execution rolling window. For an exact ledger-grade PnL, prefer GET /v2/me/stats or the rebate-claim endpoints under /v2/me/rebate/*.

pnl here is the executions-side ledger only — fees subtracted, no funding. volume is Σ quantity × price over the window's executions.

Example

TS=$(($(date +%s) * 1000))
QUERY="limit=30&period=daily&timestamp=${TS}"
SIG=$(sign "$SECRET" "$QUERY")
curl -H "X-API-KEY: $API_KEY" "$BASE_URL/v2/account/pnl-history?${QUERY}&signature=${SIG}"
const pnl = await signedRequest('GET', '/v2/account/pnl-history', {
  params: { period: 'daily', limit: 30 },
});
pnl = signed_request("GET", "/v2/account/pnl-history",
                     params={"period": "daily", "limit": 30}).json()
body, _ := zdex.SignedRequest("GET", "/v2/account/pnl-history",
    map[string]string{"period": "daily", "limit": "30"}, nil)
let pnl = signed_request(
    reqwest::Method::GET, "/v2/account/pnl-history",
    &[("period", "daily"), ("limit", "30")], None,
).await?;
$pnl = signed_request('GET', '/v2/account/pnl-history',
    ['period' => 'daily', 'limit' => 30]);

GET /v2/accounts/:id/balances

Generic spot-wallet balance for the account's primary sub. For the futures wallet use GET /v2/futures/balance; this endpoint pulls the spot ledger from the venue and forwards the raw payload through.

AuthAPI_KEY

Path

  • :id — your accountId. Passing any other id returns 404.

Response — shape is whatever the upstream getBalance connector returns; typically:

{
  "ok": true,
  "balances": [
    { "asset": "USDT", "free": "1500.50", "locked": "0" }
  ]
}

If the upstream payload doesn't carry a balances array, the entire upstream object is forwarded as balances instead — code defensively for both shapes.

Example

ACCOUNT_ID="cmnw1234..."
TS=$(($(date +%s) * 1000)); QUERY="timestamp=${TS}"
SIG=$(sign "$SECRET" "$QUERY")
curl -H "X-API-KEY: $API_KEY" "$BASE_URL/v2/accounts/${ACCOUNT_ID}/balances?${QUERY}&signature=${SIG}"
const accountId = 'cmnw1234...';
const balances = await signedRequest('GET', `/v2/accounts/${accountId}/balances`);
account_id = "cmnw1234..."
balances = signed_request("GET", f"/v2/accounts/{account_id}/balances").json()
accountID := "cmnw1234..."
body, _ := zdex.SignedRequest("GET",
    fmt.Sprintf("/v2/accounts/%s/balances", accountID), nil, nil)
let account_id = "cmnw1234...";
let balances = signed_request(
    reqwest::Method::GET,
    &format!("/v2/accounts/{account_id}/balances"),
    &[], None,
).await?;
$accountId = 'cmnw1234...';
$balances = signed_request('GET', "/v2/accounts/{$accountId}/balances");

On this page