Skip to main content

API Reference

Version: 1.0.0

MangoGridStudio exposes two API services:

  • FastAPI Backend (http://localhost:58000) — authentication, analyst workflows, scenario management, AI chat, model builder, power flow validation, and user management. All routes listed here are under this base URL unless stated otherwise.
  • Julia Solver API (http://localhost:8082) — high-performance solver execution for UC, ED, SCUC, SCED, sensitivity analysis, and case management. Accessed via the /api/modules/analyst/solve/* proxy routes below.

Request conventions

Authentication header

All endpoints require a Bearer token except where noted as No auth:

Authorization: Bearer <access_token>

Obtain a token via POST /api/auth/login. Use POST /api/auth/refresh to extend.

During local development with AUTH_BYPASS_ENABLED=True, any token value is accepted:

curl -H "Authorization: Bearer dev-bypass-token" http://localhost:58000/health

Content-Type

All POST/PUT request bodies use JSON:

Content-Type: application/json

Error codes (common to all endpoints)

CodeMeaning
400Bad request — invalid input. Check the detail field.
401Unauthorized — token missing, expired, or invalid.
403Forbidden — authenticated but insufficient permissions.
404Resource not found.
409Conflict — resource already exists or state prevents the operation.
422Validation error — field-level details in detail[].loc and detail[].msg.
429Rate limited. Retry after the interval in Retry-After header.
502Bad gateway — Julia solver service unreachable or returned an error.
503Service unavailable — Julia solver module not loaded.
504Gateway timeout — solver exceeded the configured timeout_seconds.

Authentication

GET /api/auth/csrf-token

Retrieve a CSRF token for form-based flows.

Auth: No auth

Response 200:

{ "csrf_token": "abc123..." }

POST /api/auth/login

Authenticate and receive access + refresh tokens.

Auth: No auth

Request body:

{
"username": "analyst@grid.example",
"password": "s3cr3t"
}

Response 200:

{
"access_token": "eyJhbGci...",
"refresh_token": "eyJhbGci...",
"token_type": "bearer",
"expires_in": 3600
}

Error codes: 400 (missing credentials), 401 (wrong password), 404 (unknown user)

Example:

curl -s -X POST http://localhost:58000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"analyst@grid.example","password":"s3cr3t"}' | jq .access_token

POST /api/auth/refresh

Exchange a refresh token for a new access token.

Auth: No auth

Request body:

{ "refresh_token": "eyJhbGci..." }

Response 200: same shape as /api/auth/login


POST /api/auth/logout

Revoke the current access token.

Auth: Bearer token

Response 200:

{ "message": "Logged out successfully" }

POST /api/auth/register

Register a new user account.

Auth: No auth (or admin-only — controlled by ALLOW_PUBLIC_REGISTRATION env var)

Request body:

{ "username": "newuser@grid.example", "password": "SecurePass1!" }

Response 201:

{ "user_id": "usr_01HX...", "username": "newuser@grid.example" }

POST /api/auth/verify-2fa

Complete two-factor authentication.

Auth: No auth

Request body:

{
"temp_token": "eyJhbGci...",
"code": "123456"
}

Response 200: same shape as /api/auth/login (full access + refresh tokens)


Unit Commitment (UC) — Analyst Routes

The analyst module exposes solve routes at /api/modules/analyst/solve/. These routes proxy to the Julia solver service and return a job handle immediately (HTTP 202). Poll /status until completed or failed, then fetch /results.

GET /api/modules/analyst/solve/enhanced-uc/health

Check whether the Enhanced UC Julia module is loaded and operational.

Auth: Bearer token

Response 200:

{
"loaded": true,
"api_version": "2.0.0",
"capabilities": ["unit_commitment", "economic_dispatch", "benders_decomposition"],
"supported_modes": ["da_uc", "rt_uc", "stochastic_uc"],
"supported_solvers": ["highs", "cbc", "gurobi", "cplex"]
}

Error codes: 503 (Julia module not loaded or solver unreachable)


POST /api/modules/analyst/solve/uc

Submit a Unit Commitment solve job.

Auth: Bearer token
Rate limit: configurable via RATE_LIMIT_SOLVES_PER_MINUTE env var (default: 10/min)

Request body:

{
"scenario_id": "scn_pjm_summer_2024",
"payload": {
"generators": [
{
"name": "101_STEAM_3",
"bus": 101,
"p_max": 76.0,
"p_min": 30.0,
"marginal_cost": 22.5,
"no_load_cost": 210.0,
"startup_cost": 5284.8,
"ramp_up": 120.0,
"ramp_down": 120.0,
"min_uptime": 8,
"min_downtime": 4,
"initial_status": 1
}
],
"loads": [
{ "bus": 101, "values": [350.0, 360.0, 370.0, 380.0, 390.0, 400.0, 410.0, 420.0,
430.0, 440.0, 450.0, 460.0, 450.0, 440.0, 430.0, 420.0,
410.0, 400.0, 390.0, 380.0, 370.0, 360.0, 350.0, 340.0] }
],
"horizon": 24,
"solver": "highs"
},
"timeout": 300
}

Request fields:

  • scenario_id (string, required): identifier for tracing and result lookup
  • payload.generators (array, required): generator objects. See Generator object.
  • payload.loads (array, required): per-bus load time series. values must have exactly horizon entries.
  • payload.horizon (integer, required): number of hours to optimize, typically 24
  • payload.solver (string, optional): "highs" (default), "cbc", "gurobi", "cplex"
  • timeout (integer, optional): maximum seconds before job is killed, default 300

Response 202:

{
"job_id": "job_01HX4KZABCDEF",
"status": "queued",
"status_url": "/api/modules/analyst/solve/job_01HX4KZABCDEF/status",
"results_url": "/api/modules/analyst/solve/job_01HX4KZABCDEF/results"
}

Error codes: 422 (input validation failure), 502 (Julia solver unreachable)

Full curl example:

curl -s -X POST http://localhost:58000/api/modules/analyst/solve/uc \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d @examples/uc_input_ieee118_24h.json | jq .job_id

POST /api/modules/analyst/solve/scuc

Submit a Security-Constrained Unit Commitment solve job. Same request shape as /solve/uc; include "transmission_lines" and "contingencies" in the payload for N-1 security constraints.

Auth: Bearer token
Response 202: same shape as /solve/uc


POST /api/modules/analyst/solve/ed

Submit an Economic Dispatch solve job. Accepts commitment decisions (binary) as input; optimizes dispatch quantities only.

Auth: Bearer token
Response 202: same shape as /solve/uc


GET /api/modules/analyst/solve/{job_id}/status

Poll job status.

Auth: Bearer token

Path parameter: job_id — ID returned by a submit endpoint

Response 200:

{
"job_id": "job_01HX4KZABCDEF",
"status": "running",
"job_type": "uc",
"submitted_at": "2026-03-15T14:22:00Z",
"started_at": "2026-03-15T14:22:01Z",
"finished_at": null,
"error": null,
"progress": 42
}

status values: queued, running, completed, failed, cancelled

Example:

curl -s http://localhost:58000/api/modules/analyst/solve/job_01HX4KZABCDEF/status \
-H "Authorization: Bearer $TOKEN" | jq .status

GET /api/modules/analyst/solve/{job_id}/results

Fetch completed job results. Returns 202 if still running.

Auth: Bearer token

Response 200 (completed):

{
"job_id": "job_01HX4KZABCDEF",
"status": "completed",
"solve_time_s": 3.8,
"objective_value": 142850.50,
"termination_status": "OPTIMAL",
"commitment": {
"101_STEAM_3": [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
},
"dispatch_mw": {
"101_STEAM_3": [76.0, 76.0, 76.0, "..."]
},
"lmp": {
"bus_101": [28.09, 28.09, 28.09, "..."]
},
"total_cost_usd": 142850.50
}

termination_status values: OPTIMAL, FEASIBLE, INFEASIBLE, TIMEOUT

Response 202 (still running): same shape as /status


Generator object

FieldTypeRequiredDescription
namestringyesUnique generator identifier
busintegeryesBus number
p_maxfloatyesMaximum output (MW)
p_minfloatyesMinimum stable output (MW)
marginal_costfloatyesVariable cost ($/MWh). PJM M28 §4: heat_rate × fuel_price / 1000
no_load_costfloatyesFixed cost while online ($/h)
startup_costfloatyesCold-start cost ($)
ramp_upfloatyesMaximum ramp-up rate (MW/h)
ramp_downfloatyesMaximum ramp-down rate (MW/h)
min_uptimeintegeryesMinimum consecutive hours online
min_downtimeintegeryesMinimum consecutive hours offline
initial_statusintegeryesHours online (>0) or offline (≤0) at hour 0

AI Analyst

The AI Analyst provides conversational analysis of grid optimization results and code generation assistance.

POST /api/ai/chat

Send a message to the AI Analyst.

Auth: Bearer token
Rate limit: tier-based token budget

Request body:

{
"message": "Why is bus 123 congested in hours 16–18?",
"context": {
"scenario_id": "scn_pjm_summer_2024",
"module_id": "power-flow"
},
"session_id": "sess_01HX...",
"agent_id": "grid-analyst"
}

Request fields:

  • message (string, required): user message, max 4,000 characters
  • context (object, optional): scenario/module context for grounded answers
  • session_id (string, optional): resume an existing conversation; omit to start a new session
  • agent_id (string, optional): delegate to a named agent (e.g., "grid-analyst")

Response 200:

{
"session_id": "sess_01HX...",
"response": "Bus 123 is congested because the thermal limit on line 45–123...",
"tokens_used": 312,
"moderated": false,
"refused": false,
"safety_checked": true
}

Error codes: 400 (message missing or too long), 422 (safety filter violation), 429 (rate limited)


GET /api/ai/chat/history

Retrieve conversation history for the current session.

Auth: Bearer token

Response 200:

{
"messages": [
{ "role": "user", "content": "Why is bus 123 congested?" },
{ "role": "assistant", "content": "Bus 123 is congested because..." }
]
}

Returns at most the last 20 messages in the active session.


POST /api/ai/generate-code

Generate code from a natural language prompt. Convenience wrapper around /api/ai/chat optimized for code generation tasks.

Auth: Bearer token

Request body:

{ "prompt": "Write Python code to plot LMPs at buses 101–118 for the last 24 hours" }

Response 200: same shape as /api/ai/chat


WebSocket /ws/ai/chat

Real-time streaming AI chat.

Auth: Token in query parameter — ws://localhost:58000/ws/ai/chat?token=<access_token>

Client sends:

{ "message": "Show me the top 5 congested lines", "session_id": "sess_01HX..." }

Server sends (streamed):

{ "type": "token", "content": "The " }
{ "type": "token", "content": "top 5 " }
{ "type": "done", "session_id": "sess_01HX...", "full_response": "The top 5 congested lines are..." }

Error codes: 4401 (missing or invalid token), 4408 (connection limit exceeded per user)


Audit

GET /api/audit/logs

Retrieve platform audit logs. Admin role required.

Auth: Bearer token (admin role)

Query parameters:

  • type (string, optional): filter by event type (e.g., login, solve_submitted, config_changed)

Response 200:

{
"logs": [
{
"id": "evt_01HX...",
"event_type": "solve_submitted",
"user_id": "usr_01HX...",
"timestamp": "2026-03-15T14:22:00Z",
"details": { "job_id": "job_01HX...", "solver": "highs" }
}
]
}

Users

GET /api/users/me

Retrieve the current user's profile.

Auth: Bearer token

Response 200:

{
"user_id": "usr_01HX...",
"username": "analyst@grid.example",
"created_at": "2026-01-01T00:00:00Z"
}

POST /api/users/me/password

Change the current user's password.

Auth: Bearer token

Request body:

{
"current_password": "OldPass1!",
"new_password": "NewPass2!"
}

Response 200:

{ "message": "Password updated successfully" }

Error codes: 401 (current password incorrect), 422 (new password fails complexity requirements)


POST /api/users/me/api-keys

Create a named API key for programmatic access.

Auth: Bearer token

Request body:

{ "name": "ci-pipeline-key" }

Response 201:

{
"key_id": "key_01HX...",
"name": "ci-pipeline-key",
"api_key": "mgsk_01HX...",
"created_at": "2026-03-15T14:22:00Z"
}

The api_key value is shown only once at creation time. Store it securely.


GET /api/users/me/subscriptions

List the current user's module subscriptions.

Auth: Bearer token

Response 200:

{
"user_id": "usr_01HX...",
"modules": [
{
"module_id": "power-flow",
"access_level": "full",
"features_enabled": ["solve", "validate", "stability"],
"subscribed_at": "2026-01-01T00:00:00Z"
}
]
}

Modules

GET /api/modules

List all available modules.

Auth: Bearer token

Response 200:

{
"modules": [
{
"id": "power-flow",
"name": "Power Flow",
"description": "DC power flow solve, N-1 validation, and stability analysis",
"version": "1.0.0"
}
]
}

GET /api/modules/{module_id}

Get module info and check access for the current user.

Auth: Bearer token

Path parameter: module_id — e.g., power-flow

Response 200:

{
"id": "power-flow",
"name": "Power Flow",
"has_access": true,
"access_level": "full"
}

GET /api/modules/{module_id}/access

Check whether the current user has an active subscription to a module.

Auth: Bearer token

Response 200:

{
"module_id": "power-flow",
"has_access": true,
"access_level": "full",
"features_enabled": ["solve", "validate", "stability"]
}

POST /api/modules/{module_id}/access

Record a module access event (updates last_accessed timestamp for the user's subscription).

Auth: Bearer token

Response 200:

{
"module_id": "power-flow",
"success": true,
"last_accessed": "2026-03-15T14:22:00Z"
}

Power Flow Validation

The Power Flow module provides a suite of validation endpoints for transmission network data quality checks.

POST /api/modules/power-flow/solve

Lightweight solver wrapper that handles zero-impedance lines and returns adjusted line parameters.

Auth: Bearer token

Request body:

{
"lines": [
{ "id": "line_45_123", "r_ohm": 0.01, "x_ohm": 0.05, "s_nom_mva": 200.0 }
]
}

Response 200:

{
"status": "ok",
"adjusted_lines": [...],
"warnings": [],
"processing_notes": []
}

POST /api/modules/power-flow/validate

Validate power flow data including voltage limits and phase angle constraints.

Auth: Bearer token

Request body:

{
"buses": [{ "id": 101, "v_nom_kv": 345.0, "v_pu": 1.02, "angle_deg": 0.0 }],
"lines": [...],
"generators": [...]
}

Response 200:

{
"valid": true,
"errors": [],
"warnings": ["Bus 105: voltage 1.07 pu near upper limit 1.10 pu"]
}

POST /api/modules/power-flow/validate-topology

Validate network connectivity — detects floating buses and electrical islands.

Auth: Bearer token

Request body:

{
"buses": [{ "id": 101 }, { "id": 102 }],
"lines": [{ "from_bus": 101, "to_bus": 102 }]
}

Response 200:

{
"valid": true,
"floating_buses": [],
"islands": [],
"critical_issues": [],
"warnings": []
}

POST /api/modules/power-flow/validate-generators

Validate generator data completeness — checks for required fields (p_max_mw, p_min_mw, q_max_mvar, q_min_mvar).

Auth: Bearer token

Request body:

{ "generators": [{ "id": "GEN_101", "p_max_mw": 400.0 }] }

Response 200:

{
"valid": false,
"incomplete_generators": ["GEN_101"],
"missing_fields": { "GEN_101": ["q_max_mvar", "q_min_mvar"] },
"warnings": [],
"details": []
}

POST /api/modules/power-flow/validate-lines

Validate line definitions — detects duplicates and parameter errors.

Auth: Bearer token

Request body:

{
"lines": [
{ "id": "L1", "from_bus": 101, "to_bus": 102, "r_ohm": 0.01, "x_ohm": 0.05 }
]
}

Response 200:

{
"valid": true,
"warnings": [],
"duplicate_line_pairs": [],
"details": []
}

POST /api/modules/power-flow/validate-line

Validate physical plausibility of individual line parameters.

Auth: Bearer token

Request body:

{ "r_ohm": 0.01, "x_ohm": 0.05, "id": "L1" }

Response 200:

{ "valid": true, "error": null, "details": {} }

POST /api/modules/power-flow/validate-case

Full data quality check — voltage base consistency, missing reactive limits, island detection.

Auth: Bearer token

Request body:

{
"buses": [...],
"lines": [...],
"generators": [...]
}

Response 200:

{
"valid": true,
"data_quality_issues": [],
"warnings": [],
"details": []
}

POST /api/modules/power-flow/validate-contingency

Validate N-1 contingency analysis requirements — checks ROCOF (Rate of Change of Frequency) against inertia.

Auth: Bearer token

Request body:

{
"contingency": "N-1",
"system_inertia_mw_s": 50000.0,
"projected_rate_of_change_freq": 0.5
}

Response 200:

{
"valid": true,
"violations": [],
"warnings": []
}

POST /api/modules/power-flow/validate-flow

Validate reactive flow consistency and flag extreme from/to reactive power mismatches.

Auth: Bearer token

Request body:

{
"line_id": "L1",
"from_flow_mvar": 10.2,
"to_flow_mvar": -9.8,
"line_impedance": { "r_pu": 0.001, "x_pu": 0.005 }
}

Response 200:

{
"valid": true,
"warnings": [],
"severity": "low",
"mismatch_mvar": 0.4,
"imbalance_percent": 3.9
}

POST /api/modules/power-flow/check-violations

Check line flows against thermal limits.

Auth: Bearer token

Request body:

{
"lines": [
{ "id": "L1", "flow_mva": 185.0, "thermal_limit_mva": 200.0 }
]
}

Response 200:

{
"violations": ["L1"],
"violation_details": [{ "line_id": "L1", "flow_mva": 185.0, "limit_mva": 200.0, "loading_pct": 92.5 }],
"warnings": []
}

GET /api/modules/power-flow/line-limits

Return seasonal thermal rating for a transmission line.

Auth: Bearer token

Query parameters:

  • line_id (string, required): transmission line identifier
  • season (string, required): one of summer, winter, spring_fall

Response 200:

{
"line_id": "L1",
"season": "summer",
"thermal_limit_mva": 195.0,
"rating_source": "seasonal_derating"
}

POST /api/modules/power-flow/analyze-stability

Analyze reactive power sufficiency for voltage stability.

Auth: Bearer token

Request body:

{
"bus_id": 101,
"load_mvar": 120.0,
"available_sources": [
{ "id": "GEN_101", "q_max_mvar": 80.0, "q_min_mvar": -20.0 }
]
}

Response 200:

{
"feasible": true,
"reason": "Sufficient reactive reserve",
"details": { "total_available_mvar": 80.0, "deficit_mvar": 0.0 }
}

POST /api/modules/power-flow/validate-units

Validate unit consistency — detects kV/MV mixing and MVA/kVA mixing.

Auth: Bearer token

Request body:

{ "buses": [{ "id": 101, "v_nom_kv": 345.0 }] }

Response 200:

{
"valid": true,
"warnings": [],
"suspicious_values": [],
"details": []
}

Model Builder

The Model Builder provides a GUI-backed API for configuring, running, and tracking PCM (Production Cost Model) executions.

GET /api/model-builder/models

List available PCM models.

Auth: Bearer token

Response 200:

{
"models": [
{
"id": "ieee118_24h",
"name": "IEEE 118-Bus 24h",
"description": "54-generator, 118-bus test system",
"supported_solvers": ["highs", "cbc"]
}
]
}

GET /api/model-builder/solvers

List available solvers and their configurable parameters.

Auth: Bearer token

Response 200:

{
"solvers": [
{
"id": "highs",
"name": "HiGHS",
"parameters": [
{ "name": "time_limit", "type": "integer", "default": 300, "description": "Wall-clock limit in seconds" },
{ "name": "mip_gap", "type": "float", "default": 0.001, "description": "Optimality gap tolerance" }
]
}
]
}

POST /api/model-builder/run

Execute a PCM model. Returns immediately with an execution ID; poll /executions/{execution_id} for status.

Auth: Bearer token

Request body:

{
"pcm_model_id": "ieee118_24h",
"network_id": "net_01HX...",
"solver": {
"id": "highs",
"time_limit": 600,
"mip_gap": 0.001
},
"options": {
"horizon": 24,
"include_reserves": true
}
}

Request fields:

  • pcm_model_id (string, required): model identifier from /model-builder/models
  • solver (object, required): solver selection and parameters
  • network_id (string, optional): network data ID; uses model default if omitted
  • options (object, optional): model-specific run options

Response 202:

{
"execution_id": "exec_01HX...",
"status": "queued"
}

GET /api/model-builder/executions

List execution history for the current user.

Auth: Bearer token

Query parameters:

  • limit (integer, optional): max results (default 20)
  • offset (integer, optional): pagination offset

Response 200:

{
"executions": [
{
"execution_id": "exec_01HX...",
"status": "completed",
"pcm_model_id": "ieee118_24h",
"created_at": "2026-03-15T14:22:00Z"
}
]
}

GET /api/model-builder/executions/{execution_id}

Get execution status and results.

Auth: Bearer token

Response 200:

{
"execution_id": "exec_01HX...",
"status": "completed",
"pcm_model_id": "ieee118_24h",
"solver": { "id": "highs", "time_limit": 600 },
"network_id": "net_01HX...",
"options": {},
"created_at": "2026-03-15T14:22:00Z",
"results": {
"objective_value": 142850.50,
"termination_status": "OPTIMAL",
"solve_time_s": 4.2
}
}

status values: queued, running, completed, failed


GET /api/model-builder/configs

List saved model configurations.

Auth: Bearer token

Response 200:

{
"configs": [
{
"config_id": "cfg_01HX...",
"name": "Summer Peak — HiGHS 600s",
"pcm_model_id": "ieee118_24h",
"created_at": "2026-03-15T14:22:00Z"
}
]
}

POST /api/model-builder/configs

Save a model configuration for later reuse.

Auth: Bearer token

Request body:

{
"name": "Summer Peak — HiGHS 600s",
"description": "Standard summer peak run config",
"pcm_model_id": "ieee118_24h",
"solver": { "id": "highs", "time_limit": 600, "mip_gap": 0.001 }
}

Response 201:

{ "config_id": "cfg_01HX...", "name": "Summer Peak — HiGHS 600s" }

GET /api/model-builder/configs/{config_id}

Retrieve a saved configuration by ID.

Auth: Bearer token

Response 200: same shape as the config object in /model-builder/configs


POST /api/model-builder/ai/validate

Validate a model-builder AI prompt through the guardrail system.

Auth: Bearer token

Request body:

{
"prompt": "Run a 168-hour study with demand +20% on all buses",
"channel": "model-builder"
}

Response 200:

{
"allowed": true,
"warnings": [],
"rules": []
}

If allowed is false, the prompt should not be submitted to the model builder.


POST /api/model-tuner/ai/validate

Validate a model-tuner AI prompt through the guardrail system. Same request/response shape as /model-builder/ai/validate.


Health

GET /health

Root health check.

Auth: No auth

Response 200:

{ "status": "ok" }

GET /api/health

API-prefixed health check (same behavior).

Auth: No auth

Response 200:

{ "status": "ok" }

See also

  • Developer Quickstart — end-to-end walkthrough: clone → first solve → experiment
  • Unit Commitment Concepts — DA-UC formulation, constraint types, PJM M11 §3 worked example
  • LMP Decomposition Concepts — LMP = energy + congestion + loss (PJM M11 §6.4)
  • backend/openapi.json — machine-readable OpenAPI 3.1 spec (regenerate with python scripts/export_openapi.py)
  • http://localhost:58000/docs — interactive Swagger UI (requires running backend)