---
updatedAt: 2025-12-25T02:48:54.000Z
---

Fetch the complete documentation index at: https://developer.rise.trade/llms.txt. Use this file to discover all available pages before exploring further.

# Orderbook

WebSocket orderbook channel with CRC32 checksum verification for data integrity.

**Channel: `book`**

The `book` channel provides updates on the order book with built-in data integrity verification. One snapshot of the orderbook is returned upon subscribing and every minute after that.

Subsequently, updates are streamed to the consumer *every 25ms* where `bids` and `asks` contain updates to the order-book (with the new sizes if there are changes to a price level). If there is no update, nothing is returned to the client.

Each orderbook message includes a **checksum** field for verifying data integrity using Aevo-compatible CRC32 algorithm.

## Basic Usage

```json Terminal
// npm install -g wscat first if needed
wscat -c wss://ws.dev.rise.trade/ws -x '{"op":"sub","channel":"book","product":"BTC-PERP"}'
{"type":"message", "connection_id":"dae030e0-7791-4c6f-a7c5-f38dc4fb2ab3"}
{"channel":"book","product":"BTC-PERP","type":"subscribed"}
{"channel":"book","product":"BTC-PERP","type":"snapshot","data":{"bids":[["64648","0.772"],["64646","0.775"],["64644","1.377"],["64642","0.94"],["64641","0.998"],["64639","0.909"],["64636","0.776"],["64635","0.912"],["64631","2.252"],["64626","1.177"],["64625","0.984"],["64623","1.209"],["64620","1.021"],["64618","1.135"],["64616","0.817"],["64613","1.159"],["64611","1.479"],["64609","1.135"],["64606","1.199"],["64604","0.958"],["64602","1.348"],["64601","1.006"],["64599","1.385"],["64597","1.297"],["64596","0.953"],["64591","0.982"],["64590","1.199"]],"asks":[["64655","0.792"],["64661","1.175"],["64663","1.187"],["64664","0.955"],["64668","0.983"],["64669","2.455"],["64672","1.206"],["64675","1.022"],["64679","2.749"],["64680","1.136"],["64682","1.181"],["64686","1.251"],["64687","0.863"],["64690","0.98"],["64691","1.166"],["64695","1.029"],["64698","2.232"],["64699","0.822"],["64702","1.127"],["64705","1.452"],["64707","0.872"],["64708","1.317"],["64713","2.336"],["64716","1.155"],["64719","0.929"],["64721","1.199"]],"timestamp":"1721281176903905000","gsn":108639724},"timestamp":"1721281176903905000"}
{"channel":"book","product":"BTC-PERP","type":"update","data":{"bids":[],"asks":[["65970","0.027"]],"timestamp":"1721281177084223000","gsn":108639771},"timestamp":"1721281177084223000"}
{"channel":"book","product":"BTC-PERP","type":"update","data":{"bids":[],"asks":[["65970","0"]],"timestamp":"1721281177240916000","gsn":108639794},"timestamp":"1721281177240916000"}
{"channel":"book","product":"BTC-PERP","type":"update","data":{"bids":[["63380","0.025"]],"asks":[],"timestamp":"1721281178041572000","gsn":108639872},"timestamp":"1721281178041572000"}
```

## Message Formats

```json Orderbook Request
// Request
{
  "op": "sub", 
  "channel": "book",
  "product": "BTC-PERP"
}
```

```json Orderbook Snapshot Response
// Response
{
  "channel": "book",
  "product": "BTC-PERP",
  "type": "snapshot",
  "data": {
    "bids": [ 
      ["36000", "50"],
      ["36200", "20"],
      ["36300", "10"]
    ], 
    "asks": [ 
      ["36500", "10"],
      ["36650", "20"],
      ["36800", "50"]
    ],
    "timestamp": 1701798871000000000 // unix nano
  },
  "checksum": 2837461529, // CRC32 for integrity verification
  "timestamp": "1701798871000000000" // unix nano timestamp as a string
}
```

```json Orderbook Update Response
// Response
{
  "channel": "book",
  "product": "BTC-PERP",
  "type": "update",
  "data": {
    "bids": [ 
      ["36000", "0"], // the new size of price 36000 is 0 (no order at this price level)
      ["36200", "20"], // the new size of price 36200 is 20
      ["36300", "10"]
    ], 
    "asks": [ 
      ["36500", "12"],
      ["36650", "23"],
      ["36800", "50"]
    ],
    "timestamp": 1701798871000000000 // unix nano
  },
  "checksum": 1847295103, // Updated checksum
  "timestamp": "1701798871000000000" // unix nano timestamp as a string
}
```

```json Error
{
  "channel": "book",
  "type": "error",
  "message": "given channel/product is unsupported",
  "code": 400
}
```

## Orderbook Checksum Verification

Each orderbook update includes a `checksum` field (uint32) that clients use to verify their local orderbook state matches the server. On mismatch, clients should re-subscribe to get a fresh snapshot.

### Algorithm

**CRC32 IEEE** - Standard polynomial `0xEDB88320`

**String Format**: Interleaved bid/ask levels: `bid_price:bid_size:ask_price:ask_size:...`

**Sorting (critical):**

* Bids: **descending** by price (highest first)
* Asks: **ascending** by price (lowest first)

### Pseudocode

```
1. Sort bids descending, asks ascending
2. Build string by interleaving:
   for i = 0 to max(len(bids), len(asks)):
     if i < len(bids): append "bid[i].price:bid[i].quantity:"
     if i < len(asks): append "ask[i].price:ask[i].quantity:"
3. Remove trailing colon
4. Return CRC32_IEEE(string)
```

### Example Calculation

Given orderbook:

```
Bids: [{price: 100, qty: 5}, {price: 99, qty: 3}]
Asks: [{price: 101, qty: 2}, {price: 102, qty: 4}]
```

Checksum string (after sorting):

```
100:5:101:2:99:3:102:4
```

## Client Implementation

### Go

```go
import (
    "hash/crc32"
    "strings"
)

func ComputeChecksum(bids, asks []Level) uint32 {
    var sb strings.Builder
    maxLen := len(bids)
    if len(asks) > maxLen {
        maxLen = len(asks)
    }

    for i := 0; i < maxLen; i++ {
        if i < len(bids) {
            sb.WriteString(bids[i].Price)
            sb.WriteByte(':')
            sb.WriteString(bids[i].Quantity)
            sb.WriteByte(':')
        }
        if i < len(asks) {
            sb.WriteString(asks[i].Price)
            sb.WriteByte(':')
            sb.WriteString(asks[i].Quantity)
            sb.WriteByte(':')
        }
    }

    s := sb.String()
    if len(s) > 0 {
        s = s[:len(s)-1] // trim trailing colon
    }
    return crc32.ChecksumIEEE([]byte(s))
}
```

### TypeScript

```typescript
import { crc32 } from 'crc';

interface Level {
  price: string;
  quantity: string;
}

function computeChecksum(bids: Level[], asks: Level[]): number {
  const parts: string[] = [];
  const maxLen = Math.max(bids.length, asks.length);

  for (let i = 0; i < maxLen; i++) {
    if (i < bids.length) {
      parts.push(bids[i].price, bids[i].quantity);
    }
    if (i < asks.length) {
      parts.push(asks[i].price, asks[i].quantity);
    }
  }

  return crc32(parts.join(':'));
}
```

### Python

```python
import zlib

def compute_checksum(bids: list, asks: list) -> int:
    parts = []
    max_len = max(len(bids), len(asks))

    for i in range(max_len):
        if i < len(bids):
            parts.extend([bids[i]['price'], bids[i]['quantity']])
        if i < len(asks):
            parts.extend([asks[i]['price'], asks[i]['quantity']])

    s = ':'.join(parts)
    return zlib.crc32(s.encode()) & 0xffffffff
```

## Verification Flow

```
1. Receive orderbook message (snapshot or update)
2. Apply changes to local orderbook state
3. Compute local checksum using algorithm above
4. Compare with message checksum field
5. If mismatch:
   - Log warning
   - Mark orderbook as unsynced
   - Re-subscribe to channel (triggers fresh snapshot)
```

## Important Notes

* **Price/Quantity format**: Raw integer strings (wei, 18 decimals), no decimal points
* **Empty orderbook**: Checksum of empty string is `0`
* **Sorting is critical**: Wrong sort order = wrong checksum
* **Aevo-compatible**: Same algorithm as Aevo's orderbook checksum
* **Zero quantities**: When quantity is "0", the price level should be removed from local orderbook