# Message Reference

All messages are delivered as **binary WebSocket frames** containing UTF-8 JSON. Every message has a `type` field.

### Welcome

Sent once, immediately after a successful connection.

```json
{
  "type": "welcome",
  "tier": "premium",
  "maxConnections": 5,
  "allowedCex": "*",
  "expiresInSecs": 2592000
}
```

| Field            | Type            | Description                                                                                                                                           |
| ---------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`           | `string`        | Always `"welcome"`                                                                                                                                    |
| `tier`           | `string`        | Your subscription tier: `basic`, `premium`, or `enterprise`                                                                                           |
| `maxConnections` | `integer`       | Maximum simultaneous connections allowed with your key                                                                                                |
| `allowedCex`     | `string`        | Exchanges you will receive announcements from (effective filter after applying key restrictions and your `cex` preference). `"*"` means all exchanges |
| `expiresInSecs`  | `integer\|null` | Seconds until your key expires, or `null` if no expiration                                                                                            |

***

### Announcement

Sent whenever a listing or other exchange announcement is detected on a monitored exchange.

**Single ticker:**

```json
{
  "type": "announcement",
  "title": "Binance Will List TOKEN (TOKEN)",
  "ticker": "TOKEN",
  "publisher": "binance",
  "listingType": "spot_listing",
  "publishTimestampUs": 1710345000000000,
  "detectedTimestampUs": 1710345000005000,
  "dispatchTimestampUs": 1710345000006000
}
```

**Multiple tickers** (one announcement listing several assets at once):

```json
{
  "type": "announcement",
  "title": "Binance Will List ABC, DEF and GHI",
  "ticker": "ABC,DEF,GHI",
  "publisher": "binance",
  "listingType": "spot_listing",
  "publishTimestampUs": 1710345000000000,
  "detectedTimestampUs": 1710345000005000,
  "dispatchTimestampUs": 1710345000006000
}
```

| Field                 | Type      | Description                                                                                                                  |
| --------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `type`                | `string`  | Always `"announcement"`                                                                                                      |
| `title`               | `string`  | Original announcement title from the exchange                                                                                |
| `ticker`              | `string`  | Asset symbol(s). Comma-separated when multiple tickers are listed in the same announcement (e.g. `"BTC"` or `"ABC,DEF,GHI"`) |
| `publisher`           | `string`  | Exchange name in lowercase (e.g. `"binance"`, `"upbit"`)                                                                     |
| `listingType`         | `string`  | One of the listing types below                                                                                               |
| `publishTimestampUs`  | `integer` | When the exchange published the announcement (microseconds since UNIX epoch)                                                 |
| `detectedTimestampUs` | `integer` | When our detection engine captured it (microseconds since UNIX epoch)                                                        |
| `dispatchTimestampUs` | `integer` | When the dispatch server broadcasted it (microseconds since UNIX epoch)                                                      |

{% hint style="warning" %}
**Always handle `ticker` as a potentially comma-separated list.** Some exchange announcements list multiple assets at once. Split on `,` to get individual tickers:

```python
tickers = data["ticker"].split(",")  # ["ABC", "DEF", "GHI"]
```

{% endhint %}

#### Listing types

| Value               | Meaning                                                              |
| ------------------- | -------------------------------------------------------------------- |
| `spot_listing`      | New spot market listing                                              |
| `futures_listing`   | New futures/perpetual listing                                        |
| `spot_delisting`    | Spot market delisting (coming soon)                                  |
| `futures_delisting` | Futures/perpetual delisting (coming soon)                            |
| `not_listing`       | Other exchange announcement (maintenance, airdrop, token swap, etc.) |

{% hint style="info" %}
**Delistings coming soon.** The `spot_delisting` and `futures_delisting` types are reserved for future use. Currently, announcements that are not listings are sent with `listingType: "not_listing"`.
{% endhint %}

#### Measuring your latency

All timestamps are in **microseconds since UNIX epoch** (not milliseconds, not nanoseconds).

```
Detection delay    = detectedTimestampUs - publishTimestampUs
Dispatch delay     = dispatchTimestampUs - detectedTimestampUs
Your network delay = your_receive_time_us - dispatchTimestampUs
Total end-to-end   = your_receive_time_us - publishTimestampUs
```

**Python example:**

```python
import time

def on_announcement(msg):
    now_us = int(time.time() * 1_000_000)
    detection_ms = (msg["detectedTimestampUs"] - msg["publishTimestampUs"]) / 1000
    dispatch_ms  = (msg["dispatchTimestampUs"] - msg["detectedTimestampUs"]) / 1000
    network_ms   = (now_us - msg["dispatchTimestampUs"]) / 1000
    total_ms     = (now_us - msg["publishTimestampUs"]) / 1000

    print(f"Detection: {detection_ms:.2f}ms")
    print(f"Dispatch:  {dispatch_ms:.2f}ms")
    print(f"Network:   {network_ms:.2f}ms")
    print(f"Total:     {total_ms:.2f}ms")
```

***

### Heartbeat

Sent every **30 seconds** to indicate the server is alive.

```json
{
  "type": "heartbeat",
  "timestampNs": 1710345030000000000,
  "timeUtc": "2024-03-13T10:30:30.000000Z"
}
```

| Field         | Type      | Description                                         |
| ------------- | --------- | --------------------------------------------------- |
| `type`        | `string`  | Always `"heartbeat"`                                |
| `timestampNs` | `integer` | Current server time in nanoseconds since UNIX epoch |
| `timeUtc`     | `string`  | Current server time in ISO 8601 UTC format          |

{% hint style="info" %}
If you do not receive a heartbeat within 35 seconds, your connection is likely dead. Initiate a reconnection.
{% endhint %}
