Documentation Index
Fetch the complete documentation index at: https://docs.phoenix.trade/llms.txt
Use this file to discover all available pages before exploring further.
Connection
Connect to the Phoenix WebSocket endpoint:
wss://perp-api.phoenix.trade/v1/ws
The Rust SDK uses PHOENIX_WS_URL when it is set. Otherwise, it derives the WebSocket URL from PHOENIX_API_URL by switching http to ws and using /v1/ws.
Messages are UTF-8 JSON objects.
Client messages
Subscribe with a type and subscription envelope:
{
"type": "subscribe",
"subscription": {
"channel": "orderbook",
"symbol": "SOL"
}
}
Unsubscribe with the same subscription object:
{
"type": "unsubscribe",
"subscription": {
"channel": "orderbook",
"symbol": "SOL"
}
}
Supported channels
| Channel | Subscription fields | Response type |
|---|
allMids | none | AllMidsData |
exchange | optional encoding | ExchangeMessage |
fundingRate | symbol | FundingRateMessage |
orderbook | symbol, optional bypassExecutionBand | L2BookUpdate |
traderState | authority, traderPdaIndex | TraderStateServerMessage |
market | symbol | MarketStatsUpdate |
trades | symbol | TradesMessage |
candles | symbol, timeframe | CandleData |
Control responses
The server confirms successful subscriptions with a subscriptionConfirmed message:
{
"type": "subscriptionConfirmed",
"subscription": {
"channel": "orderbook",
"symbol": "SOL"
}
}
Subscription-level errors use subscriptionError:
{
"type": "subscriptionError",
"subscription": {
"channel": "orderbook",
"symbol": "SOL"
},
"code": "invalid_subscription",
"message": "invalid subscription"
}
Server errors use the error channel:
{
"channel": "error",
"code": 400,
"error": "unknown channel"
}
Market subscriptions
Exchange
Use the exchange channel to keep local exchange and market-parameter metadata in sync. The server sends an initial snapshot followed by ordered deltas when exchange keys, exchange status, markets, or market parameters change.
{
"type": "subscribe",
"subscription": {
"channel": "exchange",
"encoding": "json"
}
}
The encoding field is optional. Omit it to use the default compressed snapshot response:
{
"channel": "exchange",
"messageType": "encodedSnapshot",
"version": 1,
"sequenceNumber": "123",
"slot": 123456789,
"slotIndex": 0,
"reason": "snapshot",
"encoding": "base64+zstd",
"payload": "..."
}
Set encoding to json to receive the initial snapshot as JSON. The examples below are abbreviated to show the fields relevant to cache synchronization:
{
"channel": "exchange",
"messageType": "snapshot",
"version": 1,
"sequenceNumber": "123",
"slot": 123456789,
"slotIndex": 0,
"reason": "snapshot",
"exchange": {
"programId": "program-pubkey",
"globalConfig": "global-config-pubkey",
"active": true,
"gated": false
},
"markets": [
{
"symbol": "SOL",
"assetId": 1,
"marketStatus": "active",
"marketPubkey": "market-pubkey",
"splinePubkey": "spline-pubkey"
}
]
}
After the snapshot, apply each delta with the next sequenceNumber to your local cache. If a sequence number is skipped, resubscribe and rebuild from a fresh snapshot.
{
"channel": "exchange",
"messageType": "delta",
"version": 1,
"sequenceNumber": "124",
"slot": 123456790,
"slotIndex": 0,
"ops": [
{
"kind": "marketAdded",
"market": {
"symbol": "ETH",
"assetId": 2,
"marketStatus": "active",
"marketPubkey": "market-pubkey",
"splinePubkey": "spline-pubkey"
}
},
{
"kind": "marketClosed",
"symbol": "SOL",
"previous_market_status": "active",
"finalized_mark_price": "150000000"
}
]
}
Handle exchange deltas as cache mutations:
| Delta kind | Sync behavior |
|---|
marketAdded | Add or replace the market config in the local market map. |
marketStatusChanged | Update the market’s marketStatus. |
marketClosed | Mark the market as closed and retain the finalized mark price if your client needs settlement context. |
marketTombstoned | Mark the market as tombstoned and stop treating it as tradeable. |
marketDeleted | Remove the market from the local market map. |
marketParameterUpdated | Patch the market’s risk, funding, fee, cap, or commodity metadata fields from the update payload. |
exchangeStatusChanged | Update exchange-level active, gated, and status feature flags. |
exchangeKeysUpdated | Replace exchange-level account and authority keys. |
All mids
{
"type": "subscribe",
"subscription": {
"channel": "allMids"
}
}
{
"channel": "allMids",
"mids": {
"SOL": 150.25,
"BTC": 65000.5
},
"slot": 123456789,
"slotIndex": 0
}
Funding rate
{
"type": "subscribe",
"subscription": {
"channel": "fundingRate",
"symbol": "SOL"
}
}
{
"channel": "fundingRate",
"symbol": "SOL",
"funding": 0.0000125
}
Orderbook
Set bypassExecutionBand to true to receive the full orderbook during commodities after-hours, including price levels outside the tradeable execution band.
{
"type": "subscribe",
"subscription": {
"channel": "orderbook",
"symbol": "SOL",
"bypassExecutionBand": false
}
}
{
"channel": "orderbook",
"symbol": "SOL",
"orderbook": {
"bids": [[150.25, 100.0], [150.2, 200.0]],
"asks": [[150.3, 150.0], [150.35, 250.0]],
"mid": 150.275
},
"bypassExecutionBand": false
}
Market stats
{
"type": "subscribe",
"subscription": {
"channel": "market",
"symbol": "SOL"
}
}
{
"channel": "market",
"symbol": "SOL",
"openInterest": 1000.0,
"markPx": 150.1,
"midPx": 150.12,
"oraclePx": 150.0,
"prevDayPx": 148.7,
"dayNtlVlm": 2500000.0,
"funding": 0.0000125
}
Trades
{
"type": "subscribe",
"subscription": {
"channel": "trades",
"symbol": "SOL"
}
}
{
"channel": "trades",
"symbol": "SOL",
"trades": [
{
"slot": "123456789",
"slotIndex": 5,
"timestamp": "1775578550",
"symbol": "SOL",
"taker": "taker-pubkey",
"tradeSequenceNumber": "100",
"side": "bid",
"baseLotsFilled": "1000",
"quoteLotsFilled": "150000",
"feeInQuoteLots": "30",
"baseAmount": 10.0,
"quoteAmount": 1500.0,
"numFills": 2
}
]
}
Candles
Supported timeframes are 1s, 5s, 1m, 5m, 15m, 30m, 1h, 4h, and 1d.
{
"type": "subscribe",
"subscription": {
"channel": "candles",
"symbol": "SOL",
"timeframe": "1m"
}
}
The server sends candle updates with channel set to candle:
{
"channel": "candle",
"symbol": "SOL",
"timeframe": "1m",
"candle": {
"time": 1727181985,
"low": 149.8,
"high": 151.5,
"open": 150.25,
"close": 150.9,
"volume": 1234.56,
"tradeCount": 89
}
}
Trader subscriptions
Trader state
{
"type": "subscribe",
"subscription": {
"channel": "traderState",
"authority": "wallet-pubkey",
"traderPdaIndex": 0
}
}
Trader state messages are either snapshot or delta payloads.
{
"channel": "traderState",
"authority": "wallet-pubkey",
"traderPdaIndex": 0,
"slot": 123456789,
"messageType": "snapshot",
"version": 1,
"capabilities": {
"flags": 63,
"state": "active",
"capabilities": {
"placeLimitOrder": { "immediate": true },
"placeMarketOrder": { "immediate": true },
"riskIncreasingTrade": { "immediate": true },
"riskReducingTrade": { "immediate": true },
"depositCollateral": { "immediate": true },
"withdrawCollateral": { "immediate": true }
}
},
"makerFeeOverrideMultiplier": 1.0,
"takerFeeOverrideMultiplier": 1.0,
"subaccounts": []
}
{
"channel": "traderState",
"authority": "wallet-pubkey",
"traderPdaIndex": 0,
"slot": 123456790,
"messageType": "delta",
"deltas": [
{
"subaccountIndex": 0,
"sequence": 42,
"collateral": "1000000",
"positions": [],
"orders": [],
"splines": [],
"tradeHistory": [],
"orderHistory": []
}
]
}