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

# WebSocket

> Realtime device updates via WebSocket connection.

Connect to live device updates over WebSocket. Requires a valid API key (user or admin). You can only subscribe to devices within your access scope.

## Connection

```
wss://your-api-host/realtime?api_key=YOUR_API_KEY
```

Pass your API key via the `api_key` query parameter, or via the `X-API-Key` header if your WebSocket client supports custom headers.

Unauthorized connections receive `401 Unauthorized` and the connection is rejected.

On successful connection, the server sends:

```json theme={null}
{
  "type": "connected",
  "connectionId": "conn-1702812600000-1"
}
```

## Client messages

### Subscribe to devices

```json theme={null}
{
  "type": "subscribe",
  "hardwareIds": ["ABC123", "DEF456"]
}
```

**Response:**

```json theme={null}
{
  "type": "subscribed",
  "hardwareIds": ["ABC123", "DEF456"]
}
```

### Unsubscribe from devices

```json theme={null}
{
  "type": "unsubscribe",
  "hardwareIds": ["ABC123"]
}
```

**Response:**

```json theme={null}
{
  "type": "unsubscribed",
  "hardwareIds": ["ABC123"]
}
```

## Server messages

### Device data update

Telemetry data received from a device. The `payload` object contains only the fields present in that particular update, not the full device state.

```json theme={null}
{
  "type": "device_data",
  "hardwareId": "ABC123",
  "payload": {
    "lat": 37.7749,
    "long": -122.4194,
    "speed": 15.5,
    "battery_voltage": 12.4,
    "lock_status": 0
  },
  "timestamp": "2025-12-17T10:30:00.000Z"
}
```

### Device status update

Online/offline status change.

```json theme={null}
{
  "type": "device_status",
  "hardwareId": "ABC123",
  "payload": {
    "is_online": false
  },
  "timestamp": "2025-12-17T10:30:00.000Z"
}
```

### Device unlocked

Sent when a device is unlocked via RFID, keypad, key, or remote command.

<Tabs>
  <Tab title="Physical unlock">
    ```json theme={null}
    {
      "type": "device_unlocked",
      "hardwareId": "ABC123",
      "eventId": "evt_123",
      "source": "rfid",
      "code": "ABC123",
      "timestamp": "2025-12-17T10:30:00.000Z"
    }
    ```
  </Tab>

  <Tab title="Remote unlock">
    ```json theme={null}
    {
      "type": "device_unlocked",
      "hardwareId": "ABC123",
      "eventId": "evt_124",
      "source": "remote",
      "metadata": {
        "userId": "user_456",
        "name": "Jane Smith"
      },
      "timestamp": "2025-12-17T10:30:00.000Z"
    }
    ```
  </Tab>
</Tabs>

### Device locked

```json theme={null}
{
  "type": "device_locked",
  "hardwareId": "ABC123",
  "eventId": "evt_125",
  "source": "key",
  "timestamp": "2025-12-17T10:30:00.000Z"
}
```

## Error messages

```json theme={null}
{
  "type": "error",
  "message": "hardwareIds must be an array"
}
```

## Example

```typescript theme={null}
const ws = new WebSocket("wss://your-api-host/realtime?api_key=YOUR_API_KEY");

ws.onopen = () => {
  ws.send(JSON.stringify({ type: "subscribe", hardwareIds: ["ABC123"] }));
};

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  switch (msg.type) {
    case "device_data":
      console.log("Telemetry:", msg.hardwareId, msg.payload);
      break;
    case "device_status":
      console.log("Status:", msg.hardwareId, msg.payload.is_online);
      break;
    case "device_unlocked":
      console.log("Unlocked:", msg.hardwareId, msg.source);
      break;
    case "device_locked":
      console.log("Locked:", msg.hardwareId, msg.source);
      break;
  }
};
```
