> ## Documentation Index
> Fetch the complete documentation index at: https://docs.p2p.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Protocol Reference

> Every client-to-server message is a JSON text frame with a required method field.

Invalid JSON, missing required fields, or unknown methods may disconnect the client with a structured error.

## Client messages

### subscribe

Subscribes the client to a coin or stream.

Subscribe to order book diffs for a coin:

<CodeGroup>
  ```json JSON theme={null}
  {"method":"subscribe","coin":"BTC"}
  ```
</CodeGroup>

The `coin` value must be a non-empty string.

Subscribing twice to the same coin is safe and idempotent.

Subscribe to mempool transactions:

<CodeGroup>
  ```json JSON theme={null}
  {"method":"subscribe","stream":"mempool"}
  ```
</CodeGroup>

Currently, the only valid stream value is `mempool`.

If the mempool stream is not enabled on the server, the server replies with a non-disconnecting `mempool_unavailable` error.

### unsubscribe

Unsubscribes from a coin or stream.

<CodeGroup>
  ```json JSON theme={null}
  {"method":"unsubscribe","coin":"BTC"}
  ```
</CodeGroup>

<CodeGroup>
  ```json JSON theme={null}
  {"method":"unsubscribe","stream":"mempool"}
  ```
</CodeGroup>

### esp

Upgrades the connection to binary protocol mode.

<CodeGroup>
  ```json JSON theme={null}
  {"method":"esp","version":1}
  ```
</CodeGroup>

The version field must match the server binary protocol version.

Current binary protocol version: `1`.

If the version does not match, the client is disconnected with the `version_mismatch` error.

### prime

Enables additional binary streams after `esp`.

<CodeGroup>
  ```json JSON theme={null}
  {"method":"prime"}
  ```
</CodeGroup>

After `prime`, the client can receive:

* Ping frames
* Timing metrics
* Server error events

`prime` must be sent after `esp`.

Calling `prime` before `esp` disconnects the client with the `not_esp` error.

### unprime

Disables the additional prime streams.

<CodeGroup>
  ```json JSON theme={null}
  {"method":"unprime"}
  ```
</CodeGroup>

Like `prime`, this must be called after `esp`.

## JSON mode

JSON mode is the default mode before `esp` is sent.

In this mode, server-to-client frames are text frames containing newline-delimited JSON order book diffs.

A single WebSocket frame may contain multiple JSON lines separated by `\n`.

Example:

<CodeGroup>
  ```json JSON theme={null}
  {"coin":"BTC","time":"...","side":"A","px":"72223.0","sz":"0","oid":123,"user":"0x..."}
  {"coin":"BTC","time":"...","side":"B","px":"72182.0","sz":"0.3","oid":456,"user":"0x..."}
  ```
</CodeGroup>

JSON mode is intended for quick testing and inspection.

For production integrations, use binary mode.

## Binary mode

After `esp`, all server-to-client data frames are binary WebSocket frames.

The first byte of every frame is a tag that identifies the frame type.

All multi-byte integers are little-endian.

| Tag | Type      | Size     | When it is received                           |
| --- | --------- | -------- | --------------------------------------------- |
| 0   | Block     | 33 bytes | After every block applied by the node         |
| 1   | TinyOrder | Variable | For each order book diff on a subscribed coin |
| 2   | Metric    | Variable | After every block, only after `prime`         |
| 3   | Ping      | 9 bytes  | Roughly every 5 ms, only after `prime`        |
| 4   | MempoolTx | Variable | For each mempool transaction, when subscribed |

## Block frame

Tag:

```
0
```

Size:

```
33 bytes
```

Block frames are emitted after every block applied by the node.

Layout:

```
offset  size  field              notes
────────────────────────────────────────────────────────────
0       1     tag                Always 0
1       8     ts_ms              Block timestamp, ms since UNIX epoch
9       8     height             Block height
17      8     wall_ts_us         Node-local wall clock, µs since epoch
25      8     apply_duration_us  Time spent applying the block
```

Node-side block latency can be calculated as:

```
wall_ts_us - (ts_ms * 1000)
```

## TinyOrder frame

Tag:

```
1
```

Size:

```
Variable
```

TinyOrder frames are emitted for order book diffs on subscribed coins.

All strings are length-prefixed with a single u8 byte.

The following fields are encoded as UTF-8 decimal strings and should be parsed as text:

* `coin`
* `price`
* `qty`
* `user`

Layout:

```
offset  size       field
────────────────────────────────────────────────────────────
0       1          tag = 1
1       8          oid, u64 little-endian
9       1          is_buyer, 1 = buy, 0 = sell
10      1          status, 1 = open, 0 = canceled
11      1 + N      coin, for example "BTC"
...     1 + N      price, for example "72223.0"
...     1 + N      qty, for example "0.3"
...     1 + N      user, hex address
```

Both opens and cancels arrive as TinyOrder frames.

A full cancel is represented as:

```
status = 0
qty = "0"
```

Partial fills are not surfaced as separate events. Instead, the resting order quantity changes.

## MempoolTx frame

Tag:

```
4
```

Size:

```
Variable
```

MempoolTx frames are emitted for mempool transactions when the client is subscribed to the mempool stream.

These frames can be large because the payload is length-prefixed with a `u32`.

Layout:

```
offset  size    field
────────────────────────────────────────────────────────────
0       1       tag = 4
1       8       receive_ts_us, node first saw the tx, µs since epoch
9       32      tx_hash, raw 32-byte hash
41      4       payload_len, u32 little-endian
45      N       payload, signed-action bundle as raw JSON
```

## Error frames

Errors are delivered as JSON text frames.

Example:

<CodeGroup>
  ```json JSON theme={null}
  {"channel":"errors","code":"<code>","message":"<human readable>"}
  ```
</CodeGroup>

The `code` field is a stable contract and can be used programmatically.

The `message` field is intended for humans and may change.

| Code                  | Meaning                                                  | Disconnects? |
| --------------------- | -------------------------------------------------------- | ------------ |
| `invalid_json`        | Text frame was not valid JSON                            | Yes          |
| `missing_method`      | JSON frame had no `method` field                         | Yes          |
| `unknown_method`      | Method value is not recognized                           | Yes          |
| `missing_param`       | Required `coin`, `stream`, or `version` field is missing | Yes          |
| `empty_coin`          | Subscribe was called with an empty coin string           | No           |
| `unknown_stream`      | Stream value is not supported                            | No           |
| `mempool_unavailable` | Mempool stream is not enabled on this server             | No           |
| `version_mismatch`    | `esp` version does not match the server version          | Yes          |
| `not_esp`             | `prime` or `unprime` was called before `esp`             | Yes          |

After `prime`, clients may also receive informational server error events. These do not necessarily indicate a client-side issue.


## Related topics

- [Operational Notes](/docs/syncro-data-hyperliquid-operational-notes.md)
- [Getting Started](/docs/syncro-data-hyperliquid-quick-start.md)
