Skip to main content

Connect

caution
  • The V3 version of the public channel push is expected to go offline on September 23, 2025
  • please complete the switch as soon as possible(Private channel v3 Unchanged)
  • Please note: The following fields: tickDirection,price24hPcnt,fundingRate,bid1Price,bid1Size,ask1Price,ask1Size,V3 Even if there is no change, it will be pushed. V5 only pushes when there is a change

WebSocket public channel:

  • Mainnet:
    Spot: wss://stream.zoomex.com/v5/public/spot
    USDT perpetual: wss://stream.zoomex.com/v5/public/linear
    Inverse contract: wss://stream.zoomex.com/v5/public/inverse

  • Testnet:
    Spot: wss://stream-testnet.zoomex.com/v5/public/spot
    USDT perpetual: wss://stream-testnet.zoomex.com/v5/public/linear
    Inverse contract: wss://stream-testnet.zoomex.com/v5/public/inverse

WebSocket private channel:

  • Mainnet:
    wss://stream.zoomex.com/v3/private

  • Testnet:
    wss://stream-testnet.zoomex.com/v3/private

Authentication​

info
Public topics do not require authentication. The following section applies to private topics only.

Apply for authentication when establishing a connection.

{
"req_id": "10001", // optional
"op": "auth",
"args": [
"api_key",
1662350400000, // expires; is greater than your current timestamp
"signature"
]
}

Successful authentication sample response

{
"success": true,
"ret_msg": "",
"op": "auth",
"conn_id": "cejreaspqfh3sjdnldmg-p"
}
note

Example signature algorithms as following.

import hmac
import json
import logging
import time


def send_auth():
key = 'XXXXXXXX'
secret = 'XXXXXXXX'
expires = int((time.time() + 1000) * 1000)
_val = f'GET/realtime{expires}'
print(_val)
signature = str(hmac.new(
bytes(secret, 'utf-8'),
bytes(_val, 'utf-8'), digestmod='sha256'
).hexdigest())
print(json.dumps({"op": "auth", "args": [key, expires, signature]}))


if __name__ == "__main__":
send_auth()
caution

Due to network complexity, your may get disconnected at any time. Please follow the instructions below to ensure that you receive WebSocket messages on time:

  1. Keep connection alive by sending the heartbeat packet
  2. Reconnect as soon as possible if disconnected

IP Limits​

  • Do not frequently connect and disconnect the connection.
  • Do not build over 500 connections in 5 minutes. This is counted separately per WebSocket endpoint.

Public channel - Args limits​

For one public connection, you cannot have length of "args" array over 21,000 characters.

How to Send the Heartbeat Packet​

How to Send

// req_id is a customised ID, which is optional
ws.send(JSON.stringify({"req_id": "100001", "op": "ping"}));

Pong message example of public channels

{
"success": true,
"ret_msg": "pong",
"conn_id": "465772b1-7630-4fdc-a492-e003e6f0f260",
"req_id": "",
"op": "ping"
}

Pong message example of private channels

{
"req_id": "test",
"op": "pong",
"args": [
"1675418560633"
],
"conn_id": "cfcb4ocsvfriu23r3er0-1b"
}
caution

To avoid network or program issues, we recommend that you send the ping heartbeat packet every 20 seconds to maintain the WebSocket connection.

How to Subscribe to Topics​

Understanding WebSocket Filters​

How to subscribe with a filter

// Subscribing level 1 orderbook
{
"req_id": "test", // optional
"op": "subscribe",
"args": [
"orderbook.1.BTCUSDT"
]
}

Subscribing with multiple symbols and topics is supported.

{
"req_id": "test", // optional
"op": "subscribe",
"args": [
"orderbook.1.BTCUSDT",
"publicTrade.BTCUSDT",
"orderbook.1.ETHUSDT"
]
}

Understanding WebSocket Filters: Unsubscription​

You can dynamically subscribe and unsubscribe from topics without unsubscribing from the WebSocket like so:

{
"op": "unsubscribe",
"args": [
"publicTrade.ETHUSD"
],
"req_id": "customised_id"
}

Understanding the Subscription Response​

Topic subscription response message example

{
"success": true,
"ret_msg": "",
"op": "subscribe",
"conn_id": "cejreassvfrsfvb9v1a0-2m"
}