Real-time market data and account updates via WebSocket.
Connection
| Environment | URL |
|---|---|
| Testnet | wss://ws.testnet.rise.trade/ws |
| Mainnet | wss://ws.rise.trade/ws |
Authentication
Authentication is required before subscribing to private channels (orders, positions). Public channels (orderbook) can be subscribed without authentication.
Authentication Request
{
"method": "auth",
"params": {
"account": "0x1234567890123456789012345678901234567890",
"signer": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
"message": "Please sign in with your wallet to access rise.trade. You are signing in on 2025-01-15 12:00:00 (GMT). This message is exclusively signed with rise.trade for security.",
"nonce": 1736942400,
"signature": "0x..."
}
}| Parameter | Type | Required | Description |
|---|---|---|---|
account | string | Yes | Your main Ethereum wallet address |
signer | string | Yes | Session key address (must be registered on-chain) |
message | string | Yes | Human-readable message that was signed |
nonce | number | Yes | Unix timestamp in seconds (must be within ±60 seconds of server time) |
signature | string | Yes | EIP-712 signature in hex format |
Authentication Response
Success:
{
"method": "auth",
"status": "success",
"message": "Authentication successful",
"data": {
"account": "0x1234567890123456789012345678901234567890",
"signer": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"
}
}Error:
{
"method": "auth",
"status": "error",
"message": "session key not active (status: 0)"
}Subscription Format
Subscribe
{
"method": "subscribe",
"params": {
"channel": "<channel_name>",
"market_ids": [1, 2],
"makers": ["0x..."]
}
}| Parameter | Type | Required | Description |
|---|---|---|---|
channel | string | Yes | Channel name: orders, orderbook, positions, trades, or oracle |
market_ids | number[] | No | Filter by market IDs. Empty or omitted = all markets |
makers | string[] | No | Filter by account addresses. Empty or omitted = all accounts |
Unsubscribe
{
"method": "unsubscribe",
"params": {
"channel": "<channel_name>"
}
}Subscription Response
{
"method": "subscribe",
"status": "success",
"message": "Subscribed to orders",
"channel": "orders",
"data": {
"market_ids": [1, 2],
"makers": ["0x1234567890123456789012345678901234567890"]
}
}Available Channels
| Channel | Auth Required | Description | Filters |
|---|---|---|---|
orderbook | No | Real-time orderbook updates with snapshots | market_ids |
trades | No | Every trade as it is matched | market_ids |
oracle | No | Mark and index prices, once per block | market_ids |
orders | Yes | Real-time order updates with snapshots | market_ids, makers |
positions | Yes | Real-time position updates with snapshots | market_ids, makers |
funding | Yes | Funding payments as they settle | market_ids, makers |
fills | Yes | Your own fills, always scoped to your account | market_ids |
Message Types
Channel data carries a type field: snapshot (full state at subscription time) or update (incremental change).
Replies to your own requests are shaped differently and carry a status field instead — including one trap worth knowing: a rejected subscribe still comes back as "type": "subscribed" with "status": "error". See Messages for every envelope shape.
Common Fields
Channel messages share one envelope:
| Field | Type | Present on | Description |
|---|---|---|---|
channel | string | every message | Channel name |
type | string | every message | snapshot or update |
market_id | string | updates | Market ID. Omitted on orders / positions snapshots, null on oracle |
data | array | object | every message | Channel-specific payload |
block_number | number | updates | Block that produced the event |
log_index | number | updates | Log index within that block |
tx_hash | string | updates, when the event came from a transaction | Transaction hash. positions updates do not carry one |
worker_timestamp | string | every message | Server time in nanoseconds when the message was built |
Snapshots add method: "snapshot" plus a count field: level_count (orderbook), order_count (orders), position_count (positions).
There is notimestampand noblock_timestampOlder revisions of this page listed both. Neither is on the wire — the only server clock in a channel message is
worker_timestamp, in nanoseconds. Block time must be read from the REST API byblock_number.
Re-subscription Behavior
Re-subscribing to the same channel replaces the previous subscription filters. To receive events from multiple markets, specify all market IDs in a single subscription.
Price and Size Format
Numbers are strings on every channel, but the scale is not the same everywhere:
| Channel | Format | Example |
|---|---|---|
orderbook, trades, orders, positions, fills, funding | Decimal, human-readable | "63250.4", "0.00079" |
oracle | Integer wei (18 decimals) | "63126084821834306372811" |
Do not divide a decimal channel by 1018 — orderbook and oracle quote the same market in different scales in the same session.
Market IDs
| Market ID | Symbol |
|---|---|
| 1 | BTC-PERP |
| 2 | ETH-PERP |
Error Handling
{
"method": "subscribe",
"status": "error",
"message": "authentication required",
"channel": "orders"
}Health Checks
The server sends ping messages every 30 seconds. Respond with pong to keep the connection alive. Connections timeout after 60 seconds of inactivity.