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

# Pairing

> Pair your drone with ADOS Mission Control: local-first over the LAN, with cloud relay as the secondary path.

# Pairing

Pairing connects your drone agent to ADOS Mission Control so the drone appears in your GCS, telemetry flows, and you can send commands.

ADOS is local-first. The primary path is direct, over the LAN. The cloud pairing code is the secondary, opt-in path for reaching a drone on a different network. The agent also works fully unpaired (local MAVLink, local video, local REST API).

## Local pairing over the LAN (default)

When Mission Control and the agent are on the same network, the GCS reaches the agent directly. In the Add-a-Node card, enter the agent's hostname, IP address, or `.local` mDNS name. The GCS calls the agent's `/api/pairing/info` (probe) and `/api/pairing/claim` (claim) over the LAN and stores the returned API key locally in the browser. No cloud account or internet connection is required.

Claiming works only while the agent is unpaired, so being on the same LAN is the authorization boundary. An agent in local mode (cloud relay off) is the default and is correct, not a misconfiguration.

## Cloud pairing for remote access

For a drone on a different network, use the cloud pairing code. This path requires the agent to be reachable through the cloud relay.

<Steps>
  <Step title="Agent generates a pairing code">
    On first boot (or after unpairing), the agent generates a 6-character alphanumeric pairing code. The code has a 15-minute TTL and regenerates after expiry.
  </Step>

  <Step title="You enter the code in Mission Control">
    Open ADOS Mission Control, go to the Hardware tab, and click "Pair New Device." Enter the 6-character code displayed by the agent.
  </Step>

  <Step title="Cloud exchange">
    Mission Control sends the pairing code to the Convex backend. The backend validates it, associates the device with your account, and generates an API key.
  </Step>

  <Step title="Agent receives the API key">
    The agent polls the Convex pairing endpoint every 30 seconds (configurable via `pairing.beacon_interval`). When the backend confirms the pairing, the agent stores the API key at `/etc/ados/pairing.json` and begins sending telemetry to the cloud.
  </Step>

  <Step title="Drone appears in your dashboard">
    The drone shows up in Mission Control with its name, board type, and live telemetry. You can rename it, send commands, and view video.
  </Step>
</Steps>

## Pair during install

The fastest way to pair is during installation:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -sSL https://raw.githubusercontent.com/altnautica/ADOSDroneAgent/main/scripts/install.sh | sudo bash -s -- --pair YOUR_CODE
```

This skips the beacon polling step. The install script writes the API key directly.

## Pair an existing agent

Run `ados`, open the setup URL shown in the terminal, and use the setup webapp
pairing page. If the agent is running a hotspot, connect to it and open
`http://192.168.4.1`.

Mission Control can also open the setup webapp from Hardware surfaces when the
agent advertises a setup URL.

## Pairing state file

After pairing, the agent stores credentials at `/etc/ados/pairing.json`:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "paired": true,
  "device_id": "a1b2c3d4",
  "owner_id": "user_abc123",
  "api_key": "sk_live_...",
  "paired_at": 1713264000
}
```

<Warning>
  The `api_key` authenticates the agent to the cloud backend and the local REST API. Protect this file. The install script sets permissions to `0600` (owner read/write only). Do not share this key.
</Warning>

## Unpairing

Unpairing disconnects the agent from your cloud account. The drone disappears from Mission Control and stops sending telemetry.

Use Mission Control or the setup webapp to unpair a device.

From the REST API:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST http://localhost:8080/api/pairing/unpair \
  -H "X-ADOS-Key: sk_live_..."
```

After unpairing:

* A new pairing code is generated immediately
* The old API key is invalidated
* `/etc/ados/pairing.json` is updated
* Cloud relay services stop sending data
* Local functionality (MAVLink, video, REST API) continues working

## API key authentication

Once paired, the REST API requires the `X-ADOS-Key` header on most endpoints. A few endpoints are exempt (like `/api/pairing/info`) so local setup and status surfaces can check pairing state without a key.

The CLI reads the key from `/etc/ados/pairing.json` automatically. If you are calling the API from your own code, include the header:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl http://localhost:8080/api/status \
  -H "X-ADOS-Key: sk_live_your_key_here"
```

## Configuration

Pairing behavior is controlled in `/etc/ados/config.yaml`:

```yaml theme={"theme":{"light":"github-light","dark":"github-dark"}}
pairing:
  state_path: "/etc/ados/pairing.json"
  beacon_interval: 30    # Seconds between cloud poll attempts
  heartbeat_interval: 60  # Seconds between heartbeat pings
  code_ttl: 900           # Pairing code validity in seconds (15 min)
```

## mDNS discovery

The agent advertises itself via mDNS as `_ados._tcp.local.` when discovery is enabled (default). This allows Mission Control to find drones on the local network without knowing their IP addresses.

```yaml theme={"theme":{"light":"github-light","dark":"github-dark"}}
discovery:
  mdns_enabled: true
  service_type: "_ados._tcp.local."
```

When you open Mission Control on the same network as the drone, it discovers the agent automatically and shows it in the connection list.

<Tip>
  mDNS discovery works without pairing. You can connect to an unpaired drone on your local network and use all features except cloud relay.
</Tip>
