API and Real-Time Reference¶
OpenCrate exposes an Axum-based REST API (feature-gated with api) and a WebSocket endpoint for live updates. This document covers every route module, the security model, and the real-time protocol.
API State¶
The API server is built from the Platform. ApiState is an Axum extension containing 25 fields:
- All 14 AutomationState stores
- PointStore, NodeStore, EventBus
- HealthRegistry
- UserStore, AuditStore, OverrideStore
- JWT secret
- BackupScheduler
- Rate limiters (per-IP and global)
- BridgeRegistry
Security¶
Authentication¶
All endpoints except POST /api/auth/login require a valid JWT in the Authorization: Bearer <token> header.
Login flow:
POST /api/auth/loginwith{ "username": "...", "password": "..." }- Server returns
{ "token": "...", "expires_at": "..." } - Client includes token in all subsequent requests
Tokens carry the user's role and permissions. Expired tokens return 401 Unauthorized.
Authorization¶
Role-based access control with permissions attached to each role. Endpoints check specific permissions:
| Permission | Allowed Roles | Used By |
|---|---|---|
ManageNotifications |
Admin | Notification routing config |
ManageWebhooks |
Admin | Webhook endpoint CRUD |
ManageMqtt |
Admin | MQTT broker config |
ManageReports |
Admin, Operator | Report definitions and schedules |
ManageEnergy |
Admin, Operator | Energy meters and rates |
ManageCommissioning |
Admin, Operator | Commissioning sessions |
ShelveAlarm |
Admin, Operator | Alarm shelving |
WritePoints |
Admin, Operator | Point value writes |
AcknowledgeAlarms |
Admin, Operator | Alarm acknowledgment |
ManagePrograms |
Admin | Logic program CRUD |
ManageSchedules |
Admin, Operator | Schedule CRUD |
ManageUsers |
Admin | User CRUD |
ManageDiscovery |
Admin | Device discovery and acceptance |
Rate Limiting¶
Two layers:
- Per-IP rate limiter -- prevents individual clients from overwhelming the server
- Global rate limiter -- protects total server capacity
Rate-limited requests receive 429 Too Many Requests with a Retry-After header.
Security Headers¶
Every response includes:
X-Content-Type-Options: nosniffX-Frame-Options: DENYStrict-Transport-Security: max-age=31536000; includeSubDomains(HSTS)Referrer-Policy: strict-origin-when-cross-origin
CORS¶
Configurable CORS policy. In development, allows localhost origins. In production, must be explicitly configured.
Body Limit¶
All requests are capped at 1 MB to prevent abuse.
Route Modules¶
Points -- /api/points¶
| Method | Path | Description |
|---|---|---|
GET |
/api/points |
List all points with current values |
GET |
/api/points/:id |
Get a single point's value and status |
POST |
/api/points/:id/write |
Write a value to a point (routes through BridgeRegistry to field device) |
Nodes -- /api/nodes¶
| Method | Path | Description |
|---|---|---|
GET |
/api/nodes |
List all nodes (filterable by type, tag, parent) |
GET |
/api/nodes/:id |
Get a single node with full detail (tags, refs, properties, capabilities) |
POST |
/api/nodes |
Create a node |
PUT |
/api/nodes/:id |
Update a node |
DELETE |
/api/nodes/:id |
Delete a node |
GET |
/api/nodes/:id/children |
Get direct children of a node |
GET |
/api/nodes/:id/hierarchy |
Get full subtree (recursive) |
GET |
/api/nodes/by-tag/:tag |
Find nodes by tag |
Alarms -- /api/alarms¶
| Method | Path | Description |
|---|---|---|
GET |
/api/alarms |
List alarms (filterable by status, severity, device) |
GET |
/api/alarms/:id |
Get alarm detail |
POST |
/api/alarms/:id/acknowledge |
Acknowledge an alarm (sends BACnet ack for BACnet devices) |
POST |
/api/alarms/:id/shelve |
Shelve an alarm (with expiration) |
POST |
/api/alarms/:id/unshelve |
Remove shelving |
GET |
/api/alarms/summary |
Alarm counts by severity and status |
History -- /api/history¶
| Method | Path | Description |
|---|---|---|
GET |
/api/history/:point_id |
Get trend data for a point (query params: start, end, interval) |
GET |
/api/history/:point_id/rollup |
Get aggregated data (min, max, avg, sum over intervals) |
Schedules -- /api/schedules¶
| Method | Path | Description |
|---|---|---|
GET |
/api/schedules |
List all schedules |
GET |
/api/schedules/:id |
Get schedule detail |
POST |
/api/schedules |
Create a schedule |
PUT |
/api/schedules/:id |
Update a schedule |
DELETE |
/api/schedules/:id |
Delete a schedule |
Discovery -- /api/discovery¶
| Method | Path | Description |
|---|---|---|
POST |
/api/discovery/scan |
Initiate a discovery scan (BACnet Who-Is, Modbus ID scan) |
GET |
/api/discovery/devices |
List discovered devices |
GET |
/api/discovery/devices/:id |
Get device detail with discovered points |
POST |
/api/discovery/devices/:id/accept |
Accept a discovered device (creates nodes) |
POST |
/api/discovery/devices/:id/ignore |
Ignore a discovered device |
GET |
/api/discovery/status |
Current scan status |
Programs -- /api/programs¶
| Method | Path | Description |
|---|---|---|
GET |
/api/programs |
List all logic programs |
GET |
/api/programs/:id |
Get program detail (block graph + compiled Rhai) |
POST |
/api/programs |
Create a program |
PUT |
/api/programs/:id |
Update a program |
DELETE |
/api/programs/:id |
Delete a program |
POST |
/api/programs/:id/execute |
Manually trigger program execution |
GET |
/api/programs/:id/log |
Get execution log (last 100 entries) |
Reports -- /api/reports¶
| Method | Path | Description |
|---|---|---|
GET |
/api/reports |
List report definitions |
GET |
/api/reports/:id |
Get report definition |
POST |
/api/reports |
Create a report definition |
PUT |
/api/reports/:id |
Update a report definition |
DELETE |
/api/reports/:id |
Delete a report definition |
POST |
/api/reports/:id/run |
Run a report now |
GET |
/api/reports/:id/preview |
Preview rendered HTML |
GET |
/api/reports/templates |
List available report templates |
GET |
/api/reports/schedules |
List report schedules |
POST |
/api/reports/schedules |
Create a report schedule |
PUT |
/api/reports/schedules/:id |
Update a report schedule |
DELETE |
/api/reports/schedules/:id |
Delete a report schedule |
Energy -- /api/energy¶
| Method | Path | Description |
|---|---|---|
GET |
/api/energy/meters |
List energy meters |
POST |
/api/energy/meters |
Create an energy meter |
PUT |
/api/energy/meters/:id |
Update an energy meter |
DELETE |
/api/energy/meters/:id |
Delete an energy meter |
GET |
/api/energy/rates |
List utility rate structures |
POST |
/api/energy/rates |
Create a rate structure |
PUT |
/api/energy/rates/:id |
Update a rate structure |
DELETE |
/api/energy/rates/:id |
Delete a rate structure |
GET |
/api/energy/summary |
Energy dashboard summary (consumption, demand, cost) |
GET |
/api/energy/consumption |
Consumption data (filterable by meter, date range) |
GET |
/api/energy/export |
Export energy data as CSV |
Webhooks -- /api/webhooks¶
| Method | Path | Description |
|---|---|---|
GET |
/api/webhooks |
List webhook endpoints |
POST |
/api/webhooks |
Create a webhook endpoint |
PUT |
/api/webhooks/:id |
Update a webhook endpoint |
DELETE |
/api/webhooks/:id |
Delete a webhook endpoint |
POST |
/api/webhooks/:id/test |
Send a test delivery |
GET |
/api/webhooks/:id/deliveries |
List delivery log for an endpoint |
GET |
/api/webhooks/deliveries |
List all deliveries (filterable by status) |
GET |
/api/webhooks/config |
Get global webhook config (pause state) |
FDD (Fault Detection) -- /api/fdd¶
| Method | Path | Description |
|---|---|---|
GET |
/api/fdd/rules |
List fault detection rules |
POST |
/api/fdd/rules |
Create a rule |
PUT |
/api/fdd/rules/:id |
Update a rule |
DELETE |
/api/fdd/rules/:id |
Delete a rule |
GET |
/api/fdd/faults |
List active and historical faults |
GET |
/api/fdd/faults/:id |
Get fault detail |
Export -- /api/export¶
| Method | Path | Description |
|---|---|---|
GET |
/api/export/targets |
List export targets (InfluxDB, Postgres) |
POST |
/api/export/targets |
Create an export target |
PUT |
/api/export/targets/:id |
Update an export target |
DELETE |
/api/export/targets/:id |
Delete an export target |
POST |
/api/export/targets/:id/test |
Test connectivity to an export target |
Overrides -- /api/overrides¶
| Method | Path | Description |
|---|---|---|
GET |
/api/overrides |
List active overrides |
POST |
/api/overrides |
Create an override (with optional expiry) |
DELETE |
/api/overrides/:id |
Remove an override |
Users -- /api/users¶
| Method | Path | Description |
|---|---|---|
GET |
/api/users |
List users |
POST |
/api/users |
Create a user |
PUT |
/api/users/:id |
Update a user |
DELETE |
/api/users/:id |
Delete a user |
POST |
/api/auth/login |
Authenticate and receive JWT |
Audit -- /api/audit¶
| Method | Path | Description |
|---|---|---|
GET |
/api/audit |
Query audit log (filterable by user, action, date range) |
GET |
/api/audit/actions |
List all audit action types |
System -- /api/system¶
| Method | Path | Description |
|---|---|---|
GET |
/api/system/health |
Per-component health status |
GET |
/api/system/info |
Version, uptime, build info |
POST |
/api/system/backup |
Trigger a database backup |
GET |
/api/system/backup/status |
Backup scheduler status |
WebSocket -- /ws¶
The WebSocket endpoint provides real-time push updates to connected clients (the GUI and any external integrations).
Connection¶
Connect to ws://<host>:<port>/ws with a valid JWT as a query parameter or in the initial HTTP upgrade headers.
Message Format¶
All messages are JSON:
{
"type": "value_changed",
"payload": {
"node_id": "1001/analog-input-1",
"value": 72.5,
"status": "ok",
"timestamp": "2026-03-31T14:30:00Z"
}
}
Event Types¶
The WebSocket forwards a subset of EventBus events to connected clients:
| Type | Description |
|---|---|
value_changed |
A point value was updated |
status_changed |
A point's status flags changed |
alarm_raised |
A new alarm was raised |
alarm_cleared |
An alarm returned to normal |
alarm_acknowledged |
An alarm was acknowledged |
device_discovered |
A new device was found during discovery |
device_down |
A device stopped responding |
device_recovered |
A previously down device came back online |
fdd_fault_raised |
A fault detection rule triggered |
fdd_fault_cleared |
A fault detection rule returned to normal |
Subscription Filtering¶
Clients can send subscription messages to filter which events they receive:
{
"subscribe": {
"node_ids": ["1001/analog-input-1", "1001/analog-input-2"],
"event_types": ["value_changed", "alarm_raised"]
}
}
Without a subscription filter, all events are forwarded.
Error Responses¶
All error responses follow a consistent format:
Standard HTTP status codes:
| Code | Meaning |
|---|---|
400 |
Bad request (invalid JSON, missing fields) |
401 |
Unauthorized (missing or expired JWT) |
403 |
Forbidden (insufficient permissions) |
404 |
Not found |
409 |
Conflict (duplicate ID, concurrent modification) |
422 |
Unprocessable entity (validation failure) |
429 |
Rate limited |
500 |
Internal server error |