closedPnl, dir and startPosition already on it. Frame shapes mirror Hyperliquid’s own websocket API, so existing Hyperliquid client code is familiar. Twenty-one feeds are live today, five of them multi-wallet lists that follow up to 1,000 addresses on a single subscription. Live OHLC candles for any coin on any of 14 intervals are on every plan. Pro accounts can also stream the full L4 order book of any coin — every resting order with its wallet, as one snapshot followed by per-block diffs — through the l4Book feed, plus every liquidation as it happens, every accepted leverage and isolated-margin change, and the node’s own TWAP state machine, which opens with a snapshot of the TWAPs running right now.
It is the third way into the same data, beside the REST API and the MCP server, and it uses the same API key. It is also a different protocol with its own rules: auth travels on the upgrade rather than in an X-API-Key header, refusals are HTTP statuses or close codes rather than problem details, and limits are capacity — connections and subscriptions — never per message. This section states those rules in full; the REST pages point here rather than repeating them.
Endpoint: wss://ws.coinversa.ai
Reference in the portal: developers.coinversa.ai/websockets
Connecting
Open the socket with your key on the HTTP upgrade, then send onesubscribe frame per feed you want. The server acknowledges each and pushes a data frame whenever matching fills land in a block. Nothing is polled, and by default nothing is replayed on connect — you receive fills from the moment you subscribe onward. Pass a sequence to resume where a dropped connection left off instead.
Every connection needs a key, including Free. There is no anonymous tier and no auth frame to send once the socket is open. The request path is ignored — /, /ws and /stream all upgrade the same.
Authentication
The key goes out with the upgrade request, so the socket is already authenticated by the time it opens. There are two places it can travel, and which one you use is decided by your runtime, not by preference.Servers: Authorization header
Node, Python, Go, and anything else that can set request headers sends
Authorization: Bearer cvsa_... on the upgrade. The Bearer scheme token is case-sensitive.Browsers: bearer subprotocol
A browser
WebSocket cannot set headers, so it offers the key as the second subprotocol after the literal bearer:
new WebSocket(url, ['bearer', key]). The server selects and echoes bearer; the key is never echoed.Authorization header is refused even if a valid subprotocol rides beside it; the subprotocol is read only when the header is absent. The key is never accepted in the URL — ?token=, ?apiKey= and ?key= are refused exactly like no key at all, and a key in a URL is a key in every access log between you and us.
The first frame
The first frame on every live connection isconnected, and its limits are what this account may do: how many connections it may hold in total, how many concurrent subscriptions per connection, and which feeds its tier includes. They are the account’s resolved numbers — enterprise overrides already applied — so read them back rather than hard-coding your plan. The tier is fixed for the life of the socket; moving to another key or plan means reconnecting.
When the handshake is refused
A refused key is fatal to the connection: the upgrade never completes, no socket exists, and nothing you write in a message handler will run. This is a different code path from theerror channel, and it is the one most clients get wrong.
A browser cannot read the status of a refused upgrade, so for a subprotocol client the handshake completes and the socket is closed at once with the verdict as a close code — the HTTP status plus 4000 — and the same reason text. These close codes are a public wire contract; match on them. A
1006 with no reason is the browser saying the handshake itself failed or the link dropped, and it will not say which.
No Retry-After comes with a 429, and a connection that died silently can hold its slot until keepalive notices — roughly 40 seconds. Client libraries that hide the response surface a refused upgrade as close code 1002, reason Expected 101 status code, with zero frames received; pick an API that hands you the status.
Where to go next
Quickstart
A complete client in Browser, Node, Python or Go — reconnect, resubscribe, sequence ordering, heartbeat.
Feeds and the fill object
The firehose, one coin, one wallet, a list of wallets, liquidations, leverage changes, candles, the order book, the three TWAP views — and every field on a fill.
Wire protocol
Every frame, the exact error strings, and how sequence numbers work.
Plan limits
Connections per account, subscriptions per connection, fair-use bandwidth.

