Skip to content

Positions & Orders

Base URL: https://service.leverup.xyz

These endpoints return indexed data across all markets in one request, which is the main reason to prefer them over getPositionsV4 — the contract read takes one pairBase at a time. They also cover closed positions, which the contract does not retain.

The trade-off is indexing lag: a position appears here a moment after it appears onchain. For anything latency-sensitive, read the contract.

Open positions

http
GET /v1/user/{user_address}/open-positions
ParameterDefaultNotes
block_chainMONAD
page0
size20Capped at 100

Response

json
{
  "content": [
    {
      "positionHash": "0x…",
      "pair": "BTC/USD",
      "pairBase": "0xcf5a…",
      "trader": "0x…",
      "tokenIn": "0x7547…",
      "marginToken": "0xfd44…",
      "isLong": true,
      "margin": "9930000000000000000",
      "qty": "10000000",
      "entryPrice": "100123450000000000000000",
      "stopLoss": "0",
      "takeProfit": "0",
      "openFee": "70000000000000000",
      "executionFee": "0",
      "longAccFundingFeePerShare": "0",
      "holdingFeeRate": "0",
      "timestamp": 1785312000,
      "status": "OPEN",
      "closeInfo": null
    }
  ],
  "pageNumber": 0,
  "pageSize": 20,
  "totalPages": 1,
  "totalElements": 1
}
FieldUnit
qty1e10
entryPrice, stopLoss, takeProfit1e18
margin, openFee, executionFeemarginToken decimals — 18 for LVUSD and LVMON
holdingFeeRate1e12
longAccFundingFeePerShare1e18, signed
timestampUnix seconds

marginToken is the lvToken. Every amount above is denominated in it, not in tokenIn.

Accrued fees are not here

This endpoint returns the position as indexed at open time. Live accrued funding and holding fees come from getPositionsV4 onchain.

All positions

Open, closing, closed and cancelled.

http
GET /v1/user/{user_address}/positions
ParameterDefaultNotes
block_chainMONAD
page0
size20Capped at 100
timestamp_afterOnly positions opened after this Unix second
close_time_afterOnly positions closed after this Unix second

Same shape as above, plus a populated closeInfo for closed positions:

json
{
  "positionHash": "0x…",
  "status": "CLOSED",
  "closeInfo": {
    "closePrice": "101500000000000000000000",
    "fundingFee": "-1200000000000000",
    "closeFee": "70000000000000000",
    "pnl": "1370000000000000000",
    "holdingFee": "500000000000000",
    "closeTime": 1785315600
  }
}
statusMeaning
PENDINGRequested, not yet filled
OPENLive
CLOSINGClose requested, not yet settled
CLOSEDSettled
CANCELLEDNever opened — refunded

closeInfo is present for CLOSED, and for CLOSING once the PnL is known. fundingFee and pnl are signed. All amounts use marginToken decimals.

ts
async function realizedPnl(address: string, sinceUnix: number) {
  const res = await fetch(
    `${API}/v1/user/${address}/positions?close_time_after=${sinceUnix}&size=100`,
  )
  const { content } = await res.json()

  return content
    .filter((p: any) => p.status === 'CLOSED')
    .reduce((sum: bigint, p: any) => sum + BigInt(p.closeInfo.pnl), 0n)
}

Limit orders

There is no public per-user limit-order endpoint. Read them onchain with getLimitOrders, and TP/SL orders with getTraderDecreaseOrders.

Order lifecycle events do appear in trade history, so a completed order is visible there after the fact.

Trading perpetuals involves risk. Nothing here is financial advice.