Hyperliquid Deployers
Why one Hyperliquid market can be listed twice, how to tell the listings apart, and which book you are actually reading
Hyperliquid markets are listed by deployers — independent HIP-4 publishers, each identified by a
short namespace (ap, aq, …). Two deployers can list the same real-world market independently.
When they do, sufwan-local-test sees two Hyperliquid listings of one question.
This page covers how those listings surface, how to tell them apart, and the one place where treating them as interchangeable will give a user depth they cannot trade against.
Availability. The deployerVenue field and cross-deployer clustering described below ship
together and stay dormant until Hyperliquid mainnet migrates to its template model. Until then
deployerVenue is null on every row of every venue, and Hyperliquid lists one deployer per
market — so the "today" behaviour in this page is what you will observe. Build against both
shapes; the transition happens without an API version change.
What a deployer is
On Hyperliquid, the venue does not publish markets — deployers do. Each deployer runs its own contracts and its own orderbook. Two deployers listing "Arsenal vs Chelsea" are publishing two distinct, non-fungible instruments: separate tokens, separate books, separate settlement.
That is the critical property. Everywhere else in sufwan-local-test, two listings of the same question live on different venues, and a user picks one. Here they live on the same venue, and the distinction is the deployer namespace.
How duplicate listings surface
sufwan-local-test clusters the two Hyperliquid listings together through a non-Hyperliquid anchor. If the same market is also on Polymarket, both Hyperliquid listings match Polymarket, and transitively land in one cluster:
Matched cluster
├── venueEvent (polymarket) ← anchor
├── venueEvent (hyperliquid, deployer "ap") ← member
└── venueEvent (hyperliquid, deployer "aq") ← memberSo GET /venue-events returns one row, and matchedVenueEvents[] carries two entries with
venue: "hyperliquid".
This is the one exception to "two events from the same venue never share a cluster." That rule
in Matched Clusters holds for every venue including Hyperliquid's
companion events — but not for Hyperliquid deployers. If your code asserts venue-uniqueness
within matchedVenueEvents[], or keys a map by venue, it will silently drop one listing.
Detecting it
Count Hyperliquid entries rather than assuming one:
const hlMembers = event.matchedVenueEvents.filter((m) => m.venue === "hyperliquid");
if (hlMembers.length > 1) {
// Same question, multiple deployers. Their books are not interchangeable.
}The same applies one level down: a market's matchedVenueMarkets[] can carry more than one
venue: "hyperliquid" sibling.
When they do not cluster
Cross-deployer clustering needs the non-Hyperliquid anchor. Two deployers listing a market that
no other venue carries have no middle node, so they stay two separate clusters — two rows from
GET /venue-events, two tiles.
This is expected, not a gap. Hyperliquid-only markets are the common case for long-tail listings.
If you need to collapse those in your own UI, group on aggKey — with
its caveats, chiefly that it is null for a substantial share of rows.
Naming the deployer
deployerVenue is exposed on the orderbook batch response, not on discovery rows. Request the
cluster's market ids and read it off matchedMarkets[]:
const { data } = await client.getOrderbooks({ venueMarketIds: ["vm_abc", "vm_def"] });
const deployers = data[0]?.matchedMarkets?.map((m) => m.deployerVenue);Full shape on Get live orderbooks for multiple markets.
{
"data": [
{
"venueMarketId": "vm_abc",
"status": "ok",
"matchedMarkets": [
{ "venue": "polymarket", "venueMarketId": "vm_abc", "hasOrderbook": true, "deployerVenue": null },
{ "venue": "hyperliquid", "venueMarketId": "vm_def", "hasOrderbook": true, "deployerVenue": "ap" },
{ "venue": "hyperliquid", "venueMarketId": "vm_ghi", "hasOrderbook": true, "deployerVenue": "aq" }
],
"venueOrderbooks": {
"polymarket": { "venueMarketId": "vm_abc", "orderbook": { "bids": [], "asks": [] }, "deployerVenue": null },
"hyperliquid": { "venueMarketId": "vm_def", "orderbook": { "bids": [], "asks": [] }, "deployerVenue": "ap" }
}
}
]
}deployerVenue is null for every non-Hyperliquid venue, and null for Hyperliquid listings that
carry no deployer namespace.
Reading the right book
Note the asymmetry in the response above: matchedMarkets[] has three entries, venueOrderbooks
has two.
venueOrderbooks is keyed by bare venue name, so it holds at most one Hyperliquid book. When a
cluster has two deployer members, exactly one member's book is published. venueOrderbooks.hyperliquid.deployerVenue
and .venueMarketId name which one.
Never pair venueOrderbooks.hyperliquid's depth with a venueMarketId taken from
matchedMarkets[]. If you place an order against deployer aq using depth read from deployer
ap's book, the liquidity you sized against does not exist on the contract you are trading.
Two fields keep this straight:
| Field | Scope | What it tells you |
|---|---|---|
matchedMarkets[].hasOrderbook | that member | Whether that specific deployer has a live book. Computed per member — it is not "is there a Hyperliquid book in the map". |
venueOrderbooks.hyperliquid.deployerVenue | the published book | Which deployer the depth in this entry belongs to. |
Which member gets published is deterministic (lowest venueMarketId), so it does not flip between
polls while cluster membership is unchanged — but treat it as an implementation detail and read
deployerVenue rather than assuming.
Depth is never summed across deployers. Two deployers' tokens are not fungible, so a combined book would show aggregate liquidity that no single order can reach. Each entry is one deployer's real, executable depth.
Practical guidance
- Rendering a venue badge row — de-duplicate by venue. Two Hyperliquid members are still "one
venue" from a badge's point of view, and
venues[]/venueCounton the event row already reflect that. - Rendering a price comparison — do not de-duplicate. Each deployer is a separately tradeable price; collapsing them hides a real execution choice from the user.
- Executing — carry the specific
venueMarketIdthrough from quote to order. That id, not the venue name, identifies what gets traded. - Persisting —
(venue, externalIdentifier)remains the durable handle, and it already distinguishes deployers. Do not build a key fromvenuealone for Hyperliquid.
Related
Matched Clusters
What a cluster is, which id to join on, and where each cluster field lives.
Comparing Venue Prices
Fetch matched markets and their midpoints to build a cross-venue comparison.
WebSocket Orderbook
Stream live depth instead of polling the batch endpoint.
Canonical Market Key (aggKey)
What aggKey is, when it is null, and the one supported way to parse it.