# Websocket

Real-time orderbook, trade, and market updates via WebSocket.

## Connection

wss\://api.turbinefi.com/api/v1/stream

No authentication is required. The WebSocket endpoint is public.

### Connection lifecycle

* The server sends a **ping** every 54 seconds.
* Clients must respond with a **pong** within 60 seconds or the connection is closed.
* On subscribe, you receive a confirmation message followed by the current orderbook snapshot.

### Example

{% code title="example.js" %}

```javascript
const ws = new WebSocket("wss://api.turbinefi.com/api/v1/stream");

ws.onopen = () => {
  console.log("Connected");
};

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  console.log(msg.type, msg.data);
};
```

{% endcode %}

## Subscribe

Subscribe to real-time updates for a market. You can optionally filter by outcome.

### Request

```json
{
  "type": "subscribe",
  "marketId": "0x1234...abcd"
}
```

With outcome filter:

```json
{
  "type": "subscribe",
  "marketId": "0x1234...abcd",
  "data": {
    "outcome": 0
  }
}
```

| Field          | Type    | Description                                                    |
| -------------- | ------- | -------------------------------------------------------------- |
| `type`         | string  | `"subscribe"`                                                  |
| `marketId`     | bytes32 | Market to subscribe to                                         |
| `data.outcome` | uint8   | Optional. `0` = YES only, `1` = NO only. Omit for all outcomes |

### Response

You receive a subscription confirmation followed by the initial orderbook snapshot:

```json
{
  "type": "subscribe",
  "marketId": "0x1234...abcd",
  "data": {
    "status": "subscribed"
  }
}
```

```json
{
  "type": "orderbook",
  "marketId": "0x1234...abcd",
  "data": {
    "marketId": "0x1234...abcd",
    "bids": [
      { "price": 450000, "size": 20000000 }
    ],
    "asks": [
      { "price": 550000, "size": 15000000 }
    ],
    "lastUpdate": 1735689000
  }
}
```

## Unsubscribe

Stop receiving updates for a market.

### Request

```json
{
  "type": "unsubscribe",
  "marketId": "0x1234...abcd"
}
```

### Response

```json
{
  "type": "unsubscribe",
  "marketId": "0x1234...abcd",
  "data": {
    "status": "unsubscribed"
  }
}
```

## Event Types

All server messages follow this format:

```json
{
  "type": "<event_type>",
  "marketId": "0x...",
  "data": { ... }
}
```

### orderbook

Full orderbook snapshot sent on subscribe and after each trade or order change.

```json
{
  "type": "orderbook",
  "marketId": "0x1234...abcd",
  "data": {
    "marketId": "0x1234...abcd",
    "bids": [
      { "price": 450000, "size": 20000000 },
      { "price": 400000, "size": 10000000 }
    ],
    "asks": [
      { "price": 550000, "size": 15000000 },
      { "price": 600000, "size": 5000000 }
    ],
    "lastUpdate": 1735689000
  }
}
```

| Field          | Type   | Description                                                   |
| -------------- | ------ | ------------------------------------------------------------- |
| `bids`         | array  | Buy orders, sorted by price descending                        |
| `asks`         | array  | Sell orders, sorted by price ascending                        |
| `bids[].price` | uint64 | Bid price (6 decimals). `450000` = $0.45                      |
| `bids[].size`  | uint64 | Total size at this price (6 decimals). `20000000` = 20 shares |
| `asks[].price` | uint64 | Ask price (6 decimals). `550000` = $0.55                      |
| `asks[].size`  | uint64 | Total size at this price (6 decimals)                         |
| `lastUpdate`   | uint64 | Unix timestamp of last update                                 |

### trade

Sent when a trade is executed.

```json
{
  "type": "trade",
  "marketId": "0x1234...abcd",
  "data": {
    "marketId": "0x1234...abcd",
    "price": 550000,
    "size": 10000000,
    "outcome": 0,
    "timestamp": 1735689000,
    "tradeHash": "0x...",
    "maker": "0xMakerAddress...",
    "taker": "0xTakerAddress...",
    "side": 0
  }
}
```

| Field       | Type    | Description                                     |
| ----------- | ------- | ----------------------------------------------- |
| `price`     | uint64  | Trade price (6 decimals). `550000` = $0.55      |
| `size`      | uint64  | Trade size (6 decimals). `10000000` = 10 shares |
| `outcome`   | uint8   | `0` = YES, `1` = NO                             |
| `timestamp` | uint64  | Unix timestamp                                  |
| `tradeHash` | string  | Unique trade identifier                         |
| `maker`     | address | Limit order placer                              |
| `taker`     | address | Market order placer                             |
| `side`      | uint8   | Taker's side: `0` = BUY, `1` = SELL             |

### trade\_error

Sent when an on-chain trade settlement fails.

```json
{
  "type": "trade_error",
  "marketId": "0x1234...abcd",
  "data": {
    "marketId": "0x1234...abcd",
    "buyer": "0xBuyerAddress...",
    "seller": "0xSellerAddress...",
    "price": 550000,
    "size": 10000000,
    "txHash": "0xFailedTxHash...",
    "error": "execution reverted"
  }
}
```

| Field    | Type    | Description              |
| -------- | ------- | ------------------------ |
| `buyer`  | address | Buyer's wallet address   |
| `seller` | address | Seller's wallet address  |
| `price`  | uint64  | Trade price (6 decimals) |
| `size`   | uint64  | Trade size (6 decimals)  |
| `txHash` | string  | Failed transaction hash  |
| `error`  | string  | Error description        |

### order\_cancelled

Sent when an order is cancelled, either by the user or by the system (e.g., during market rebalancing).

```json
{
  "type": "order_cancelled",
  "marketId": "0x1234...abcd",
  "data": {
    "orderHash": "0xOrderHash...",
    "marketId": "0x1234...abcd",
    "side": "buy",
    "trader": "0xTraderAddress...",
    "reason": "user_cancelled"
  }
}
```

| Field       | Type    | Description                                                            |
| ----------- | ------- | ---------------------------------------------------------------------- |
| `orderHash` | string  | Cancelled order hash                                                   |
| `marketId`  | string  | Market identifier                                                      |
| `side`      | string  | `"buy"` or `"sell"`                                                    |
| `trader`    | address | Order owner                                                            |
| `reason`    | string  | Cancellation reason (e.g., `"user_cancelled"`, `"market_rebalancing"`) |

### quick\_market

Broadcast to all connected clients when a quick market is created or resolved.

```json
{
  "type": "quick_market",
  "data": {
    "type": "new_market",
    "asset": "BTC",
    "marketId": "0x...",
    "quickMarket": {
      "id": 42,
      "asset": "BTC",
      "startPrice": 9750000000000,
      "startTime": 1735689000,
      "endTime": 1735689900
    }
  }
}
```

```json
{
  "type": "quick_market",
  "data": {
    "type": "resolved",
    "asset": "BTC",
    "marketId": "0x...",
    "quickMarket": {
      "id": 42,
      "asset": "BTC",
      "resolved": true,
      "outcome": 0
    }
  }
}
```

| Field              | Type   | Description                    |
| ------------------ | ------ | ------------------------------ |
| `data.type`        | string | `"new_market"` or `"resolved"` |
| `data.asset`       | string | Asset symbol (e.g., `"BTC"`)   |
| `data.marketId`    | string | Market identifier              |
| `data.quickMarket` | object | Quick market details           |

Quick market events are sent to **all** connected clients regardless of subscriptions.

## Full example

{% tabs %}
{% tab title="JavaScript" %}
{% code title="full-example.js" %}

```javascript
const ws = new WebSocket("wss://api.turbinefi.com/api/v1/stream");

ws.onopen = () => {
  // Subscribe to a market (YES outcome only)
  ws.send(JSON.stringify({
    type: "subscribe",
    marketId: "0x1234...abcd",
    data: { outcome: 0 }
  }));
};

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);

  switch (msg.type) {
    case "subscribe":
      console.log("Subscribed:", msg.data.status);
      break;
    case "orderbook":
      console.log("Bids:", msg.data.bids);
      console.log("Asks:", msg.data.asks);
      break;
    case "trade":
      console.log(`Trade: ${msg.data.size} shares at $${msg.data.price / 1000000}`);
      break;
    case "trade_error":
      console.error("Settlement failed:", msg.data.error);
      break;
    case "order_cancelled":
      console.log("Order cancelled:", msg.data.orderHash, msg.data.reason);
      break;
    case "quick_market":
      console.log("Quick market:", msg.data.type, msg.data.asset);
      break;
  }
};

ws.onclose = () => {
  console.log("Disconnected");
};
```

{% endcode %}
{% endtab %}

{% tab title="Python" %}
{% code title="full-example.py" %}

```python
import websocket
import json

def on_message(ws, message):
    msg = json.loads(message)
    print(f"{msg['type']}: {msg.get('data')}")

def on_open(ws):
    ws.send(json.dumps({
        "type": "subscribe",
        "marketId": "0x1234...abcd"
    }))

ws = websocket.WebSocketApp(
    "wss://api.turbinefi.com/api/v1/stream",
    on_message=on_message,
    on_open=on_open
)
ws.run_forever()
```

{% endcode %}
{% endtab %}
{% endtabs %}
