> For the complete documentation index, see [llms.txt](https://docs.hydromancer.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.hydromancer.xyz/readme/websocket.md).

# Websocket

Hydromancer WebSocket API Real-time Hypercore events

### Websocket URL

#### Mainnet

```url
wss://api.hydromancer.xyz/ws
```

#### Testnet

```
wss://api-testnet.hydromancer.xyz/ws
```

### Authentication

Include your API key as a query parameter in the connection URL:

```
wss://api.hydromancer.xyz/ws?token=your-api-key-here
```

### Subscribe

```
{ 
    "type": "subscribe",
    "subscription": {
        "type": "userFills",
        "addresses": ["0x742d35Cc6634C0532925a3b844Bc9e7595f7F2e2"]
    }
} 
```

### Unsubscribe

```
{ 
    "type": "unsubscribe",
    "subscription": {
        "type": "userFills",
        "addresses": ["0x742d35Cc6634C0532925a3b844Bc9e7595f7F2e2"]
    }
} 
```

### Correlating subscription feedback

Subscribe and unsubscribe messages may include an optional string `requestId` (at most 128 characters, no control characters). The server echoes it on the confirmation or rejection for that request. Oversized or control-bearing values are rejected with `code: "invalid_request_id"` and are not treated as a successful correlation id. Use a unique value whenever one connection has multiple requests in flight.

```json
{
  "method": "subscribe",
  "requestId": "books-42",
  "subscription": { "type": "l2Book", "coins": ["BTC", "BTCUSD"] }
}
```

A successful request returns a normalized `subscription`, its `operation`, and the affected channel. Empty optional fields may be omitted from the echoed subscription. Unsubscribe confirmations use `unsubscribed`; `subscribed` and `failed` remain present for compatibility.

```json
{
  "type": "subscriptionUpdate",
  "requestId": "books-42",
  "operation": "subscribe",
  "subscription": {
    "type": "l2Book",
    "coins": ["BTC", "BTCUSD"],
    "nLevels": 20
  },
  "subscribed": ["l2Book"],
  "failed": [],
  "warnings": [{
    "code": "inactive_coins",
    "message": "no currently active market for coin(s): [\"BTCUSD\"]",
    "coins": ["BTCUSD"]
  }]
}
```

Subscription errors also echo `requestId`, `operation`, and `subscription`. Machine-readable `code` and `details` are included where available. The existing `type`, `message`, `subscribed`, and `failed` fields are retained; the new fields are additive. Clients must ignore unknown object fields and unknown message types so the protocol can evolve safely.

For `l2Book`, `l2BookDiff`, `l4BookUpdates`, and `bbo`, warnings are advisory: the subscription succeeds and `failed` stays empty. `inactive_coins` identifies well-formed perp, spot, or outcome symbols with no currently active market. `market_activity_unavailable` means activity could not be established: a cold or stale metadata cache, or a refresh that committed perp/spot data while HIP-4 `outcomeMeta` was unavailable (outcome coins only). A warning never prevents a market that lists later from streaming.

### Live Message Chunking

For improved connection stability during high-volume periods, enable chunked message delivery by adding `liveFormat=chunked-v1` to your connection URL:

```
wss://api.hydromancer.xyz/ws?token=your-api-key&liveFormat=chunked-v1
```

For `chunked-v1` connections, large batched live messages (fills, orders, trades, etc.) are split by item count into smaller chunks with metadata (`chunk`, `totalChunks`, `batchId`) for reassembly. This is fully backward compatible — existing clients without `liveFormat` see no change.

See [Live Message Chunking](/readme/websocket/live-message-chunking.md) for full details.

### Live Data Routing

Every live subscription data message carries both `type` and `channel`. Their values are identical to the subscription type sent by the client, so generic clients may route on either field:

```json
{
  "type": "userFills",
  "channel": "userFills",
  "seq": 1,
  "cursor": "500:1704067200000:3",
  "fills": []
}
```

This additive contract does not change control frames such as `connected`, `subscriptionUpdate`, `subscriptionResponse`, `replay`, or `pong`.

### Heartbeats

To see if a client is still active the server will send a ping message every 60 seconds, please make sure to respond with a pong to keep the connection alive.

Server sends:

```json
{ 
    "type": "ping"
} 
```

Respond with:

```json
{ 
    "type": "pong"
} 
```
