For the complete documentation index, see llms.txt. This page is also available as Markdown.

perpPrices

Stream the accepted oracle and mark prices of perps, one message per block.

Every live data message includes both routing identifiers with the same value:

{"type": "perpPrices", "channel": "perpPrices"}

Other payload fields are omitted above. Existing clients may continue routing on either field.

πŸ’§ New endpoint - this endpoint is not a part of original Hyperliquid API and is added by us for builder convenience.

The streaming counterpart of perpPriceHistoryByTime: the prices the exchange actually uses for margining and liquidation, on every dex including HIP-3. A row here is identical to the row the REST endpoint returns for the same block.

Subscribe

{
    "method": "subscribe",
    "subscription": {
        "type": "perpPrices",
        "coins": ["BTC", "xyz:GOLD"]
    }
}

Parameters:

Parameter
Type
Required
Description

coins

string[]

Yes

Coins to subscribe to, 1 to 200 per request. Use the dex-prefixed symbol for HIP-3 markets (e.g. xyz:GOLD).

Coins always merge. A connection holds one perpPrices subscription. Subscribing again unions the new coins into it β€” the next block is one frame covering the merged set, with no unsubscribe/resubscribe gap. The ack echoes the request; re-sending coins you already hold is a no-op. The merged set is bounded by your tier's coin cap.

The ack is the boundary. The ack is delivered after every frame that was already in flight when the change committed, so every frame after the ack covers the new set. Apply a coin-set change when the ack arrives, not when the request is sent.

Unsubscribe

Name coins to remove; the rest keep streaming without a gap. Omit coins to drop the whole subscription.

Update data format

A message is sent for every block (~70 ms), including blocks that carry no price round for your coins β€” prices is then []. That lets you track the chain height and time continuously, and seq is gap-free per connection so a missed message is detectable. Price rounds arrive roughly every 3 seconds per dex, so expect about one message in forty to carry rows.

A block carries at most one row per coin: when a dex publishes more than one round in a block, the last one is the accepted price, exactly as the REST endpoint reports it.

Field definitions

Field
Type
Description

height

int

Block height

timestamp

int

Block timestamp (ms since epoch)

prices

object[]

The block's accepted rounds for your coins; empty when there were none

prices[].time

int

Block timestamp of the oracle round (ms) β€” equals timestamp

prices[].blockNumber

int

Height of the block that committed the round β€” equals height

prices[].dex

string

DEX identifier ("hyperliquid" for the native dex)

prices[].coin

string

Trading pair

prices[].oraclePx

string?

Accepted oracle price. Omitted when the round carried no oracle slot for the asset (the natively-priced HYPE/PURR miss the slot in ~2 rounds a day)

prices[].markPx

string

Accepted mark price β€” the value used for margining, liquidations and funding. Always present

prices[].extPerpPx

string?

External perp reference price; omitted for assets without one

prices[].updateClass

string?

HIP-3 only: how the network sourced the round as reported by the node ("Deployer", "Fallback", "Normal"). Omitted for the native dex

Reconnect replay

Subscribe with the cursor of the last message you received (block:timestamp) and the server first sends a replay message covering up to 30 seconds of missed data, then the subscription ack, then live messages. Replay carries one item per block that had a round for your coins β€” the empty tick messages are not replayed; take the chain height from your first live message. hasGap: true on the replay means the cursor is older than the cache: fill the hole with perpPriceHistoryByTime, whose rows are identical to these. The replay message format is described in Session management and reconnection.

Limits

perpPrices is included in every tier. Your tier's coin cap bounds the coins per API key (10/100/200 for starter/growth/scale; higher bespoke limits are available β€” contact us), and each subscribed coin counts as one subscription toward your tier's total. A single request may name at most 200 coins.

Examples

Common errors

The subscription feedback and warning shapes are documented in the WebSocket overview. A well-formed but unknown or inactive coin succeeds with an inactive_coins warning and simply never produces rows.

  1. coins required for perpPrices subscription - Send at least one coin; there is no all-markets form yet

  2. Too many coins - More than 200 coins in one request, or the merge would push the set past your tier's coin cap; the existing subscription is left unchanged

  3. Rate limit exceeded - Reduce subscription frequency

  4. Authentication failed - Check API key

Last updated