Migration

Migrating from QuickNode

Our endpoint is wire-compatible with QuickNode's Hyperliquid gRPC services — the hyperliquid.* proto package. Your generated stubs, message types, and decoding logic work unchanged: the migration is one endpoint string and one auth header, then a side-by-side validation run.

What stays the same

Every QuickNode-shape service is served, same package, same wire format. Nothing in this table requires a code change:

Service / methodCarriesStatus
hyperliquid.Streaming/StreamDataTRADES, ORDERS, BOOK_UPDATES, TWAP, EVENTS, BLOCKS stream typesunchanged
hyperliquid.OrderBookStreaming/StreamL2BookAggregated book, {coin, n_levels}, snapshot then per-block updatesunchanged
hyperliquid.OrderBookStreaming/StreamL4BookFull order-by-order book, snapshot + per-block diffsunchanged
hyperliquid.BlockStreaming/StreamBlocksRaw L1 block streamunchanged

gRPC reflection is enabled on our side too, so grpcurl … list and stub generation straight from the endpoint both work — see SDKs & protos.

The migration

  1. Swap the endpoint

    Wherever your client constructs its channel, replace the QuickNode endpoint with ours. TLS over HTTP/2, port 443:

    grpc endpointdiff
    removed: ENDPOINT = "your-current-quicknode-endpoint:443"
    added: ENDPOINT = "stream.hyperliquidrpc.com:443"
  2. Move auth to x-api-key metadata

    Authentication is an API key sent as gRPC metadata on each call — replace whatever credential mechanism your QuickNode setup used with the x-api-key pair. Keys come from the console; see Authentication.

    client.pydiff
    removed: channel = grpc.secure_channel(ENDPOINT, grpc.ssl_channel_credentials())
    removed: stub = StreamingStub(channel)
    removed: stream = stub.StreamData(request)
    added: channel = grpc.secure_channel(ENDPOINT, grpc.ssl_channel_credentials())
    added: stub = StreamingStub(channel)
    added: stream = stub.StreamData(request, metadata=(("x-api-key", "YOUR_KEY"),))
  3. Check your channel options

    Two settings bite migrators in production rather than in the first test:

    • Message size. First messages on L4/book streams are full snapshots and can be large — set max receive message size to at least 256 MB.
    • Reconnects. Streams are long-lived but not eternal. Reconnect with backoff; a DATA_LOSS status means your consumer fell behind — reconnect, optionally replaying from a block height to backfill the gap.
    channel = grpc.secure_channel(    "stream.hyperliquidrpc.com:443",    grpc.ssl_channel_credentials(),    options=[        # full L4/book snapshots can exceed default limits — allow >=256 MB        ("grpc.max_receive_message_length", 268_435_456),    ],)
  4. Validate side by side

    Run both endpoints in parallel before cutting over. Trades carry a globally unique tid and every message carries its block height, so per-block equality is a one-screen script:

    validate.pypython
    # run both providers in parallel and diff per-block content.# uses the stubs you already generated — field names per your proto version.import grpc OLD = "your-current-quicknode-endpoint:443"NEW = "stream.hyperliquidrpc.com:443" def trades(endpoint, metadata=()):    channel = grpc.secure_channel(        endpoint,        grpc.ssl_channel_credentials(),        options=[("grpc.max_receive_message_length", 268_435_456)],    )    stub = StreamingStub(channel)    req = StreamDataRequest(stream_type=TRADES, coins=["BTC"])    return stub.StreamData(req, metadata=metadata) old = trades(OLD)                                          # existing authnew = trades(NEW, metadata=(("x-api-key", "YOUR_KEY"),))   # ours # align on a common block height, then compare trade ids per blockfor a, b in zip(old, new):    assert a.block_height == b.block_height, (a.block_height, b.block_height)    assert {t.tid for t in a.trades} == {t.tid for t in b.trades}    print("block", a.block_height, "ok:", len(a.trades), "trades")

    Let it run through a busy period, then cut over by deleting the old endpoint. Keep the validator around — it is also a fine canary for your own consumer's health.

What you gain

The point of the move is not just parity. Same stubs, more surface:

  • Attribution on every fill — trader wallet, realized PnL (closed_pnl), fee and rebate flag, maker/taker, and position context on the trades stream.
  • Replay from height — start any stream from a past block to backfill, then continue live without a gap.
  • Server-side filtering — subscribe by coins, wallets, and market_type; pay bandwidth only for what you take.
  • The historical archive, same schema — 1.65B+ order events and 1B+ book updates, queryable with the field names your live code already uses.
  • Extra native streams — the flat hyperliquid_swaps.v1 trade schema and the dedicated BTC price ticker.

Also moving RPC?

The same key serves HyperEVM JSON-RPC (standard eth_* set including eth_sendRawTransaction) and the HyperCore /info API — point your existing JSON-RPC client at https://rpc.hyperliquidrpc.com with the x-api-key header and you are done.