# ARC Labs API Guide — External Access

> **Version 1.0** — Read-only API access for external systems, dashboards, and integrations.

## Overview

ARC Labs provides a REST API for accessing grow data — telemetry, devices, rooms, runs, conditions, and more. External systems can authenticate using **API keys** for read-only access without needing user credentials.

## Authentication

### API Key (recommended for external systems)

Send your API key in the `X-API-Key` header:

```
GET /api/devices
Host: arclabcanna.com
X-API-Key: arc_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

API keys are:
- **Read-only** — only GET requests are allowed
- **Org-scoped** — a key can only access data for the organization it was created for
- **Revocable** — keys can be deactivated anytime by an admin
- **Rate-limited** — 60 requests per minute per key (configurable)

### Bearer Token (for interactive sessions)

```
GET /api/devices
Host: arclabcanna.com
Authorization: Bearer <jwt_token>
X-Org-ID: <org-uuid>
```

Bearer tokens are obtained via login (POST /auth/login) and are for interactive use only. Use API keys for automated systems.

## Getting an API Key

1. **Request access**: Email info@arclabcanna.com with your org name and use case
2. **Admin creates key**: An ARC Labs admin creates your key in the admin console
2. Go to **Admin** → **API Keys** section
3. Click **Create API Key**
4. Enter a name (e.g., "Greenhouse Dashboard", "Reporting Bot")
5. Click Create — the key is shown **once**. Copy it immediately.
6. Use the key in your external system's `X-API-Key` header

API keys look like: `arc_AbCdEfGhIjKlMnOpQrStUvWxYz1234567890`

## Base URL

```
https://arclabcanna.com
```

All endpoints are under `/api/` (sidecar) or `/` (main API).

## Endpoints

### Devices

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/devices` | List all devices in your org |
| GET | `/api/integrations/devices` | List devices with integration status |

**Example response:**
```json
[
  {
    "id": 2250536,
    "name": "Room-9 Media",
    "kind": "media_probe",
    "room_id": "bd9e5c2b-...",
    "zone_id": "3",
    "device_type": "cloud_agent"
  }
]
```

### Telemetry

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/telem/latest?device_id=<id>` | Latest readings for a device |
| GET | `/api/telem/query?device_id=<id>&since=<ISO>&until=<ISO>&limit=<n>` | Historical telemetry |

**Query parameters:**
- `device_id` (required) — device ID
- `since` (optional) — ISO 8601 timestamp, default 24h ago
- `until` (optional) — ISO 8601 timestamp, default now
- `order` (optional) — `asc` or `desc`, default `asc`
- `limit` (optional) — max rows, default 1000, max 50000
- `keys` (optional) — comma-separated metric names (e.g., `vwc_pct,ec_mScm`)

**Example response:**
```json
{
  "ok": true,
  "count": 5,
  "since": "2026-08-21T00:00:00Z",
  "until": "2026-08-21T23:59:59Z",
  "rows": [
    [2250536, "bd9e5c2b-...", "vwc_pct", 51.0, "2026-08-21T18:24:19Z"],
    [2250536, "bd9e5c2b-...", "ec_mScm", 6.05, "2026-08-21T18:24:19Z"]
  ]
}
```

### Rooms

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/rooms` | List all rooms in your org |

### Runs (Grow Cycles)

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/lifecycle/runs` | List all runs |
| GET | `/api/lifecycle/runs/{run_id}` | Get run details |

### Conditions (Watering Status)

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/conditions/{controller_id}/decisions` | Watering decision history |
| GET | `/api/controller/condition-monitor/today-summary` | Today's watering summary |

### Health

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/health` | System health check (no auth required) |

## Common Metrics

| Key | Unit | Description |
|-----|------|-------------|
| `vwc_pct` | % | Volumetric water content (media moisture) |
| `ec_mScm` | mS/cm | Electrical conductivity (nutrient strength) |
| `media_temp_c` | °C | Media temperature |
| `temp_c` | °C | Air temperature |
| `temp_f` | °F | Air temperature |
| `rh_pct` | % | Relative humidity |
| `co2_ppm` | ppm | CO2 concentration |
| `lux` | lux | Light intensity |
| `lights_on` | 0/1 | Lights status |
| `battery_pct` | % | Device battery level |

## Rate Limiting

- API keys: 60 requests/minute (configurable per key)
- Login: 5 attempts/minute
- Bearer token: 60 requests/minute (general API zone)
- Rate limit headers are included in responses

## Error Responses

| Status | Meaning |
|--------|---------|
| 200 | Success |
| 401 | Invalid or missing API key |
| 403 | API key is read-only (tried POST/PATCH/DELETE) |
| 404 | Resource not found |
| 429 | Rate limit exceeded |
| 500 | Server error |

**Error format:**
```json
{
  "detail": "Invalid API key"
}
```

## Code Examples

### Python
```python
import requests

API_KEY = "arc_xxxxxxxx..."
BASE = "https://arclabcanna.com"

headers = {"X-API-Key": API_KEY}

# Get all devices
resp = requests.get(f"{BASE}/api/devices", headers=headers)
devices = resp.json()

# Get latest telemetry for a device
resp = requests.get(f"{BASE}/api/telem/latest?device_id=2250536", headers=headers)
telemetry = resp.json()

# Query historical telemetry (last 24h)
resp = requests.get(
    f"{BASE}/api/telem/query",
    params={"device_id": 2250536, "limit": 1000, "order": "desc"},
    headers=headers
)
history = resp.json()
```

### JavaScript / Node.js
```javascript
const API_KEY = "arc_xxxxxxxx...";
const BASE = "https://arclabcanna.com";

const headers = { "X-API-Key": API_KEY };

// Get all devices
const devices = await fetch(`${BASE}/api/devices`, { headers })
  .then(r => r.json());

// Get latest telemetry
const telemetry = await fetch(
  `${BASE}/api/telem/latest?device_id=2250536`,
  { headers }
).then(r => r.json());
```

### cURL
```bash
# List devices
curl -H "X-API-Key: arc_xxxxxxxx..." https://arclabcanna.com/api/devices

# Get latest telemetry
curl -H "X-API-Key: arc_xxxxxxxx..." https://arclabcanna.com/api/telem/latest?device_id=2250536

# Query historical data (last 7 days, VWC only)
curl -H "X-API-Key: arc_xxxxxxxx..." \
  "https://arclabcanna.com/api/telem/query?device_id=2250536&since=2026-08-14T00:00:00Z&keys=vwc_pct&limit=50000"
```

## Security

- API keys are **hashed** in the database (SHA-256) — the full key is only shown once on creation
- Keys are **org-scoped** — they can only access data within the organization they belong to
- Keys are **read-only** — no data modification is possible
- Keys can be **revoked** instantly by an admin
- Keys can have an **expiration date** — set during creation
- All API access is over **HTTPS** only
- **Row Level Security (RLS)** is enforced at the database level — even if a key is compromised, it can only see its org's data

## Support

- **Create keys**: Admin → API Keys section
- **Revoke keys**: Admin → API Keys → Revoke
- **Issues**: Contact your ARC Labs administrator