> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agg.market/llms.txt
> Use this file to discover all available pages before exploring further.

# 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, AGG 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.

<Note>
  **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.
</Note>

## 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 AGG, 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

AGG 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")    ← member
```

So `GET /venue-events` returns **one row**, and `matchedVenueEvents[]` carries *two entries with
`venue: "hyperliquid"`*.

<Warning>
  **This is the one exception to "two events from the same venue never share a cluster."** That rule
  in [Matched Clusters](/recipes/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.
</Warning>

### Detecting it

Count Hyperliquid entries rather than assuming one:

```js theme={null}
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](/recipes/agg-key), 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[]`:

```bash theme={null}
curl -G "https://api.agg.market/orderbooks" \
  --data-urlencode "venueMarketIds=vm_abc,vm_def" \
  -H "x-app-id: $AGG_APP_ID"
```

```jsonc theme={null}
{
  "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**.

<Warning>
  **`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.
</Warning>

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.

<Note>
  **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.
</Note>

## 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[]` / `venueCount` on 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 `venueMarketId` through 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 from `venue` alone for Hyperliquid.

## Related

<CardGroup cols={2}>
  <Card title="Matched Clusters" icon="diagram-project" href="/recipes/matched-clusters">
    What a cluster is, which id to join on, and where each cluster field lives.
  </Card>

  <Card title="Comparing Venue Prices" icon="scale-balanced" href="/recipes/comparing-venue-prices">
    Fetch matched markets and their midpoints to build a cross-venue comparison.
  </Card>

  <Card title="WebSocket Orderbook" icon="bolt" href="/recipes/websocket-orderbook">
    Stream live depth instead of polling the batch endpoint.
  </Card>

  <Card title="Canonical Market Key (aggKey)" icon="key" href="/recipes/agg-key">
    What aggKey is, when it is null, and the one supported way to parse it.
  </Card>
</CardGroup>
