REST API
EnerOS REST API follows RESTful conventions, using standard HTTP method semantics, with all response bodies in JSON. Endpoints are provided by the eneros-api crate, validated by eneros-gateway and forwarded to the kernel. Each endpoint goes through the complete authentication, rate limiting, and audit chain.
Common Conventions
HTTP Method Semantics
| Method | Semantics | Idempotent | Safe | Request Body | Typical Use |
|---|---|---|---|---|---|
| GET | Read resource | Yes | Yes | No | Query list/details |
| POST | Create resource / Trigger action | No | No | Yes | Create network, trigger load flow |
| PUT | Full update resource | Yes | No | Yes | Replace resource |
| PATCH | Partial update resource | No | No | Yes | Modify fields |
| DELETE | Delete resource | Yes | No | No | Delete resource |
Endpoint List
| Method | Path | Description | Auth | Rate Limit |
|---|---|---|---|---|
| GET | /api/v1/health | Health check | No | 60/min |
| POST | /api/v1/auth/token | Get Token | No | 30/min |
| POST | /api/v1/auth/refresh | Refresh Token | Yes | 30/min |
| GET | /api/v1/networks | Network list | Yes | 600/min |
| POST | /api/v1/networks | Create network | Yes | 60/min |
| GET | /api/v1/networks/{id} | Network details | Yes | 600/min |
| PUT | /api/v1/networks/{id} | Update network | Yes | 60/min |
| DELETE | /api/v1/networks/{id} | Delete network | Yes | 30/min |
| POST | /api/v1/networks/{id}/powerflow | Trigger load flow calculation | Yes | 30/min |
| POST | /api/v1/networks/{id}/validate | Validate topology | Yes | 60/min |
| GET | /api/v1/agents | Agent list | Yes | 600/min |
| POST | /api/v1/agents | Create Agent | Yes | 60/min |
| GET | /api/v1/agents/{id} | Agent details | Yes | 600/min |
| PUT | /api/v1/agents/{id} | Update Agent configuration | Yes | 60/min |
| DELETE | /api/v1/agents/{id} | Delete Agent | Yes | 30/min |
| POST | /api/v1/agents/{id}/command | Dispatch Agent command | Yes | 100/min |
| POST | /api/v1/agents/{id}/pause | Pause Agent | Yes | 60/min |
| POST | /api/v1/agents/{id}/resume | Resume Agent | Yes | 60/min |
| GET | /api/v1/devices | Device list | Yes | 600/min |
| GET | /api/v1/devices/{id} | Device details | Yes | 600/min |
| PATCH | /api/v1/devices/{id} | Update device status | Yes | 60/min |
| GET | /api/v1/timeseries | Time-series data query | Yes | 600/min |
| POST | /api/v1/timeseries/batch | Batch write time-series | Yes | 1000/min |
| GET | /api/v1/events | Event history | Yes | 600/min |
| GET | /api/v1/alarms | Alarm list | Yes | 600/min |
| PATCH | /api/v1/alarms/{id}/ack | Acknowledge alarm | Yes | 60/min |
| GET | /api/v1/audit | Audit log | Yes | 600/min |
| GET | /api/v1/tasks/{id} | Task status query | Yes | 600/min |
| DELETE | /api/v1/tasks/{id} | Cancel task | Yes | 30/min |
Pagination, Filtering, Sorting
Pagination Parameters
List endpoints uniformly support the following pagination parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
page | int | No | 1 | Page number, starting from 1 |
page_size | int | No | 20 | Items per page, max 100 |
cursor | string | No | — | Cursor (for cursor pagination, takes precedence over page) |
Pagination response:
{
"data": [/* ... */],
"meta": {
"page": 1,
"page_size": 20,
"total": 137,
"total_pages": 7,
"next_cursor": "eyJpZCI6Im5ldF94eHgifQ=="
}
}
Filter Parameters
Examples of filter fields supported by each endpoint:
| Endpoint | Filter Fields | Example |
|---|---|---|
/networks | status, name | ?status=ready&name=IEEE |
/agents | status, type | ?status=running&type=dispatch |
/devices | type, online | ?type=PV&online=true |
/alarms | severity, status, from, to | ?severity=critical&from=2026-07-06T00:00:00Z |
/events | topic, from, to | ?topic=alarm.critical&from=... |
Sort Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
sort | string | No | -created_at | Prefix - for descending order |
sort multi-field | string | No | — | Comma-separated, e.g., name,-created_at |
Example: ?sort=-created_at&page=2&page_size=50
Endpoint Details
Health Check
GET /api/v1/health checks service availability, no authentication required.
Request Parameters: None
Response Fields:
| Field | Type | Description |
|---|---|---|
status | string | ok / degraded / down |
version | string | EnerOS version number |
uptime_seconds | int | Service uptime |
checks | object | Subsystem status |
cURL Example:
curl http://localhost:8080/api/v1/health
Response Example:
{
"data": {
"status": "ok",
"version": "0.47.0",
"uptime_seconds": 86400,
"checks": {
"database": "ok",
"timeseries": "ok",
"eventbus": "ok",
"realtime": "ok"
}
},
"request_id": "req_20260706_001",
"timestamp": "2026-07-06T08:30:00Z"
}
Get Token
POST /api/v1/auth/token exchanges username/password for a Bearer Token.
Request Parameters:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
username | string | Yes | — | Username |
password | string | Yes | — | Password |
tenant_id | string | No | Default tenant | Tenant ID |
scope | string | No | default | Permission scope |
cURL Example:
curl -X POST http://localhost:8080/api/v1/auth/token \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin"}'
Response Example:
{
"data": {
"token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "rft_20260706_abc123",
"expires_in": 3600,
"token_type": "Bearer"
},
"request_id": "req_20260706_002",
"timestamp": "2026-07-06T08:30:00Z"
}
Create Network
POST /api/v1/networks creates a new network model.
Request Parameters:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | Yes | — | Network name, max 64 characters |
description | string | No | "" | Description, max 256 characters |
base_kv | float | No | 110.0 | Base voltage (kV) |
base_mva | float | No | 100.0 | Base capacity (MVA) |
buses | array | Yes | — | Bus list, at least 1 |
buses[].id | int | Yes | — | Bus number |
buses[].type | string | Yes | — | slack / pv / pq |
buses[].v | float | No | 1.0 | Voltage per-unit (required for slack/pv) |
buses[].theta | float | No | 0.0 | Phase angle (radians, required for slack) |
buses[].area | int | No | 1 | Area number |
branches | array | No | [] | Branch list |
branches[].from | int | Yes | — | From bus |
branches[].to | int | Yes | — | To bus |
branches[].r | float | Yes | — | Resistance per-unit |
branches[].x | float | Yes | — | Reactance per-unit |
branches[].b | float | No | 0.0 | Charging susceptance per-unit |
generators | array | No | [] | Generator list |
loads | array | No | [] | Load list |
tags | object | No | {} | Custom tags |
cURL Example:
curl -X POST http://localhost:8080/api/v1/networks \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"name": "IEEE-14",
"base_kv": 110.0,
"base_mva": 100.0,
"buses": [
{"id": 1, "type": "slack", "v": 1.05, "theta": 0.0},
{"id": 2, "type": "pv", "v": 1.04},
{"id": 3, "type": "pq"}
],
"branches": [
{"from": 1, "to": 2, "r": 0.01938, "x": 0.05917, "b": 0.0528}
],
"generators": [
{"bus": 1, "mw": 50.0, "mvar": 0.0}
],
"loads": [
{"bus": 3, "mw": 94.2, "mvar": 19.0}
],
"tags": {"owner": "ieee", "scenario": "summer"}
}'
Rust Example:
use eneros_sdk::{ApiClient, models::NetworkInput};
use serde_json::json;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let client = ApiClient::builder()
.endpoint("http://localhost:8080")
.token("<bearer-token>")
.build()?;
let input = NetworkInput {
name: "IEEE-14".to_string(),
base_kv: Some(110.0),
base_mva: Some(100.0),
buses: vec![
json!({"id": 1, "type": "slack", "v": 1.05, "theta": 0.0}),
json!({"id": 2, "type": "pv", "v": 1.04}),
json!({"id": 3, "type": "pq"}),
],
branches: vec![
json!({"from": 1, "to": 2, "r": 0.01938, "x": 0.05917, "b": 0.0528}),
],
generators: vec![json!({"bus": 1, "mw": 50.0, "mvar": 0.0})],
loads: vec![json!({"bus": 3, "mw": 94.2, "mvar": 19.0})],
tags: json!({"owner": "ieee", "scenario": "summer"}),
..Default::default()
};
let network = client.networks().create(&input).await?;
println!("created network: {}", network.id);
Ok(())
}
Python Example:
from eneros_sdk import ApiClient
client = ApiClient(
endpoint="http://localhost:8080",
token="<bearer-token>",
)
network = client.networks.create({
"name": "IEEE-14",
"base_kv": 110.0,
"base_mva": 100.0,
"buses": [
{"id": 1, "type": "slack", "v": 1.05, "theta": 0.0},
{"id": 2, "type": "pv", "v": 1.04},
{"id": 3, "type": "pq"},
],
"branches": [
{"from": 1, "to": 2, "r": 0.01938, "x": 0.05917, "b": 0.0528},
],
"generators": [{"bus": 1, "mw": 50.0, "mvar": 0.0}],
"loads": [{"bus": 3, "mw": 94.2, "mvar": 19.0}],
"tags": {"owner": "ieee", "scenario": "summer"},
})
print(f"created network: {network.id}")
Response Example:
{
"data": {
"id": "net_8f3a2b",
"name": "IEEE-14",
"description": "",
"base_kv": 110.0,
"base_mva": 100.0,
"bus_count": 14,
"branch_count": 20,
"generator_count": 5,
"load_count": 11,
"status": "ready",
"tags": {"owner": "ieee", "scenario": "summer"},
"created_at": "2026-07-06T08:30:00Z",
"updated_at": "2026-07-06T08:30:00Z"
},
"request_id": "req_20260706_003",
"timestamp": "2026-07-06T08:30:00Z"
}
Get Network List
GET /api/v1/networks returns the list of networks under the current tenant.
Request Parameters (Query):
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
page | int | No | 1 | Page number |
page_size | int | No | 20 | Items per page |
status | string | No | — | Filter status |
name | string | No | — | Fuzzy match name |
tag | string | No | — | Filter by tag, format key:value |
sort | string | No | -created_at | Sort field |
Response Example:
{
"data": [
{
"id": "net_8f3a2b",
"name": "IEEE-14",
"bus_count": 14,
"status": "ready",
"created_at": "2026-07-06T08:30:00Z"
},
{
"id": "net_9c4d1e",
"name": "IEEE-30",
"bus_count": 30,
"status": "ready",
"created_at": "2026-07-05T10:00:00Z"
}
],
"meta": {
"page": 1,
"page_size": 20,
"total": 2,
"total_pages": 1
},
"request_id": "req_20260706_004",
"timestamp": "2026-07-06T08:30:00Z"
}
Trigger Load Flow Calculation
POST /api/v1/networks/{id}/powerflow triggers a load flow calculation task.
Path Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Network ID |
Request Parameters:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
method | string | No | newton_raphson | Algorithm: newton_raphson / fast_decoupled / dc |
tolerance | float | No | 1e-8 | Convergence tolerance |
max_iterations | int | No | 50 | Maximum iterations |
async | bool | No | false | Whether to execute asynchronously |
flat_start | bool | No | false | Whether flat start |
timeout_ms | int | No | 30000 | Timeout (milliseconds) |
cURL Example:
curl -X POST http://localhost:8080/api/v1/networks/net_8f3a2b/powerflow \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"method": "newton_raphson", "tolerance": 1e-8, "max_iterations": 50}'
Response Example (synchronous mode):
{
"data": {
"task_id": "pf_20260706_001",
"network_id": "net_8f3a2b",
"status": "converged",
"method": "newton_raphson",
"iterations": 4,
"duration_ms": 12,
"tolerance": 1e-8,
"buses": [
{"id": 1, "v": 1.05, "theta": 0.0, "p_gen": 50.0, "q_gen": 12.5},
{"id": 2, "v": 1.04, "theta": -0.039, "p_gen": 0.0, "q_gen": 0.0}
],
"branches": [
{"from": 1, "to": 2, "p_from": 50.0, "q_from": 12.5, "loading": 0.45}
],
"losses": {"p_mw": 1.23, "q_mvar": 5.67},
"started_at": "2026-07-06T08:30:00Z",
"completed_at": "2026-07-06T08:30:00.012Z"
},
"request_id": "req_20260706_005",
"timestamp": "2026-07-06T08:30:00Z"
}
Response Example (asynchronous mode):
{
"data": {
"task_id": "pf_20260706_002",
"network_id": "net_8f3a2b",
"status": "queued",
"poll_url": "/api/v1/tasks/pf_20260706_002"
},
"request_id": "req_20260706_006",
"timestamp": "2026-07-06T08:30:00Z"
}
Create Agent
POST /api/v1/agents creates and registers a new Agent.
Request Parameters:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | Yes | — | Agent name |
type | string | Yes | — | dispatch / self_healing / trading / maintenance / planning |
network_id | string | No | — | Associated network ID |
config | object | No | {} | Agent configuration |
tools | array | No | [] | List of allowed tools |
reasoning_model | string | No | default | Reasoning model |
max_actions_per_minute | int | No | 60 | Maximum action frequency |
auto_start | bool | No | false | Auto-start after creation |
cURL Example:
curl -X POST http://localhost:8080/api/v1/agents \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"name": "DispatchAgent-01",
"type": "dispatch",
"network_id": "net_8f3a2b",
"config": {"objective": "economic", "horizon_minutes": 15},
"tools": ["powerflow", "topology", "forecast"],
"reasoning_model": "default",
"max_actions_per_minute": 30,
"auto_start": true
}'
JavaScript Example:
import { ApiClient } from '@eneros/sdk';
const client = new ApiClient({
endpoint: 'http://localhost:8080',
token: '<bearer-token>',
});
const agent = await client.agents.create({
name: 'DispatchAgent-01',
type: 'dispatch',
networkId: 'net_8f3a2b',
config: { objective: 'economic', horizonMinutes: 15 },
tools: ['powerflow', 'topology', 'forecast'],
reasoningModel: 'default',
maxActionsPerMinute: 30,
autoStart: true,
});
console.log('created agent:', agent.id);
Response Example:
{
"data": {
"id": "agent_dispatch_01",
"name": "DispatchAgent-01",
"type": "dispatch",
"network_id": "net_8f3a2b",
"status": "running",
"config": {"objective": "economic", "horizon_minutes": 15},
"tools": ["powerflow", "topology", "forecast"],
"reasoning_model": "default",
"max_actions_per_minute": 30,
"created_at": "2026-07-06T08:30:00Z",
"started_at": "2026-07-06T08:30:01Z"
},
"request_id": "req_20260706_007",
"timestamp": "2026-07-06T08:30:00Z"
}
Dispatch Agent Command
POST /api/v1/agents/{id}/command dispatches a command to an Agent.
Request Parameters:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
command | string | Yes | — | Command name |
params | object | No | {} | Command parameters |
priority | string | No | normal | low / normal / high / emergency |
timeout_ms | int | No | 5000 | Command timeout |
await_result | bool | No | true | Whether to wait for result |
cURL Example:
curl -X POST http://localhost:8080/api/v1/agents/agent_dispatch_01/command \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"command": "set_generation",
"params": {"bus": 2, "mw": 50.0},
"priority": "normal",
"timeout_ms": 5000,
"await_result": true
}'
Response Example:
{
"data": {
"command_id": "cmd_20260706_001",
"agent_id": "agent_dispatch_01",
"command": "set_generation",
"status": "success",
"result": {
"bus": 2,
"mw_set": 50.0,
"constraint_checked": true,
"audit_id": "aud_20260706_001"
},
"duration_ms": 12,
"executed_at": "2026-07-06T08:30:00Z"
},
"request_id": "req_20260706_008",
"timestamp": "2026-07-06T08:30:00Z"
}
Time-Series Data Query
GET /api/v1/timeseries queries time-series data, supporting aggregation and downsampling.
Request Parameters (Query):
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
metric | string | Yes | — | Metric name, e.g., branch_loading |
tags | string | No | — | Tag filter, format key:value,key2:value2 |
from | datetime | Yes | — | Start time (RFC 3339) |
to | datetime | Yes | — | End time |
aggregation | string | No | none | none / avg / sum / max / min / count |
interval | string | No | — | Downsampling interval, e.g., 1m / 5m / 1h |
fill | string | No | null | Missing value fill strategy: null / zero / linear |
limit | int | No | 10000 | Maximum return points |
cURL Example:
curl -G http://localhost:8080/api/v1/timeseries \
-H "Authorization: Bearer <token>" \
--data-urlencode "metric=branch_loading" \
--data-urlencode "tags=network:net_8f3a2b,branch:1-2" \
--data-urlencode "from=2026-07-06T00:00:00Z" \
--data-urlencode "to=2026-07-06T08:00:00Z" \
--data-urlencode "aggregation=avg" \
--data-urlencode "interval=5m"
Python Example:
from eneros_sdk import ApiClient
from datetime import datetime, timezone, timedelta
client = ApiClient(endpoint="http://localhost:8080", token="<bearer-token>")
result = client.timeseries.query(
metric="branch_loading",
tags={"network": "net_8f3a2b", "branch": "1-2"},
from_=datetime.now(timezone.utc) - timedelta(hours=8),
to=datetime.now(timezone.utc),
aggregation="avg",
interval="5m",
)
for point in result.points:
print(f"{point.timestamp} -> {point.value}")
Response Example:
{
"data": {
"metric": "branch_loading",
"tags": {"network": "net_8f3a2b", "branch": "1-2"},
"aggregation": "avg",
"interval": "5m",
"points": [
{"timestamp": "2026-07-06T00:00:00Z", "value": 0.42},
{"timestamp": "2026-07-06T00:05:00Z", "value": 0.45},
{"timestamp": "2026-07-06T00:10:00Z", "value": 0.48}
],
"count": 96
},
"request_id": "req_20260706_009",
"timestamp": "2026-07-06T08:30:00Z"
}
Batch Write Time-Series
POST /api/v1/timeseries/batch batch writes time-series data points, up to 10000 points per call.
Request Parameters:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
points | array | Yes | — | Data point array |
points[].metric | string | Yes | — | Metric name |
points[].timestamp | datetime | No | Current time | Timestamp |
points[].value | float | Yes | — | Value |
points[].tags | object | No | {} | Tags |
cURL Example:
curl -X POST http://localhost:8080/api/v1/timeseries/batch \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"points": [
{"metric": "branch_loading", "timestamp": "2026-07-06T08:30:00Z", "value": 0.42, "tags": {"network": "net_8f3a2b", "branch": "1-2"}},
{"metric": "bus_voltage", "timestamp": "2026-07-06T08:30:00Z", "value": 1.05, "tags": {"network": "net_8f3a2b", "bus": "1"}}
]
}'
Response Example:
{
"data": {
"accepted": 2,
"rejected": 0,
"errors": []
},
"request_id": "req_20260706_010",
"timestamp": "2026-07-06T08:30:00Z"
}
Alarm List and Acknowledgment
GET /api/v1/alarms gets alarm list, PATCH /api/v1/alarms/{id}/ack acknowledges alarm.
List Request Parameters:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
severity | string | No | — | info / warn / error / critical |
status | string | No | — | active / acknowledged / cleared |
network_id | string | No | — | Limit to network |
from | datetime | No | — | Start time |
to | datetime | No | — | End time |
Acknowledge Alarm Request Parameters:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
acknowledged_by | string | Yes | — | Acknowledger |
note | string | No | "" | Note |
Response Example (list):
{
"data": [
{
"id": "alm_001",
"severity": "critical",
"status": "active",
"type": "BRANCH_OVERLOAD",
"message": "Branch 1-2 overload: 105% of limit",
"network_id": "net_8f3a2b",
"source": {"type": "constraint_engine", "id": "ce_01"},
"details": {"branch_id": "1-2", "loading": 1.05, "limit": 1.0},
"raised_at": "2026-07-06T08:30:00Z",
"acknowledged_at": null,
"cleared_at": null
}
],
"meta": {"page": 1, "page_size": 20, "total": 1, "total_pages": 1},
"request_id": "req_20260706_011",
"timestamp": "2026-07-06T08:30:00Z"
}
Audit Log Query
GET /api/v1/audit queries operation audit logs, requires audit permission.
Request Parameters:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
actor | string | No | — | Operator |
action | string | No | — | Operation type |
resource_type | string | No | — | Resource type |
resource_id | string | No | — | Resource ID |
from | datetime | No | — | Start time |
to | datetime | No | — | End time |
page | int | No | 1 | Page number |
page_size | int | No | 50 | Items per page |
Response Example:
{
"data": [
{
"id": "aud_20260706_001",
"timestamp": "2026-07-06T08:30:00Z",
"actor": {"type": "user", "id": "admin", "tenant": "default"},
"action": "agent.command",
"resource": {"type": "agent", "id": "agent_dispatch_01"},
"request_id": "req_20260706_008",
"ip": "192.168.1.10",
"user_agent": "curl/7.88.1",
"result": "success",
"details": {"command": "set_generation", "params": {"bus": 2, "mw": 50.0}}
}
],
"meta": {"page": 1, "page_size": 50, "total": 1, "total_pages": 1},
"request_id": "req_20260706_012",
"timestamp": "2026-07-06T08:30:00Z"
}
Error Codes
Common Error Codes
| HTTP Status | Error Code | Meaning |
|---|---|---|
| 400 | INVALID_REQUEST | Invalid request parameters |
| 400 | INVALID_FIELD | Invalid field value |
| 401 | UNAUTHORIZED | Not authenticated or token invalid |
| 401 | TOKEN_EXPIRED | Token has expired |
| 403 | FORBIDDEN | Insufficient permissions |
| 404 | NOT_FOUND | Resource does not exist |
| 405 | METHOD_NOT_ALLOWED | Method not supported |
| 409 | CONFLICT | Resource state conflict |
| 409 | CONSTRAINT_VIOLATION | Security constraint violation |
| 413 | PAYLOAD_TOO_LARGE | Request body too large |
| 422 | VALIDATION_FAILED | Business validation failed |
| 429 | RATE_LIMITED | Rate limit triggered |
| 500 | INTERNAL_ERROR | Kernel error |
| 503 | SERVICE_UNAVAILABLE | Service unavailable |
| 504 | GATEWAY_TIMEOUT | Gateway timeout |
Business Error Codes
| HTTP Status | Error Code | Meaning |
|---|---|---|
| 409 | POWERFLOW_DIVERGED | Load flow did not converge |
| 409 | NETWORK_LOCKED | Network is locked |
| 422 | TOPOLOGY_INVALID | Topology invalid |
| 422 | PARAM_OUT_OF_RANGE | Parameter out of bounds |
| 422 | AGENT_BUSY | Agent busy |
| 422 | BUS_NOT_FOUND | Bus does not exist |
| 422 | BRANCH_NOT_FOUND | Branch does not exist |
| 422 | ISLANDED_BUS | Bus is islanded |
| 422 | VOLTAGE_OUT_OF_LIMIT | Voltage out of limits |
Unified error response body format:
{
"error": {
"code": "CONSTRAINT_VIOLATION",
"message": "Branch 1-2 overload: 105% of limit",
"details": {"branch_id": "1-2", "loading": 1.05, "limit": 1.0},
"trace_id": "trace_abc123",
"doc_url": "https://docs.openeneros.com/api-reference/rest#error-codes"
},
"request_id": "req_20260706_008"
}
Field Enum Value Descriptions
NetworkStatus
| Value | Description |
|---|---|
draft | Draft, editable |
ready | Ready, can participate in calculations |
locked | Locked (computation in progress), not modifiable |
archived | Archived, read-only |
AgentType
| Value | Description |
|---|---|
dispatch | Dispatch Agent |
self_healing | Self-healing Agent |
trading | Trading Agent |
maintenance | Maintenance Agent |
planning | Planning Agent |
AgentStatus
| Value | Description |
|---|---|
idle | Idle |
running | Running |
paused | Paused |
error | Error |
stopped | Stopped |
PowerFlowMethod
| Value | Description |
|---|---|
newton_raphson | Newton-Raphson method (default) |
fast_decoupled | Fast decoupled method (PQ decomposition) |
dc | DC load flow |
BusType
| Value | Description |
|---|---|
slack | Slack bus |
pv | PV bus (voltage controllable) |
pq | PQ bus (load bus) |
DeviceType
| Value | Description |
|---|---|
PV | Photovoltaic |
WIND | Wind power |
BESS | Energy storage |
EV | Electric vehicle |
LOAD | Load |
TRANSFORMER | Transformer |
BREAKER | Circuit breaker |
Batch Operations
In addition to time-series writes, the REST API also supports the following batch endpoints:
| Method | Path | Description | Single Batch Limit |
|---|---|---|---|
| POST | /api/v1/networks/batch | Batch create networks | 20 |
| POST | /api/v1/agents/batch | Batch create Agents | 50 |
| POST | /api/v1/devices/batch | Batch create devices | 200 |
| DELETE | /api/v1/networks/batch | Batch delete networks | 50 |
Batch requests uniformly return independent results for each entry:
{
"data": {
"succeeded": [{"index": 0, "id": "net_a"}, {"index": 1, "id": "net_b"}],
"failed": [{"index": 2, "error": {"code": "VALIDATION_FAILED", "message": "invalid bus"}}]
}
}
Related Documentation
- API Overview — Four API comparison
- GraphQL — Flexible query alternative
- Rate Limiting and Quota — Rate limiting strategy
- Version Management — API version evolution
- eneros-api crate — API service implementation