# Control WebSocket

`WS /v1/outputs/{id}/control/ws`

A live connection to an output. It tells you everything that changes as it happens, and takes the same [commands](https://docs.airframe.tv/api/commands) as [Run commands](https://docs.airframe.tv/api/run-commands).

## Connect

Open a WebSocket to the path above, on `wss://`. Browsers can't set headers on a WebSocket, so pass the API key as `?token=`. From the server side, an `Authorization: Bearer` header works too.

## What it sends

- `state` (message): First, the output's whole state, then again whenever the output loads another version. `now` is the output's clock in milliseconds, which timers are measured against.
- `patch` (message): Each change after that: `revision` and the `update`, holding only what changed, such as `onAir`, `components` data or `timers`. Apply them in order on top of the state.
- `show` (message): The version the output plays and its instances, on connect and whenever they change.
- `ack` (message): A batch you sent ran. Carries your batch's `id` and the new `revision`.
- `error` (message): A batch didn't run, or a message wasn't understood. Carries your batch's `id` and the failed command's `index` where there is one.

## What you send

```json
{ "type": "commands", "id": "take-1", "commands": [ … ] }
```

`id` is optional, and comes back on the `ack` or `error` so you can match them up. Batches over the socket follow the same rules as over HTTP: in order, all or nothing.

> **Reconnect when it drops.** Networks blip. When the socket closes, wait a moment and connect again: the first message is the whole state, so you're back in step straight away.

## Example request

```js
const ws = new WebSocket(
  `wss://api.airframe.tv/v1/outputs/${outputId}/control/ws?token=${key}`,
);

ws.addEventListener("message", (event) => {
  const message = JSON.parse(event.data);
  if (message.type === "state") console.log("Now", message.state);
  if (message.type === "patch") console.log("Changed", message.update);
  if (message.type === "ack") console.log("Ran batch", message.id);
  if (message.type === "error") console.error(message.message);
});

ws.addEventListener("open", () => {
  ws.send(JSON.stringify({
    type: "commands",
    id: "take-1",
    commands: [{ command: "in", component: "lower-third" }],
  }));
});
```

### ack

```json
{
  "type": "ack",
  "id": "take-1",
  "revision": 43
}
```

### patch

```json
{
  "type": "patch",
  "revision": 43,
  "update": {
    "onAir": {
      "lower-third": true
    }
  },
  "now": 1793000000000
}
```

### error

```json
{
  "type": "error",
  "id": "take-1",
  "index": 0,
  "message": "No component lower-thrid"
}
```
