# Optimizing latency

Run three sockets and keep account snapshots and market data out of the
order-entry loop.

| Path | Purpose | Client key |
| --- | --- | --- |
| [`/v1/exchange/ws`](/api/exchange-websocket) | Place, modify, cancel | frame `id` |
| [`/v1/exchange/ws`](/api/exchange-websocket#maintenance-announcements) `maintenance` | Venue maintenance announcements | `topic`, then source `venue` |
| [`/v1/ws`](/api/websocket) `orderUpdates` | Order lifecycle | `cloid` |
| [`/v1/ws`](/api/websocket) `userFills` | Confirmed executions | `(venue, fillId)` |
| [`/v1/ws`](/api/websocket) `clearinghouseState` | Market catalog and account state | `data.type` |
| [`/v1/market-data/ws`](/api/market-data-websocket) `bbo`, `l2Book` | Market data | `(topic, venue, coin)` |

:::warning\[Hyperliquid only]
The low-latency path is validated for `hyperliquid` venues. Lighter is
supported by the same API without these latency expectations.
:::

## Order entry

1. Send one order per frame and pipeline independent frames without waiting
   for responses. Keep at most 128 requests in flight per client IP, across
   all connections from that IP. On `inflight_limit_exceeded`, wait for
   outstanding requests to complete before retrying. Mosaiq can close the
   connection if it cannot deliver the refusal. If a response is missing,
   follow [disconnect recovery](#disconnect-recovery) before resending.
2. Give every order frame a unique increasing `id` and match responses by
   `data.id`. Completion order is not guaranteed.
3. Give every placement a fresh `cloid`: `0x` plus 32 lowercase hex digits,
   not all zero.
4. Send a dependent cancel or modify on the same connection, after its place,
   with the same `cloid`. Ordering is keyed by `(venue, cloid)`; a single-item
   Hyperliquid cancel can stop a pending placement before it is sent.
   See [Ordering](/api/exchange-websocket#ordering) for the exact contract.
5. Use a library that answers server Pings with the same payload on all three
   sockets.

On the execution socket, route `topic: "maintenance"` separately from
`channel: "post"` order responses. Maintenance snapshots replace the complete
source array and do not confirm order outcomes. Subscribe again after an
execution-socket reconnect.

A batch is not atomic and its items are answered by index; separate pipelined
frames are correlated by `id`.

## Lifecycle processing

Keep `/v1/ws` subscribed to `orderUpdates` and `userFills` and keep reading it
even when the strategy ignores messages. Write responses and lifecycle events
are independent, so an `orderUpdates` event can arrive before the matching
write response. Key orders by `cloid`, fills by `(venue, fillId)`, accept
duplicates, and make every transition idempotent. A successful write response
is an acknowledgement, not a fill. It says that Mosaiq launched the venue send.
The venue's answer reaches you only on `orderUpdates`, so time a write to its
first `orderUpdates` row when you compare venues.

`clearinghouseState` sends four snapshots on subscribe, then only the chunks
whose contents changed. Silence means unchanged, not disconnected. Set
`subscription.markets` to the assets your strategy uses to limit market data.
Keep the latest value of each `data.type` and never use these messages to
confirm individual orders. No topic orders events relative to another topic.

## Disconnect recovery

A dropped connection does not say whether the last frame reached Mosaiq. Do
not resend immediately.

1. Reconnect with backoff.
2. Subscribe again and buffer the new `orderUpdates` and `userFills` messages.
3. Backfill [`GET /v1/userFills`](/api/user-fills), following its cursor and
   deduplicating by `(venue, fillId)`.
4. Query [`GET /v1/openOrders?cloid=<cloid>`](/api/open-orders) for each
   ambiguous order.
5. Reconcile before retrying or replacing. A replacement placement needs a
   new `cloid`.

## Network placement

Measure round-trip time from the host that will run the strategy and reuse
established sockets so DNS, TCP, TLS, and authentication stay off the
per-order path. Private VPC peering is available on request during onboarding.
Mosaiq does not guarantee a specific latency; benchmark the full
client-to-venue path from the host you will use for trading.
