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

# Establish a WebSocket for an airport

> Performs a WebSocket upgrade to stream real-time airport state. Requires:
- GET with `Upgrade: websocket`
- `airport` (ICAO, 4 chars) and an API key via either:
  - `key` query parameter, or
  - `Authorization: Bearer <API key>` header
The API key is forwarded as a Bearer token to the airport's Durable Object for auth.


## Establish a session

1. Connect to `/connect` with `airport` and your API key.
2. Wait for `INITIAL_STATE` (this confirms your role and current airport state).
3. Keep the connection alive by sending `HEARTBEAT` regularly.

The server sends `HEARTBEAT` every 60 seconds and closes idle sessions after \~70 seconds without inbound client messages.

## Packet envelope

Every packet uses this top-level shape:

```json
{
  "type": "STATE_UPDATE",
  "airport": "YSSY",
  "data": {},
  "timestamp": 1739400000000
}
```

* `type` is required.
* `airport` is optional on most client packets (server uses your connected airport if omitted).
* `timestamp` is optional on client packets and server-populated on outbound packets.

## Packet permissions by role

| Packet type           | Who can send                | What happens                                         |
| --------------------- | --------------------------- | ---------------------------------------------------- |
| `HEARTBEAT`           | controller, pilot, observer | Server replies with `HEARTBEAT_ACK`                  |
| `GET_STATE`           | controller, pilot, observer | Server replies with `STATE_SNAPSHOT`                 |
| `STATE_UPDATE`        | controller only             | Broadcast to same-airport clients (except sender)    |
| `MULTI_STATE_UPDATE`  | controller only             | Broadcast to same-airport clients (except sender)    |
| `SHARED_STATE_UPDATE` | controller only             | Broadcast to same-airport clients (including sender) |
| `STOPBAR_CROSSING`    | pilot only                  | Broadcast to same-airport controllers                |
| `CLOSE`               | controller, pilot, observer | Server closes the session gracefully                 |

## Client packets you send

### HEARTBEAT

```json
{ "type": "HEARTBEAT" }
```

### GET\_STATE

```json
{ "type": "GET_STATE" }
```

### STATE\_UPDATE (controller only)

```json
{
  "type": "STATE_UPDATE",
  "data": {
    "objectId": "BARS_7K2QH",
    "state": false
  }
}
```

### MULTI\_STATE\_UPDATE (controller only)

```json
{
  "type": "MULTI_STATE_UPDATE",
  "data": {
    "updates": [
      { "objectId": "BARS_7K2QH", "state": false },
      { "objectId": "BARS_8R1LP", "state": true }
    ]
  }
}
```

### SHARED\_STATE\_UPDATE (controller only)

```json
{
  "type": "SHARED_STATE_UPDATE",
  "data": {
    "sharedStatePatch": {
      "profile": "default",
      "nodes": {
        "TWY_A1": true,
        "TWY_B2": false,
        "RWY_09L_HOLD": true
      },
      "blocks": {
        "BLOCK_A": "clear",
        "BLOCK_B": "relax",
        "BLOCK_C": { "route": ["TWY_A1", "TWY_B2"] }
      }
    }
  }
}
```

### STOPBAR\_CROSSING (pilot only)

```json
{
  "type": "STOPBAR_CROSSING",
  "data": {
    "objectId": "BARS_7K2QH"
  }
}
```

### CLOSE

```json
{ "type": "CLOSE" }
```

## Server packets you should handle

* `INITIAL_STATE` immediately after connect
* `HEARTBEAT` every 60 seconds
* `HEARTBEAT_ACK` in response to client `HEARTBEAT`
* `STATE_SNAPSHOT` in response to `GET_STATE`
* `STATE_UPDATE` when a controller changes one object state
* `MULTI_STATE_UPDATE` when a controller sends a batch state change
* `CONTROLLER_CONNECT` / `CONTROLLER_DISCONNECT` for controller presence changes
* `SHARED_STATE_UPDATE` when shared state changes
* `STOPBAR_CROSSING` (controllers only) when a pilot crosses a stopbar
* `ERROR` when validation/processing fails

## Validation and limits (avoid malformed packets)

* `objectId` must match `^[a-zA-Z0-9_-]+$`.
* `STATE_UPDATE` must include `data.objectId` and one of `data.state` or `data.patch`.
* `MULTI_STATE_UPDATE` must include `data.updates` (maximum `200` updates).
* `SHARED_STATE_UPDATE` must include `data.sharedStatePatch` object (maximum `10,240` serialized characters).
* Maximum packet size is `50,000` characters.
* Unknown packet `type` values are rejected.


## OpenAPI

````yaml https://raw.githubusercontent.com/stopbars/Core/refs/heads/main/data/openapi.json get /connect
openapi: 3.0.4
info:
  title: BARS Core API
  version: 2.0.0
  description: API documentation for BARS Core
  contact:
    name: BARS Support
    email: support@stopbars.com
    url: https://stopbars.com/support
servers:
  - url: https://v2.stopbars.com
    description: Production
  - url: http://localhost:8787
    description: Local development (wrangler dev)
security: []
tags:
  - name: RealTime
    description: WebSocket connection and real-time state interaction endpoints.
  - name: State
    description: Endpoints for retrieving current system or airport lighting/network state.
  - name: Auth
    description: Authentication, account management, and API key lifecycle.
  - name: Airports
    description: Lookup and metadata endpoints for airports.
  - name: Divisions
    description: Division management, membership, and associated airport access.
  - name: Points
    description: Creation and management of lighting/navigation point data.
  - name: Generation
    description: Utilities for generating light support / BARS XML artifacts.
  - name: NOTAM
    description: Global NOTAM retrieval and (staff) updates.
  - name: Contributions
    description: Community lighting package submission, review, and leaderboard.
  - name: Staff
    description: >-
      Restricted staff-only operational and moderation endpoints (hidden from
      public docs).
  - name: CDN
    description: File storage, upload, listing, and deletion via CDN-backed storage.
  - name: FAQ
    description: Frequently Asked Questions (FAQ) management and retrieval.
  - name: EuroScope
    description: EuroScope sector file upload, listing, and permission checks by ICAO.
  - name: Cache
    description: Administrative cache management operations.
  - name: GitHub
    description: Repository contributor information.
  - name: System
    description: System health and OpenAPI specification discovery.
externalDocs:
  description: Find more info here
  url: https://docs.stopbars.com
paths:
  /connect:
    get:
      tags:
        - RealTime
      summary: Establish a WebSocket for an airport
      description: >
        Performs a WebSocket upgrade to stream real-time airport state.
        Requires:

        - GET with `Upgrade: websocket`

        - `airport` (ICAO, 4 chars) and an API key via either:
          - `key` query parameter, or
          - `Authorization: Bearer <API key>` header
        The API key is forwarded as a Bearer token to the airport's Durable
        Object for auth.
      parameters:
        - in: query
          name: airport
          required: true
          description: Airport ICAO (4 alphanumeric characters)
          schema:
            type: string
            minLength: 4
            maxLength: 4
            pattern: ^[A-Z0-9]{4}$
        - in: query
          name: key
          required: false
          description: User API key (optional when using Authorization header)
          schema:
            type: string
        - in: header
          name: Authorization
          required: false
          description: Bearer <API key> (alternative to `key` query parameter)
          schema:
            type: string
      responses:
        '101':
          description: WebSocket upgrade accepted
        '400':
          description: Not a WebSocket upgrade
        '401':
          description: Missing or invalid API key/airport, or key rejected
        '403':
          description: Forbidden

````