Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions docs/api-reference/endpoints.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,114 @@

Detailed documentation for all REST API endpoints.

!!! info "Authentication required"
All endpoints require an `X-API-Key` header. GET endpoints need `read_access`; POST/PUT/DELETE endpoints need `write_access`. See [API Key Management](../getting-started/api-keys.md).

## API Key Endpoints

### List API Keys

```
GET /v1/api-keys
```

Requires `read_access`.

**Query Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `active_only` | boolean | Filter to active keys only (default: false) |

**Response:**

```json
{
"errorCode": 0,
"errorMessage": null,
"payload": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"app_name": "my-app",
"read_access": true,
"write_access": true,
"is_active": true,
"created_at": "2026-03-27T10:00:00Z",
"updated_at": "2026-03-27T10:00:00Z"
}
]
}
```

### Create API Key

```
POST /v1/api-keys
```

Requires `write_access`.

**Request Body:**

```json
{
"appName": "new-client",
"readAccess": true,
"writeAccess": false
}
```

**Response:**

```json
{
"errorCode": 0,
"errorMessage": null,
"payload": {
"id": "660e8400-e29b-41d4-a716-446655440001",
"app_name": "new-client",
"token": "sq_abc123...",
"read_access": true,
"write_access": false,
"is_active": true,
"created_at": "2026-03-27T12:00:00Z"
}
}
```

!!! warning
The `token` field only appears in the creation response. It cannot be retrieved again.

### Deactivate API Key

```
DELETE /v1/api-keys/{id}
```

Requires `write_access`. Soft-deletes the key (sets `is_active=False`).

**Path Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `id` | UUID | API key ID |

### Count API Keys

```
GET /v1/api-keys/count
```

Requires `read_access`.

**Query Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `active_only` | boolean | Count only active keys (default: false) |

---

## PV Endpoints

### Search PVs
Expand Down
40 changes: 39 additions & 1 deletion docs/api-reference/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,45 @@ GET /v1/pvs/paged?cursor=abc123

## Authentication

Currently, the API does not require authentication. This may change in future versions.
All endpoints require an API key passed via the `X-API-Key` header:

```
X-API-Key: sq_your_token_here
```

Requests without a valid key return `401 Unauthorized`.

### Permission Levels

| Permission | Required for |
|------------|--------------|
| `read_access` | GET requests, WebSocket connections |
| `write_access` | POST, PUT, DELETE requests |

### Getting an API Key

Use the management script to create your first key:

```bash
# Docker
docker exec squirrel-api python -m scripts.create_key my-app --read --write
Comment thread
zdomke marked this conversation as resolved.
Outdated

# Local development
python -m scripts.create_key my-app --read --write
Comment thread
zdomke marked this conversation as resolved.
Outdated
```

See [API Key Management](../getting-started/api-keys.md) for full details on creating and managing keys.

### API Key Endpoints

The `/v1/api-keys` endpoints allow managing keys via the REST API (requires `write_access`):

| Method | Endpoint | Description |
|--------|----------|-------------|
| `GET` | `/v1/api-keys` | List all API keys |
| `POST` | `/v1/api-keys` | Create a new API key |
| `DELETE` | `/v1/api-keys/{id}` | Deactivate an API key |
| `GET` | `/v1/api-keys/count` | Count API keys |

## Rate Limiting

Expand Down
30 changes: 19 additions & 11 deletions docs/api-reference/websocket.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ The WebSocket API provides real-time PV value streaming with diff-based updates.

## Connection

Connect to the WebSocket endpoint:
Connect to the WebSocket endpoint and include your API key in the `X-API-Key` header:

```
ws://localhost:8080/ws
Expand All @@ -16,6 +16,9 @@ Or for local development:
ws://localhost:8000/ws
```

!!! info "Authentication"
WebSocket connections require an `X-API-Key` header with a key that has `read_access`. Connections without a valid key are rejected with close code `1008 (Policy Violation)`. See [API Key Management](../getting-started/api-keys.md).

## Message Format

All messages are JSON objects with an `action` field.
Expand Down Expand Up @@ -112,7 +115,9 @@ Multiple updates are batched together (100ms window):
## JavaScript Example

```javascript
const ws = new WebSocket('ws://localhost:8080/ws');
const ws = new WebSocket('ws://localhost:8080/ws', [], {
headers: { 'X-API-Key': 'sq_your_token_here' }
});

ws.onopen = () => {
console.log('Connected to WebSocket');
Expand Down Expand Up @@ -167,8 +172,9 @@ import websockets

async def subscribe_to_pvs():
uri = "ws://localhost:8080/ws"
headers = {"X-API-Key": "sq_your_token_here"}

async with websockets.connect(uri) as websocket:
async with websockets.connect(uri, additional_headers=headers) as websocket:
# Subscribe to PVs
await websocket.send(json.dumps({
"action": "subscribe",
Expand Down Expand Up @@ -204,12 +210,14 @@ interface PVValue {
severity: number;
}

function usePVSubscription(pvNames: string[]) {
function usePVSubscription(pvNames: string[], apiKey: string) {
const [values, setValues] = useState<Record<string, PVValue>>({});
const [connected, setConnected] = useState(false);

useEffect(() => {
const ws = new WebSocket('ws://localhost:8080/ws');
const ws = new WebSocket('ws://localhost:8080/ws', [], {
headers: { 'X-API-Key': apiKey }
});

ws.onopen = () => {
setConnected(true);
Expand Down Expand Up @@ -260,10 +268,10 @@ function usePVSubscription(pvNames: string[]) {

// Usage
function PVDisplay() {
const { values, connected } = usePVSubscription([
'QUAD:LI21:201:BDES',
'QUAD:LI21:201:BACT'
]);
const { values, connected } = usePVSubscription(
['QUAD:LI21:201:BDES', 'QUAD:LI21:201:BACT'],
'sq_your_token_here'
);

return (
<div>
Expand Down Expand Up @@ -349,13 +357,13 @@ The server sends periodic heartbeat messages to keep connections alive:
Implement reconnection logic in your client:

```javascript
function createReconnectingWebSocket(url, onMessage) {
function createReconnectingWebSocket(url, apiKey, onMessage) {
let ws;
let reconnectInterval = 1000;
const maxInterval = 30000;

function connect() {
ws = new WebSocket(url);
ws = new WebSocket(url, [], { headers: { 'X-API-Key': apiKey } });

ws.onopen = () => {
console.log('Connected');
Expand Down
Loading
Loading