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

# Frames

> Event, control, and error frame shapes sent over the Radion WebSocket.

Every message the server sends is a JSON object with a `type` field. Confirmed-event payloads are shown here. Pending-transaction payloads are on the [Mempool](/websockets/mempool) page. Every event frame carries a `confirmed` boolean on the envelope — `true` for on-chain confirmed events, `false` for pending (mempool) transactions — and both use the bare channel name.

## Event frame

```json theme={null}
{
  "type": "event",
  "id": "s1",
  "channel": "trading",
  "confirmed": true,
  "data": {
    "type": "order_filled_v2",
    "orderHash": "0x…",
    "maker": "0x…",
    "taker": "0x…",
    "side": 0,
    "tokenId": "0x…",
    "makerAmountFilled": "0x…",
    "takerAmountFilled": "0x…",
    "fee": "0x…",
    "builder": "0x…",
    "metadata": "0x…"
  }
}
```

* `id` — the subscription `id` you gave.
* `channel` — the channel that matched (the bare name, the same for confirmed and pending).
* `confirmed` — `true` for on-chain confirmed events, `false` for pending transactions. Route pending vs confirmed by this flag and your subscription `id`.
* `data.type` — tells you which event it is (snake\_case). The other keys are the event's fields, decoded straight from the on-chain event.

The example above is one `trading` event. `data.type` and the field set change per event. Each channel page lists **every** event it carries with its own payload example and full field table — see the **Payloads** section on [`trading`](/websockets/channels/trading#payloads), [`fees`](/websockets/channels/fees#payloads), [`oracle`](/websockets/channels/oracle#payloads), [`resolution`](/websockets/channels/resolution#payloads), [`lifecycle`](/websockets/channels/lifecycle#payloads), [`positions`](/websockets/channels/positions#payloads), [`combos`](/websockets/channels/combos#payloads), [`transfers`](/websockets/channels/transfers#payloads), and [`accounts`](/websockets/channels/accounts#payloads).

The [`clob.*`](/websockets/channels/clob) channels are the exception: their `data` has **no** `type` field, because each clob channel has one fixed payload shape.

## Control frames

These confirm the messages you send:

```json theme={null}
{ "type": "subscribed", "id": "s1", "channel": "trading" }
{ "type": "unsubscribed", "id": "s1" }
{ "type": "pong" }
```

## Error frames

Errors carry a fixed `code` and a `message` you can read.

| `code`                | When                                                                  | Connection |
| --------------------- | --------------------------------------------------------------------- | ---------- |
| `invalid_message`     | The message was not valid JSON.                                       | Stays open |
| `unknown_channel`     | Unknown channel name, or a required filter is missing or wrong.       | Stays open |
| `subscription_limit`  | The subscribe would go over your plan's subscriptions per connection. | Stays open |
| `lagged`              | The client fell behind the live stream, so some events were dropped.  | Stays open |
| `key_revoked`         | The API key was revoked or is no longer valid.                        | Closes     |
| `revalidation_failed` | Radion could not re-check the API key after several tries.            | Closes     |

A `lagged` error also tells you how many events were skipped:

```json theme={null}
{
  "type": "error",
  "code": "lagged",
  "skipped": 42,
  "message": "Receiver fell behind; 42 events dropped. Reconnect to resume."
}
```

See [Limitations → Backpressure](/websockets/limitations#backpressure) for why lag happens and how to handle it.
