Reading Data
This page covers every way to read Velocity state in your app — from the subscribed VelocityClient/User caches, to the stateless VelocityCore decoders, to the Data API REST endpoints.
Account data via VelocityClient / User
Once velocityClient is subscribed (see setup), account data is available synchronously from the User wrapper for the active (or any) subaccount.
Get the active account
const user = velocityClient.getUser(); // active subaccount
const otherUser = velocityClient.getUser(1); // subaccount 1
const userAccount = user.getUserAccount(); // raw decoded UserAccount
userAccount.authority;
userAccount.subAccountId;
userAccount.name; // number[] — decode with `decodeName()`Positions
import { decodeName } from "@velocity-exchange/sdk";
for (const position of userAccount.perpPositions) {
if (position.baseAssetAmount.isZero()) continue;
position.marketIndex;
position.baseAssetAmount; // BASE_PRECISION (1e9), signed: + long, - short
position.quoteAssetAmount; // QUOTE_PRECISION (1e6)
position.quoteEntryAmount;
position.quoteBreakEvenAmount;
position.lastCumulativeFundingRate;
position.openOrders;
position.openBids;
position.openAsks;
}
// Higher-level PnL/health accessors live on `User` — see PnL & Risk
const unrealizedPnl = user.getUnrealizedPNL(true, 0); // withFunding=true, market 0
const health = user.getHealth(); // 0-100See PnL & Risk for getTotalCollateral, getMarginRequirement, getFreeCollateral, getLeverage, and isolated-position variants.
Open orders
for (const order of userAccount.orders) {
if (order.status !== 1 /* OrderStatus.Open */) continue;
order.orderId;
order.marketIndex;
order.direction;
order.price; // PRICE_PRECISION (1e6), 0 for market orders
order.triggerPrice;
order.baseAssetAmount;
order.baseAssetAmountFilled;
order.oraclePriceOffset; // BN (i64) — always wrap in `new BN(...)` when constructing
order.reduceOnly;
order.bitFlags; // OrderBitFlag bitmask: postOnly / reduceOnly / HasBuilder / IsIsolatedPosition
}Spot balances and collateral
for (const position of userAccount.spotPositions) {
if (position.scaledBalance.isZero()) continue;
position.marketIndex;
position.balanceType; // { deposit: {} } | { borrow: {} }
position.scaledBalance; // SPOT_BALANCE_PRECISION (1e9); multiply by the market's cumulative interest for token amount
}
const totalCollateral = user.getTotalCollateral(); // BN, QUOTE_PRECISION (1e6)Decoding accounts without a subscription: VelocityCore
For read-only tooling (indexers, one-off scripts, serverless functions) where a fully subscribed VelocityClient is overkill, VelocityCore decodes accounts directly from an RPC fetch or a raw buffer:
import { VelocityCore } from "@velocity-exchange/sdk";
import { Connection } from "@solana/web3.js";
const connection = new Connection("<RPC_URL>");
// Fetch + decode a User account in one call, no subscription required
const userAccount = await VelocityCore.fetchUserAccount(connection, userAccountPublicKey);
// Or decode a buffer you already have (e.g. from a websocket account notification)
const decoded = VelocityCore.decodeUserAccount(rawAccountBuffer);
// PDA helpers (state, user, perp/spot market, vaults) are re-exported statically
const userPda = VelocityCore.pdas.getUserAccountPublicKeySync(programId, authority, 0);For account types beyond User, build a coder directly against the bundled IDL:
import { VelocityCore } from "@velocity-exchange/sdk";
const coder = VelocityCore.coder(); // defaults to VelocityCore.defaultIdl()
const perpMarket = coder.accounts.decode("perpMarket", rawAccountBuffer);IDL account names are camelCase in Anchor 1.0. Any string-keyed coder call must use 'perpMarket', 'spotMarket', 'user', 'userStats', 'state' — not the PascalCase Drift used with Anchor 0.29 ('PerpMarket', 'SpotMarket', …). Passing the old casing throws or silently returns undefined depending on the coder version.
MarketStatus discriminants shifted. Velocity’s surviving MarketStatus variants are Initialized (0), Active (1), ReduceOnly (2), Settlement (3), Delisted (4) — Drift had ReduceOnly (6), Settlement (7), Delisted (8). A raw/cached decoder built against Drift’s numbering will silently misread these. Always decode against the current sdk/src/idl/velocity.json, never a hardcoded enum copied from a Drift integration. PerpMarketAccount is also a different size (1304 bytes vs Drift’s 1216) — see Account Model for the full layout diff.
Market data
Oracle and mark prices
const oraclePriceData = velocityClient.getMMOracleDataForPerpMarket(0); // MMOraclePriceData
const perpMarket = velocityClient.getPerpMarketAccount(0);
perpMarket.marketStats; // mark/oracle TWAPs live here, not on the top-level PerpMarket
perpMarket.oracle; // top-level now (moved off amm.* in the AMM decoupling)
perpMarket.oracleSource;Orderbook (DLOB)
For a live L2/L3 orderbook, subscribe to the DLOB directly with the SDK’s SlotSubscriber / OrderSubscriber / DLOBSubscriber classes — see DLOB for the full setup sequence and Orderbook + DLOB websocket for the hosted DLOB server’s REST/websocket API if you’d rather not run your own DLOB.
Data API (REST)
The Data API provides historical and aggregate data via REST endpoints, without running your own indexer. Use it for dashboards, analytics, or any non-SDK integration.
Provisional endpoint. Velocity’s hosted Data API host is not yet finalized. The examples below use data.velocity.exchange as a placeholder pattern — confirm the real host before shipping against it. See Data API and the migration report’s open questions.
- Base URL (provisional):
https://data.velocity.exchange - Data API playground
Market stats
Returns aggregate stats for all markets — volume, open interest, funding rate, oracle price, and market status.
GET https://data.velocity.exchange/stats/marketsResponse shape:
[
{
"marketIndex": 0,
"symbol": "SOL-PERP",
"marketType": "perp",
"oraclePrice": 123.456,
"volume24h": 50000000.0,
"openInterest": 12000000.0,
"fundingRate": 0.00012,
"fundingRate24hAvg": 0.00010,
"status": "active"
}
]Funding rates
GET https://data.velocity.exchange/fundingRates?symbol=SOL-PERPTrades
GET https://data.velocity.exchange/trades?symbol=SOL-PERP&limit=100Query parameters:
symbol— Market symbol (required)limit— Max results (default varies, max typically 1000)pageIndex— For pagination
Note: Amounts are in protocol precision (base: 1e9, quote: 1e6). Divide accordingly for human-readable values. See the Data API glossary for the full column reference, and note that spot-fulfillment-related columns no longer apply (spot DLOB trading and external fulfillment are both removed on Velocity).
Fetching data in code
const marketsRes = await fetch("https://data.velocity.exchange/stats/markets");
const markets = await marketsRes.json();
for (const m of markets) {
console.log(`${m.symbol}: price=${m.oraclePrice} OI=${m.openInterest} funding=${m.fundingRate}`);
}
const tradesRes = await fetch(
"https://data.velocity.exchange/trades?symbol=SOL-PERP&limit=100"
);
const trades = await tradesRes.json();Function fetchReference ↗
Function fetchReference ↗fetch.DLOB + Swift for live order flow
For real-time orderbook and order flow, Velocity uses separate services (both hostnames below are provisional pending final infra naming):
- DLOB server (provisional:
https://dlob.velocity.exchange) — Orderbook snapshots and streaming. See Orderbook + DLOB websocket. - Swift server (provisional:
https://swift.velocity.exchange) — Signed message orders for fast execution. See Swift.