{
  "openapi": "3.1.0",
  "info": {
    "title": "Observability AI \u2014 SaaS Anomaly Detection API",
    "description": "EV charging session anomaly detection as a service.\n\n## How it works\n\n1. **Create** a session via `POST /sessions` with OCPP-compatible meter values.\n2. If >= 3 meter values are provided, the CSAR-2 pipeline runs automatically.\n3. **Append** data later via `PATCH /sessions/{id}` or **replace** via `PUT /sessions/{id}`.\n4. **Get results** via `GET /sessions/{id}` or browse anomalies via `GET /sessions`.\n\nThe API accepts full OCPP measurand/unit/phase/location fields (case-insensitive)\nand maps them to the internal pipeline format automatically.\n\n## Authentication\n\nEvery request must include a valid **Bearer** token in the `Authorization` header.\nSupported token types:\n- **SuperTokens session token** \u2014 obtained via login flow\n- **API key** \u2014 prefixed with `sk-obs-`, created via admin endpoints\n\n## Endpoint status\n\n| Endpoint | Status |\n|----------|--------|\n| `POST /sessions` | **Live** \u2014 creates session, auto-runs CSAR-2 pipeline |\n| `PUT /sessions/{id}` | **Live** \u2014 replace meter values |\n| `PATCH /sessions/{id}` | **Live** \u2014 append meter values |\n| `GET /sessions` | **Live** \u2014 paginated list with filters |\n| `GET /sessions/{id}` | **Live** \u2014 full session details |\n| `GET /sessions/{id}/explain` | **Live** \u2014 cached LLM explanation (no credits) |\n| `POST /sessions/{id}/explain` | **Live** \u2014 LLM-generated anomaly explanation |\n| `POST /sessions/{id}/ask` | **Live** \u2014 LLM Q&A about a session |\n| `POST /sessions/batch` | **Live** \u2014 async batch processing |\n| `GET /stations` | **Live** \u2014 lists stations with aggregated anomaly stats |\n| `GET /stations/{id}` | **Live** \u2014 station detail with connectors and metadata |\n| `GET /stations/{id}/connectors` | **Live** \u2014 per-connector anomaly category breakdown |\n| `GET /stations/{id}/inference` | **Live** \u2014 latest SHADE inference result |\n| `GET /stations/{id}/anomalies` | **Live** \u2014 station anomaly history |\n| `GET /stations/{id}/shade-overview` | **Live** \u2014 SHADE overview with energy timeline |\n| `PUT /billing/overage-limit` | **Live** \u2014 set overage spending limit |\n| Models endpoints (`/models/*`) | Planned (returns 501) |\n\n## Webhooks\n\nSubscribe to real-time event notifications via outbound webhooks.\n\n| Endpoint | Status |\n|----------|--------|\n| `POST /webhooks` | **Live** \u2014 register webhook subscription |\n| `GET /webhooks` | **Live** \u2014 list webhooks |\n| `GET /webhooks/{id}` | **Live** \u2014 detail with delivery history |\n| `PATCH /webhooks/{id}` | **Live** \u2014 update webhook |\n| `DELETE /webhooks/{id}` | **Live** \u2014 delete webhook |\n| `POST /webhooks/{id}/test` | **Live** \u2014 send test event |\n| `POST /webhooks/{id}/rotate-secret` | **Live** \u2014 rotate HMAC signing secret |\n\n**Events:** `station.anomaly_detected`, `station.anomaly_resolved`, `station.restart_recommended`\n\nEvery delivery includes an `X-Webhook-Signature` header (`t=<timestamp>,v1=<HMAC-SHA256>`) for payload verification. See [standalone docs](https://github.com/solidstudiosh/observability-ai) for verification examples.\n\n## Error format\n\nAll non-2xx responses follow [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) Problem Details format:\n\n```json\n{\"type\": \"error-type\", \"title\": \"Error Title\", \"status\": 404, \"detail\": \"Human-readable message.\"}\n```\n\nContent-Type: `application/problem+json`.\n\n## LLM-friendly documentation\n\nMachine-readable API summary: **[GET /llms.txt](/llms.txt)**\n",
    "version": "0.1.0"
  },
  "paths": {
    "/api/saas/v1/sessions": {
      "post": {
        "tags": [
          "saas:sessions"
        ],
        "summary": "Create Session",
        "description": "Create a charging session and optionally run anomaly analysis.\n\nIR-372: the SQLAlchemy session is opened inside the handler body\nrather than via ``Depends(get_saas_db)`` so the pool slot is not held\nwhile the request queues on the anyio threadpool. See\n``docs/plans/2026-05-18-saas-db-session-decoupling-design.md``.\n\nMeter values are optional \u2014 session can be created empty and populated\nlater via PUT or PATCH. If more than MIN_UNIQUE_TIMESTAMPS (5)\nunique-timestamp meter values are accumulated, anomaly analysis runs\nautomatically \u2014 deferred to a background task for active sessions, or\nsynchronously when ``status`` is ``completed``.",
        "operationId": "create_session",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SessionCreateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Session created. For an active session the analysis fields reflect the last COMPLETED inference and may lag the values just submitted (eventual consistency); the fresh analysis runs in the background. Send `status: completed` to force a synchronous final analysis.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionAnalysisResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid Bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "404": {
            "description": "ML model not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation error or inference pipeline failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error."
          }
        }
      },
      "get": {
        "tags": [
          "saas:sessions"
        ],
        "summary": "List Sessions",
        "description": "List analyzed sessions with pagination and filters.\n\nReturns all sessions for the authenticated tenant, most-recent first.\nEach item includes the latest inference result when available, plus the\ndata-quality defect codes detected for the session.",
        "operationId": "list_sessions",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1,
              "title": "Page"
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "default": 20,
              "title": "Pagesize"
            }
          },
          {
            "name": "chargingStationId",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Chargingstationid"
            }
          },
          {
            "name": "evseId",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Evseid"
            }
          },
          {
            "name": "isAnomaly",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "boolean"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Isanomaly"
            }
          },
          {
            "name": "minScore",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "number",
                  "maximum": 1,
                  "minimum": 0
                },
                {
                  "type": "null"
                }
              ],
              "title": "Minscore"
            }
          },
          {
            "name": "minConfidence",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "number",
                  "maximum": 1,
                  "minimum": 0
                },
                {
                  "type": "null"
                }
              ],
              "title": "Minconfidence"
            }
          },
          {
            "name": "dateFrom",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Datefrom"
            }
          },
          {
            "name": "dateTo",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Dateto"
            }
          },
          {
            "name": "defectCode",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter to sessions carrying any of these data-quality defect codes (S1\u2013S10)",
              "title": "Defectcode"
            },
            "description": "Filter to sessions carrying any of these data-quality defect codes (S1\u2013S10)"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionListResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid Bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/sessions/{session_id}": {
      "put": {
        "tags": [
          "saas:sessions"
        ],
        "summary": "Replace Session",
        "description": "Replace all meter values for a session.\n\nIR-372: session opened inline. Same rationale as ``create_session``.\n\nDeletes existing meter values and sets new ones. Requires at least 1 reading.\nIf more than MIN_UNIQUE_TIMESTAMPS (5) unique-timestamp meter values are\naccumulated, anomaly analysis runs automatically \u2014 deferred to a background\ntask for active sessions, or synchronously when ``status`` is ``completed``.",
        "operationId": "replace_session",
        "parameters": [
          {
            "name": "session_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Session Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SessionReplaceRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Meter values replaced. For an active session the analysis fields reflect the last COMPLETED inference and may lag the values just submitted (eventual consistency); the fresh analysis runs in the background. Send `status: completed` to force a synchronous final analysis.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionAnalysisResponse"
                }
              }
            }
          },
          "404": {
            "description": "Session not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation error or inference pipeline failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "saas:sessions"
        ],
        "summary": "Update Session",
        "description": "Append meter values to an existing session (OCPI-like incremental push).\n\nIR-372: session opened inline. Same rationale as ``create_session``.\n\nEmpty meter_values list = no changes, returns current state.\nIf more than MIN_UNIQUE_TIMESTAMPS (5) unique-timestamp meter values are\naccumulated, anomaly analysis runs automatically \u2014 deferred to a background\ntask for active sessions, or synchronously when ``status`` is ``completed``.",
        "operationId": "update_session",
        "parameters": [
          {
            "name": "session_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Session Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SessionUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Meter values appended. For an active session the analysis fields reflect the last COMPLETED inference and may lag the values just submitted (eventual consistency); the fresh analysis runs in the background. Send `status: completed` to force a synchronous final analysis.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionAnalysisResponse"
                }
              }
            }
          },
          "404": {
            "description": "Session not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation error or inference pipeline failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "saas:sessions"
        ],
        "summary": "Get Session Detail",
        "description": "Get full session details including meter values, analysis result, and anomaly categories.",
        "operationId": "get_session_detail",
        "parameters": [
          {
            "name": "session_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Session Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionDetailResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid Bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "404": {
            "description": "Session not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/sessions/{session_id}/explain": {
      "get": {
        "tags": [
          "saas:llm"
        ],
        "summary": "Get Session Explanation",
        "description": "Return cached LLM explanation if available. Legacy CPMS frontend may request refresh.",
        "operationId": "get_session_explanation",
        "parameters": [
          {
            "name": "session_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Session Id"
            }
          },
          {
            "name": "lang",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "minLength": 2,
                  "maxLength": 5,
                  "pattern": "^[a-z]{2,5}$"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Lang"
            }
          },
          {
            "name": "refresh",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false,
              "title": "Refresh"
            }
          },
          {
            "name": "style",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 32,
              "default": "business",
              "title": "Style"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/SessionExplainResponse"
                    },
                    {
                      "$ref": "#/components/schemas/LegacyExplainResponse"
                    }
                  ],
                  "title": "Response Get Session Explanation"
                }
              }
            }
          },
          "404": {
            "description": "No cached explanation found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "402": {
            "description": "Legacy refresh: no AI credits remaining.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "429": {
            "description": "Legacy refresh: rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "503": {
            "description": "Legacy refresh: LLM service unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "saas:llm"
        ],
        "summary": "Explain Session",
        "description": "Get an LLM-generated explanation of session anomalies.",
        "operationId": "explain_session",
        "parameters": [
          {
            "name": "session_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Session Id"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/SessionExplainRequest"
                  },
                  {
                    "type": "null"
                  }
                ],
                "title": "Request"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionExplainResponse"
                }
              }
            }
          },
          "402": {
            "description": "No AI credits remaining.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "404": {
            "description": "Session not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "503": {
            "description": "LLM service unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/sessions/{session_id}/ask": {
      "post": {
        "tags": [
          "saas:llm"
        ],
        "summary": "Ask Session",
        "description": "Ask a natural language question about a specific session.",
        "operationId": "ask_session",
        "parameters": [
          {
            "name": "session_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Session Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SessionAskRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionAskResponse"
                }
              }
            }
          },
          "402": {
            "description": "No AI credits remaining.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "404": {
            "description": "Session not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "503": {
            "description": "LLM service unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/sessions/batch": {
      "post": {
        "tags": [
          "saas:batches"
        ],
        "summary": "Submit Batch",
        "description": "Submit multiple sessions for batch analysis.\n\nCreates a batch record and enqueues background processing.\nReturns batch_id for polling via GET /sessions/batch/{batch_id}.",
        "operationId": "submit_batch",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchSubmitRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchSubmitResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid Bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/sessions/batch/{batch_id}": {
      "get": {
        "tags": [
          "saas:batches"
        ],
        "summary": "Get Batch Status",
        "description": "Get batch processing status and results (paginated).",
        "operationId": "get_batch_status",
        "parameters": [
          {
            "name": "batch_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Batch Id"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1,
              "title": "Page"
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "default": 100,
              "title": "Pagesize"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchStatusResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid Bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "404": {
            "description": "Batch not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/stations": {
      "get": {
        "tags": [
          "saas:stations"
        ],
        "summary": "List Stations",
        "description": "List tenant's charging stations with aggregated anomaly statistics.\n\nReads from ``charging_stations_aggregated_mv`` materialized view\n(refreshed ~60 s) for pre-aggregated session/anomaly counts per station.",
        "operationId": "list_stations",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 1,
              "title": "Page"
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "default": 20,
              "title": "Pagesize"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "integer",
                  "maximum": 100,
                  "minimum": 1
                },
                {
                  "type": "null"
                }
              ],
              "title": "Limit"
            }
          },
          {
            "name": "ocpp_charging_station_id",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by external station id",
              "title": "Ocpp Charging Station Id"
            },
            "description": "Filter by external station id"
          },
          {
            "name": "occurrenceFrom",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Last anomaly lower bound",
              "title": "Occurrencefrom"
            },
            "description": "Last anomaly lower bound"
          },
          {
            "name": "occurrenceTo",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Last anomaly upper bound",
              "title": "Occurrenceto"
            },
            "description": "Last anomaly upper bound"
          },
          {
            "name": "sortByAnomalies",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "enum": [
                    "asc",
                    "desc"
                  ],
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Sort by total anomalies: asc or desc",
              "title": "Sortbyanomalies"
            },
            "description": "Sort by total anomalies: asc or desc"
          },
          {
            "name": "sortByScore",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "enum": [
                    "asc",
                    "desc"
                  ],
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Sort by max anomaly score: asc or desc",
              "title": "Sortbyscore"
            },
            "description": "Sort by max anomaly score: asc or desc"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/StationListResponse"
                    },
                    {
                      "$ref": "#/components/schemas/LegacyStationListResponse"
                    }
                  ],
                  "title": "Response List Stations"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid Bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/stations/lookup": {
      "get": {
        "tags": [
          "saas:stations"
        ],
        "summary": "Lookup Station Ids",
        "description": "Return distinct station IDs for filter dropdowns.\n\nReads from the ``charging_stations`` base table (no MV dependency).",
        "operationId": "lookup_station_ids",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StationLookupResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid Bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/stations/{charging_station_id}": {
      "get": {
        "tags": [
          "saas:stations"
        ],
        "summary": "Get Station Detail",
        "description": "Get station details: connectors, anomaly statistics, metadata.\n\nUses ``charging_stations_aggregated_mv`` materialized view (refreshed ~60 s)\nfor station-level aggregates.",
        "operationId": "get_station_detail",
        "parameters": [
          {
            "name": "charging_station_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Charging Station Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StationDetailResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid Bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "404": {
            "description": "Station not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/stations/{charging_station_id}/connectors": {
      "get": {
        "tags": [
          "saas:stations"
        ],
        "summary": "Get Station Connectors",
        "description": "Get station connectors with per-connector anomaly category breakdown.",
        "operationId": "get_station_connectors",
        "parameters": [
          {
            "name": "charging_station_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Charging Station Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StationConnectorsResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid Bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "404": {
            "description": "Station not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/stations/{charging_station_id}/inference": {
      "get": {
        "tags": [
          "saas:stations"
        ],
        "summary": "Get Station Inference",
        "description": "Get latest SHADE inference result for a station.",
        "operationId": "get_station_inference",
        "parameters": [
          {
            "name": "charging_station_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Charging Station Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StationInferenceResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid Bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "404": {
            "description": "Station or inference not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/stations/{charging_station_id}/anomalies": {
      "get": {
        "tags": [
          "saas:stations"
        ],
        "summary": "List Station Anomalies",
        "description": "Get station-level anomaly history (SHADE detection results).",
        "operationId": "list_station_anomalies",
        "parameters": [
          {
            "name": "charging_station_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Charging Station Id"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 1,
              "title": "Page"
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "default": 20,
              "title": "Pagesize"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "integer",
                  "maximum": 100,
                  "minimum": 1
                },
                {
                  "type": "null"
                }
              ],
              "title": "Limit"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/StationAnomalyListResponse"
                    },
                    {
                      "$ref": "#/components/schemas/LegacyStationAnomalyListResponse"
                    }
                  ],
                  "title": "Response List Station Anomalies"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid Bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "404": {
            "description": "Station not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/stations/{charging_station_id}/shade-overview": {
      "get": {
        "tags": [
          "saas:stations"
        ],
        "summary": "Get Shade Overview",
        "description": "Get SHADE station overview: cumulative energy timeline with anomaly markers.",
        "operationId": "get_shade_overview",
        "parameters": [
          {
            "name": "charging_station_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Charging Station Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShadeOverviewResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid Bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "404": {
            "description": "Station or inference not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/stations/{charging_station_id}/energy": {
      "get": {
        "tags": [
          "saas:stations"
        ],
        "summary": "Get Station Energy",
        "description": "Get per-connector and aggregated energy timelines with SHADE anomaly markers.",
        "operationId": "get_station_energy",
        "parameters": [
          {
            "name": "charging_station_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Charging Station Id"
            }
          },
          {
            "name": "dateTo",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Dateto"
            }
          },
          {
            "name": "anomalyId",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Anomalyid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/StationEnergyResponse"
                    },
                    {
                      "$ref": "#/components/schemas/LegacyStationEnergyResponse"
                    }
                  ],
                  "title": "Response Get Station Energy"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid Bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "404": {
            "description": "Station not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/models": {
      "get": {
        "tags": [
          "saas:models"
        ],
        "summary": "List Models",
        "description": "List available models: base SaaS models + tenant's fine-tuned models.",
        "operationId": "list_models",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModelListResponse"
                }
              }
            }
          },
          "501": {
            "description": "Endpoint not yet implemented.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/models/fine-tune": {
      "post": {
        "tags": [
          "saas:models"
        ],
        "summary": "Start Fine Tune",
        "description": "Trigger model fine-tuning.\n\nClient specifies base model and training data source\n(previously submitted sessions or direct upload).",
        "operationId": "start_fine_tune",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FineTuneRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FineTuneResponse"
                }
              }
            }
          },
          "501": {
            "description": "Endpoint not yet implemented.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/models/fine-tune/{job_id}": {
      "get": {
        "tags": [
          "saas:models"
        ],
        "summary": "Get Fine Tune Status",
        "description": "Get fine-tuning job status and progress.",
        "operationId": "get_fine_tune_status",
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Job Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FineTuneStatusResponse"
                }
              }
            }
          },
          "404": {
            "description": "Fine-tune job not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "501": {
            "description": "Endpoint not yet implemented.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/models/{model_id}": {
      "get": {
        "tags": [
          "saas:models"
        ],
        "summary": "Get Model Detail",
        "description": "Get model details: version, metrics, training date.",
        "operationId": "get_model_detail",
        "parameters": [
          {
            "name": "model_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Model Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModelDetailResponse"
                }
              }
            }
          },
          "404": {
            "description": "Model not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "501": {
            "description": "Endpoint not yet implemented.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/statistics": {
      "get": {
        "tags": [
          "saas:statistics"
        ],
        "summary": "Get Statistics",
        "description": "Get tenant statistics summary: sessions, anomalies, stations.\n\nQueries charging session and inference tables to compute\ntenant-wide aggregated metrics.",
        "operationId": "get_statistics",
        "parameters": [
          {
            "name": "occurrenceFrom",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Detection date lower bound",
              "title": "Occurrencefrom"
            },
            "description": "Detection date lower bound"
          },
          {
            "name": "occurrenceTo",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Detection date upper bound",
              "title": "Occurrenceto"
            },
            "description": "Detection date upper bound"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SaasStatisticsResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid Bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/anomalies": {
      "get": {
        "tags": [
          "saas:anomalies"
        ],
        "summary": "List Anomalies",
        "description": "List individual anomalies with pagination and optional filters.",
        "operationId": "list_anomalies",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 1,
              "title": "Page"
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "default": 20,
              "title": "Pagesize"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "integer",
                  "maximum": 100,
                  "minimum": 1
                },
                {
                  "type": "null"
                }
              ],
              "title": "Limit"
            }
          },
          {
            "name": "anomalyType",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by anomaly category",
              "title": "Anomalytype"
            },
            "description": "Filter by anomaly category"
          },
          {
            "name": "connectorId",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by connector",
              "title": "Connectorid"
            },
            "description": "Filter by connector"
          },
          {
            "name": "chargingSessionId",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by session",
              "title": "Chargingsessionid"
            },
            "description": "Filter by session"
          },
          {
            "name": "chargingPointId",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by charging point(s)",
              "title": "Chargingpointid"
            },
            "description": "Filter by charging point(s)"
          },
          {
            "name": "evseId",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by EVSE(s)",
              "title": "Evseid"
            },
            "description": "Filter by EVSE(s)"
          },
          {
            "name": "ocpp_charging_station_id",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Ocpp Charging Station Id"
            }
          },
          {
            "name": "occurrenceFrom",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Detection date lower bound",
              "title": "Occurrencefrom"
            },
            "description": "Detection date lower bound"
          },
          {
            "name": "occurrenceTo",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Detection date upper bound",
              "title": "Occurrenceto"
            },
            "description": "Detection date upper bound"
          },
          {
            "name": "updateFrom",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Last update date lower bound",
              "title": "Updatefrom"
            },
            "description": "Last update date lower bound"
          },
          {
            "name": "updateTo",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Last update date upper bound",
              "title": "Updateto"
            },
            "description": "Last update date upper bound"
          },
          {
            "name": "sortByScore",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "enum": [
                    "asc",
                    "desc"
                  ],
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Sort by score: asc or desc",
              "title": "Sortbyscore"
            },
            "description": "Sort by score: asc or desc"
          },
          {
            "name": "anomalyIssuesStatus",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "enum": [
                      "OPEN",
                      "IN_PROGRESS",
                      "RESOLVED",
                      "DISMISSED"
                    ],
                    "type": "string"
                  }
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by issue status(es)",
              "title": "Anomalyissuesstatus"
            },
            "description": "Filter by issue status(es)"
          },
          {
            "name": "assignedTo",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by assignee email(s) (use 'me' for current user)",
              "title": "Assignedto"
            },
            "description": "Filter by assignee email(s) (use 'me' for current user)"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/AnomalyListResponse"
                    },
                    {
                      "$ref": "#/components/schemas/LegacyAnomalyListResponse"
                    }
                  ],
                  "title": "Response List Anomalies"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid Bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/anomalies/sessions": {
      "get": {
        "tags": [
          "saas:anomalies"
        ],
        "summary": "List Anomaly Sessions",
        "description": "List sessions with anomalies, aggregated by session.",
        "operationId": "list_anomaly_sessions",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 1,
              "title": "Page"
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "default": 20,
              "title": "Pagesize"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "integer",
                  "maximum": 100,
                  "minimum": 1
                },
                {
                  "type": "null"
                }
              ],
              "title": "Limit"
            }
          },
          {
            "name": "anomalyType",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by anomaly category",
              "title": "Anomalytype"
            },
            "description": "Filter by anomaly category"
          },
          {
            "name": "chargingSessionId",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by session",
              "title": "Chargingsessionid"
            },
            "description": "Filter by session"
          },
          {
            "name": "occurrenceFrom",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Detection date lower bound",
              "title": "Occurrencefrom"
            },
            "description": "Detection date lower bound"
          },
          {
            "name": "occurrenceTo",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Detection date upper bound",
              "title": "Occurrenceto"
            },
            "description": "Detection date upper bound"
          },
          {
            "name": "sortBy",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Sort: score_asc, score_desc, count_asc, count_desc",
              "title": "Sortby"
            },
            "description": "Sort: score_asc, score_desc, count_asc, count_desc"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/AnomalySessionListResponse"
                    },
                    {
                      "$ref": "#/components/schemas/LegacyAnomalySessionListResponse"
                    }
                  ],
                  "title": "Response List Anomaly Sessions"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid Bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/anomalies/connectors": {
      "get": {
        "tags": [
          "saas:anomalies"
        ],
        "summary": "List Anomaly Connectors",
        "description": "List connectors with anomalies, aggregated by connector.",
        "operationId": "list_anomaly_connectors",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 1,
              "title": "Page"
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "default": 20,
              "title": "Pagesize"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "integer",
                  "maximum": 100,
                  "minimum": 1
                },
                {
                  "type": "null"
                }
              ],
              "title": "Limit"
            }
          },
          {
            "name": "connectorId",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by connector",
              "title": "Connectorid"
            },
            "description": "Filter by connector"
          },
          {
            "name": "anomalyType",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by anomaly category",
              "title": "Anomalytype"
            },
            "description": "Filter by anomaly category"
          },
          {
            "name": "occurrenceFrom",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Detection date lower bound",
              "title": "Occurrencefrom"
            },
            "description": "Detection date lower bound"
          },
          {
            "name": "occurrenceTo",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "format": "date-time"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Detection date upper bound",
              "title": "Occurrenceto"
            },
            "description": "Detection date upper bound"
          },
          {
            "name": "sortBy",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "enum": [
                    "count_asc",
                    "count_desc"
                  ],
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Sort: count_asc, count_desc",
              "title": "Sortby"
            },
            "description": "Sort: count_asc, count_desc"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/AnomalyConnectorListResponse"
                    },
                    {
                      "$ref": "#/components/schemas/LegacyAnomalyConnectorListResponse"
                    }
                  ],
                  "title": "Response List Anomaly Connectors"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid Bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/anomalies/sessions/{session_id}/categories/{category_id}/details": {
      "get": {
        "tags": [
          "saas:anomalies"
        ],
        "summary": "Get Anomaly Detail",
        "description": "Get full anomaly detail for a specific session and category.",
        "operationId": "get_anomaly_detail",
        "parameters": [
          {
            "name": "session_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Session Id"
            }
          },
          {
            "name": "category_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Category Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/AnomalyDetailResponse"
                    },
                    {
                      "$ref": "#/components/schemas/LegacyCategoryAnomalyDetailsResponse"
                    }
                  ],
                  "title": "Response Get Anomaly Detail"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid Bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "404": {
            "description": "Anomaly detail not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/anomalies/issues/{issue_id}": {
      "put": {
        "tags": [
          "saas:anomalies"
        ],
        "summary": "Update Issue",
        "description": "Update an anomaly issue status and/or assignment.",
        "operationId": "update_anomaly_issue",
        "parameters": [
          {
            "name": "issue_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Issue Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateIssueRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/IssueResponse"
                    },
                    {
                      "$ref": "#/components/schemas/LegacyIssueUpdateResponse"
                    }
                  ],
                  "title": "Response Update Anomaly Issue"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid Bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "404": {
            "description": "Issue not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/api-keys": {
      "get": {
        "tags": [
          "saas:api-keys"
        ],
        "summary": "List Api Keys",
        "description": "List all API keys for the current tenant.",
        "operationId": "list_api_keys_api_saas_v1_api_keys_get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyListResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "saas:api-keys"
        ],
        "summary": "Create Api Key",
        "description": "Create a new API key for the tenant. Returns the full key only once.\n\nIR-379: handler manages DB sessions itself rather than holding one across\nevery Stripe HTTP round-trip, and every Stripe call is dispatched via\n``run_in_threadpool`` so the worker's event loop is not blocked during\nthe urllib3 round-trip. ``ensure_stripe_customer`` and\n``create_setup_session`` still hold a session for one Stripe call each\n(BillingService boundary refactor is tracked separately) but\n``list_payment_methods`` \u2014 the call that runs on every request \u2014 no\nlonger pins a pool slot. Each phase that re-acquires a session\nre-verifies ``BillingAccount.stripe_customer_id`` and the user\u2192tenant\nmapping (strict TOCTOU) so a concurrent customer rotation or admin\nrevocation between phases fails the request instead of silently issuing\na key against stale state.",
        "operationId": "create_api_key_api_saas_v1_api_keys_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateApiKeyRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateApiKeyResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/api-keys/{key_id}": {
      "delete": {
        "tags": [
          "saas:api-keys"
        ],
        "summary": "Revoke Api Key",
        "description": "Revoke an API key.",
        "operationId": "revoke_api_key_api_saas_v1_api_keys__key_id__delete",
        "parameters": [
          {
            "name": "key_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Key Id"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Successful Response"
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/organization": {
      "get": {
        "tags": [
          "saas:organization"
        ],
        "summary": "Get Organization",
        "description": "Get organization details for the current tenant.",
        "operationId": "get_organization_api_saas_v1_organization_get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrganizationResponse"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "saas:organization"
        ],
        "summary": "Update Organization",
        "description": "Create or update organization details. Admin only.\n\nFor open signup users (tenant_id=None): provisions org, billing, subscription,\nand tenant mapping, then refreshes session claims.\nFor existing tenants: updates org fields. On first creation, also provisions billing.",
        "operationId": "update_organization_api_saas_v1_organization_put",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OrganizationUpdate"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrganizationResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/members": {
      "get": {
        "tags": [
          "saas:members"
        ],
        "summary": "List Members",
        "description": "List all members and pending invitations for the current tenant.\n\nPending invitations are only visible to admin and super_admin callers.\n\nIR-379: a single DB session reads mappings and invitations, snapshots\nevery field needed downstream into plain dataclasses, and is closed\nbefore any SuperTokens HTTP fan-out. Holding the session through\n``asyncio.gather(N \u00d7 SuperTokens)`` was the dashboard's largest\npool-pin under load.",
        "operationId": "list_members_api_saas_v1_members_get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MemberListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/members/{user_id}": {
      "delete": {
        "tags": [
          "saas:members"
        ],
        "summary": "Remove Member",
        "description": "Remove a member from the tenant. Admin only.",
        "operationId": "remove_member_api_saas_v1_members__user_id__delete",
        "parameters": [
          {
            "name": "user_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "User Id"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Successful Response"
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/webhooks": {
      "post": {
        "tags": [
          "saas:webhooks"
        ],
        "summary": "Create Webhook",
        "description": "Register a new webhook. Secret is returned only once.",
        "operationId": "create_webhook",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookCreateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookCreateResponse"
                }
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            },
            "description": "Unauthorized"
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "saas:webhooks"
        ],
        "summary": "List Webhooks",
        "description": "List tenant's webhooks (secrets are not included).",
        "operationId": "list_webhooks",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 10000,
              "minimum": 1,
              "description": "Page number (1-based)",
              "default": 1,
              "title": "Page"
            },
            "description": "Page number (1-based)"
          },
          {
            "name": "pageSize",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "description": "Items per page",
              "default": 20,
              "title": "Pagesize"
            },
            "description": "Items per page"
          },
          {
            "name": "events",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WebhookEventType"
                  }
                },
                {
                  "type": "null"
                }
              ],
              "description": "Filter by subscribed event type(s). Multi-select: webhooks subscribing to ANY of the given events match.",
              "title": "Events"
            },
            "description": "Filter by subscribed event type(s). Multi-select: webhooks subscribing to ANY of the given events match."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookListResponse"
                }
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            },
            "description": "Unauthorized"
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/webhooks/{webhook_id}": {
      "get": {
        "tags": [
          "saas:webhooks"
        ],
        "summary": "Get Webhook",
        "description": "Get webhook details with recent delivery history.",
        "operationId": "get_webhook",
        "parameters": [
          {
            "name": "webhook_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Webhook Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDetailResponse"
                }
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            },
            "description": "Unauthorized"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            },
            "description": "Not Found"
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "saas:webhooks"
        ],
        "summary": "Update Webhook",
        "description": "Update webhook URL, events, or enabled state.",
        "operationId": "update_webhook",
        "parameters": [
          {
            "name": "webhook_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Webhook Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookResponse"
                }
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            },
            "description": "Unauthorized"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            },
            "description": "Not Found"
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "saas:webhooks"
        ],
        "summary": "Delete Webhook",
        "description": "Delete a webhook and all its delivery records.",
        "operationId": "delete_webhook",
        "parameters": [
          {
            "name": "webhook_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Webhook Id"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Successful Response"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            },
            "description": "Unauthorized"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            },
            "description": "Not Found"
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/webhooks/{webhook_id}/test": {
      "post": {
        "tags": [
          "saas:webhooks"
        ],
        "summary": "Test Webhook",
        "description": "Send a test event to the webhook URL.",
        "operationId": "test_webhook",
        "parameters": [
          {
            "name": "webhook_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Webhook Id"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            },
            "description": "Unauthorized"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            },
            "description": "Not Found"
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/saas/v1/webhooks/{webhook_id}/rotate-secret": {
      "post": {
        "tags": [
          "saas:webhooks"
        ],
        "summary": "Rotate Secret",
        "description": "Rotate webhook secret. Old secret valid for 24h grace period.",
        "operationId": "rotate_webhook_secret",
        "parameters": [
          {
            "name": "webhook_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Webhook Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookCreateResponse"
                }
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            },
            "description": "Unauthorized"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetailResponse"
                }
              }
            },
            "description": "Not Found"
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "AnomalyBucketRange": {
        "properties": {
          "startUnit": {
            "type": "integer",
            "title": "Startunit",
            "description": "Start bucket index (0-based, 15-second slot offset from session start)"
          },
          "endUnit": {
            "type": "integer",
            "title": "Endunit",
            "description": "End bucket index (inclusive, 15-second slot offset from session start)"
          }
        },
        "type": "object",
        "required": [
          "startUnit",
          "endUnit"
        ],
        "title": "AnomalyBucketRange",
        "description": "Time range of an anomaly expressed as CSAR-2 bucket indexes (15-second slots from session start)."
      },
      "AnomalyCategory": {
        "type": "string",
        "enum": [
          "POWER_INTERRUPTION",
          "KWH_DECREASE",
          "ENERGY_METER_MISMATCH",
          "UNEXPECTED_CHARGE_LEVEL_CHANGES",
          "ZERO_SESSION",
          "CHARGING_EXPECTED",
          "ENERGY_PIT",
          "UNEXPECTED_KWH_ACCUMULATE",
          "INCORRECT_ACTIVE_POWER_REGISTER"
        ],
        "title": "AnomalyCategory",
        "description": "Anomaly categories detected by CSAR-2 / CSAR-C-2 pipeline."
      },
      "AnomalyCategoryInfo": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id",
            "description": "Category identifier"
          },
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Display name of the anomaly category"
          },
          "description": {
            "type": "string",
            "title": "Description",
            "description": "Human-readable description",
            "default": ""
          },
          "maxScore": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Maxscore",
            "description": "Maximum observed risk score for this category"
          }
        },
        "type": "object",
        "required": [
          "id",
          "name",
          "maxScore"
        ],
        "title": "AnomalyCategoryInfo",
        "description": "Anomaly category metadata."
      },
      "AnomalyConnectorListItem": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id",
            "description": "Internal connector anomaly identifier"
          },
          "connectorId": {
            "type": "string",
            "title": "Connectorid",
            "description": "Connector identifier"
          },
          "anomalyCount": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Anomalycount",
            "description": "Number of anomalies on this connector"
          },
          "chargingPointId": {
            "type": "string",
            "title": "Chargingpointid",
            "description": "Charging point identifier"
          },
          "evseId": {
            "type": "string",
            "title": "Evseid",
            "description": "EVSE identifier"
          },
          "detectionDate": {
            "type": "string",
            "title": "Detectiondate",
            "description": "When anomalies were first detected"
          },
          "lastUpdate": {
            "type": "string",
            "title": "Lastupdate",
            "description": "When connector anomalies were last updated"
          },
          "anomalyTypes": {
            "items": {
              "$ref": "#/components/schemas/AnomalyTypeCount"
            },
            "type": "array",
            "title": "Anomalytypes",
            "description": "Breakdown of anomaly types on this connector"
          }
        },
        "type": "object",
        "required": [
          "id",
          "connectorId",
          "anomalyCount",
          "chargingPointId",
          "evseId",
          "detectionDate",
          "lastUpdate"
        ],
        "title": "AnomalyConnectorListItem",
        "description": "Connector-level anomaly summary."
      },
      "AnomalyConnectorListResponse": {
        "properties": {
          "content": {
            "items": {
              "$ref": "#/components/schemas/AnomalyConnectorListItem"
            },
            "type": "array",
            "title": "Content",
            "description": "Connector anomaly items on the current page"
          },
          "pagination": {
            "$ref": "#/components/schemas/PaginationInfo",
            "description": "Pagination metadata"
          }
        },
        "type": "object",
        "required": [
          "content",
          "pagination"
        ],
        "title": "AnomalyConnectorListResponse",
        "description": "Paginated list of connectors with anomalies."
      },
      "AnomalyDetail": {
        "properties": {
          "category": {
            "$ref": "#/components/schemas/AnomalyCategory",
            "description": "Anomaly classification category"
          },
          "score": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Score",
            "description": "Anomaly severity score (0.0 = normal, 1.0 = extreme)"
          },
          "bucketRange": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/AnomalyBucketRange"
              },
              {
                "type": "null"
              }
            ],
            "description": "Affected meter value range (bucket indexes, null when not available)"
          },
          "timeRange": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/AnomalyTimeRange"
              },
              {
                "type": "null"
              }
            ],
            "description": "Affected time range (start/end timestamps, null if not available)"
          },
          "confidence": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Confidence",
            "description": "Model confidence in this detection (0.0\u20131.0)"
          }
        },
        "type": "object",
        "required": [
          "category",
          "score",
          "confidence"
        ],
        "title": "AnomalyDetail",
        "description": "Single anomaly detected within a session.",
        "example": {
          "bucketRange": {
            "endUnit": 7,
            "startUnit": 4
          },
          "category": "KWH_DECREASE",
          "confidence": 0.92,
          "score": 0.87,
          "timeRange": {
            "endTimestamp": "2026-02-27T11:45:00Z",
            "startTimestamp": "2026-02-27T11:00:00Z"
          }
        }
      },
      "AnomalyDetailResponse": {
        "properties": {
          "sessionId": {
            "type": "string",
            "title": "Sessionid",
            "description": "Charging session identifier"
          },
          "clientId": {
            "type": "string",
            "title": "Clientid",
            "description": "Tenant/client identifier"
          },
          "connectorId": {
            "type": "string",
            "title": "Connectorid",
            "description": "Connector identifier"
          },
          "chargingPointId": {
            "type": "string",
            "title": "Chargingpointid",
            "description": "Charging point identifier"
          },
          "ocppChargingStationId": {
            "type": "string",
            "title": "Ocppchargingstationid",
            "description": "OCPP charging station identifier"
          },
          "evseId": {
            "type": "string",
            "title": "Evseid",
            "description": "EVSE identifier"
          },
          "detectionLevel": {
            "type": "string",
            "title": "Detectionlevel",
            "description": "Detection granularity level (e.g. connector)"
          },
          "meterValues": {
            "items": {
              "$ref": "#/components/schemas/DetailMeterValue"
            },
            "type": "array",
            "title": "Metervalues",
            "description": "Meter values for the session"
          },
          "currentRiskScore": {
            "type": "integer",
            "maximum": 100.0,
            "minimum": 0.0,
            "title": "Currentriskscore",
            "description": "Current risk score (0\u2013100)"
          },
          "firstDetectionDate": {
            "type": "string",
            "title": "Firstdetectiondate",
            "description": "When this anomaly was first detected"
          },
          "lastUpdateDate": {
            "type": "string",
            "title": "Lastupdatedate",
            "description": "When this anomaly was last updated"
          },
          "anomalyCategory": {
            "$ref": "#/components/schemas/AnomalyCategoryInfo",
            "description": "Anomaly category details"
          },
          "riskScoreTimeline": {
            "items": {
              "$ref": "#/components/schemas/RiskScorePoint"
            },
            "type": "array",
            "title": "Riskscoretimeline",
            "description": "Risk score evolution over time"
          },
          "anomalyPeriod": {
            "$ref": "#/components/schemas/AnomalyPeriod",
            "description": "Time range of the anomaly (first/highest-confidence range)"
          },
          "anomalyPeriods": {
            "items": {
              "$ref": "#/components/schemas/AnomalyPeriod"
            },
            "type": "array",
            "title": "Anomalyperiods",
            "description": "All detected anomaly time ranges for this category"
          },
          "issues": {
            "items": {
              "$ref": "#/components/schemas/IssueResponse"
            },
            "type": "array",
            "title": "Issues",
            "description": "Linked issues"
          }
        },
        "type": "object",
        "required": [
          "sessionId",
          "clientId",
          "connectorId",
          "chargingPointId",
          "ocppChargingStationId",
          "evseId",
          "detectionLevel",
          "currentRiskScore",
          "firstDetectionDate",
          "lastUpdateDate",
          "anomalyCategory",
          "anomalyPeriod"
        ],
        "title": "AnomalyDetailResponse",
        "description": "Full anomaly detail for a specific session and category."
      },
      "AnomalyListItem": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id",
            "description": "Anomaly identifier"
          },
          "anomalyType": {
            "type": "string",
            "title": "Anomalytype",
            "description": "Display name of the anomaly type"
          },
          "anomalyTypeId": {
            "type": "string",
            "title": "Anomalytypeid",
            "description": "Internal category enum value (use in URLs)"
          },
          "aiRiskScore": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Airiskscore",
            "description": "AI-computed risk score (0.0\u20131.0)"
          },
          "connectorId": {
            "type": "string",
            "title": "Connectorid",
            "description": "Connector identifier"
          },
          "chargingPointId": {
            "type": "string",
            "title": "Chargingpointid",
            "description": "Charging point identifier"
          },
          "ocppChargingStationId": {
            "type": "string",
            "title": "Ocppchargingstationid",
            "description": "OCPP charging station identifier"
          },
          "evseId": {
            "type": "string",
            "title": "Evseid",
            "description": "EVSE identifier"
          },
          "chargingSessionId": {
            "type": "string",
            "title": "Chargingsessionid",
            "description": "Associated charging session identifier"
          },
          "dateOfAnomalyOccurrence": {
            "type": "string",
            "title": "Dateofanomalyoccurrence",
            "description": "When the anomaly was first detected"
          },
          "dateOfLastUpdate": {
            "type": "string",
            "title": "Dateoflastupdate",
            "description": "When the anomaly was last updated"
          },
          "issues": {
            "items": {
              "$ref": "#/components/schemas/IssueResponse"
            },
            "type": "array",
            "title": "Issues",
            "description": "Linked issues"
          }
        },
        "type": "object",
        "required": [
          "id",
          "anomalyType",
          "anomalyTypeId",
          "aiRiskScore",
          "connectorId",
          "chargingPointId",
          "ocppChargingStationId",
          "evseId",
          "chargingSessionId",
          "dateOfAnomalyOccurrence",
          "dateOfLastUpdate"
        ],
        "title": "AnomalyListItem",
        "description": "Single anomaly entry in the anomaly list."
      },
      "AnomalyListResponse": {
        "properties": {
          "content": {
            "items": {
              "$ref": "#/components/schemas/AnomalyListItem"
            },
            "type": "array",
            "title": "Content",
            "description": "Anomaly items on the current page"
          },
          "pagination": {
            "$ref": "#/components/schemas/PaginationInfo",
            "description": "Pagination metadata"
          }
        },
        "type": "object",
        "required": [
          "content",
          "pagination"
        ],
        "title": "AnomalyListResponse",
        "description": "Paginated list of individual anomalies."
      },
      "AnomalyMarker": {
        "properties": {
          "startMinute": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Startminute",
            "description": "Minute offset from day start (0-1439)"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "title": "Timestamp",
            "description": "Absolute timestamp of the anomaly bucket (UTC)"
          },
          "score": {
            "type": "number",
            "title": "Score",
            "description": "Normalized anomaly score for this bucket (0-1)"
          }
        },
        "type": "object",
        "required": [
          "startMinute",
          "timestamp",
          "score"
        ],
        "title": "AnomalyMarker",
        "description": "SHADE anomaly marker on the timeline."
      },
      "AnomalyPeriod": {
        "properties": {
          "start": {
            "type": "string",
            "title": "Start",
            "description": "Start of the anomaly period"
          },
          "end": {
            "type": "string",
            "title": "End",
            "description": "End of the anomaly period"
          }
        },
        "type": "object",
        "required": [
          "start",
          "end"
        ],
        "title": "AnomalyPeriod",
        "description": "Time range of the anomaly."
      },
      "AnomalySessionListItem": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id",
            "description": "Internal session anomaly identifier"
          },
          "chargingSessionId": {
            "type": "string",
            "title": "Chargingsessionid",
            "description": "Client-provided session identifier"
          },
          "anomalyCount": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Anomalycount",
            "description": "Number of anomalies in this session"
          },
          "detectionDate": {
            "type": "string",
            "title": "Detectiondate",
            "description": "When anomalies were first detected"
          },
          "lastUpdate": {
            "type": "string",
            "title": "Lastupdate",
            "description": "When session anomalies were last updated"
          },
          "aiRiskScore": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Airiskscore",
            "description": "Highest AI risk score in this session"
          },
          "anomalyTypes": {
            "items": {
              "$ref": "#/components/schemas/AnomalyTypeCount"
            },
            "type": "array",
            "title": "Anomalytypes",
            "description": "Breakdown of anomaly types in this session"
          }
        },
        "type": "object",
        "required": [
          "id",
          "chargingSessionId",
          "anomalyCount",
          "detectionDate",
          "lastUpdate",
          "aiRiskScore"
        ],
        "title": "AnomalySessionListItem",
        "description": "Session-level anomaly summary."
      },
      "AnomalySessionListResponse": {
        "properties": {
          "content": {
            "items": {
              "$ref": "#/components/schemas/AnomalySessionListItem"
            },
            "type": "array",
            "title": "Content",
            "description": "Session anomaly items on the current page"
          },
          "pagination": {
            "$ref": "#/components/schemas/PaginationInfo",
            "description": "Pagination metadata"
          }
        },
        "type": "object",
        "required": [
          "content",
          "pagination"
        ],
        "title": "AnomalySessionListResponse",
        "description": "Paginated list of sessions with anomalies."
      },
      "AnomalyTimeRange": {
        "properties": {
          "startTimestamp": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Starttimestamp",
            "description": "Start of the anomaly time range"
          },
          "endTimestamp": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Endtimestamp",
            "description": "End of the anomaly time range"
          }
        },
        "type": "object",
        "title": "AnomalyTimeRange",
        "description": "Time range of an anomaly expressed as timestamps."
      },
      "AnomalyTypeCount": {
        "properties": {
          "type": {
            "type": "string",
            "title": "Type",
            "description": "Display name of the anomaly type"
          },
          "typeId": {
            "type": "string",
            "title": "Typeid",
            "description": "Internal category enum value (use in URLs)"
          },
          "count": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Count",
            "description": "Number of occurrences"
          }
        },
        "type": "object",
        "required": [
          "type",
          "typeId",
          "count"
        ],
        "title": "AnomalyTypeCount",
        "description": "Anomaly type with its occurrence count."
      },
      "ApiKeyListItem": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "name": {
            "type": "string",
            "title": "Name"
          },
          "description": {
            "type": "string",
            "title": "Description"
          },
          "tenantId": {
            "type": "string",
            "title": "Tenantid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "title": "Createdat"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time",
            "title": "Expiresat"
          },
          "lastUsedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Lastusedat"
          },
          "revokedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Revokedat"
          }
        },
        "type": "object",
        "required": [
          "id",
          "name",
          "description",
          "tenantId",
          "createdAt",
          "expiresAt",
          "lastUsedAt",
          "revokedAt"
        ],
        "title": "ApiKeyListItem"
      },
      "ApiKeyListResponse": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/ApiKeyListItem"
            },
            "type": "array",
            "title": "Items"
          }
        },
        "type": "object",
        "required": [
          "items"
        ],
        "title": "ApiKeyListResponse"
      },
      "BatchStatus": {
        "type": "string",
        "enum": [
          "pending",
          "processing",
          "completed",
          "failed"
        ],
        "title": "BatchStatus",
        "description": "Processing status of a batch upload."
      },
      "BatchStatusResponse": {
        "properties": {
          "batchId": {
            "type": "string",
            "title": "Batchid"
          },
          "status": {
            "$ref": "#/components/schemas/BatchStatus"
          },
          "totalSessions": {
            "type": "integer",
            "title": "Totalsessions"
          },
          "processedSessions": {
            "type": "integer",
            "title": "Processedsessions"
          },
          "failedSessions": {
            "type": "integer",
            "title": "Failedsessions"
          },
          "results": {
            "items": {
              "$ref": "#/components/schemas/SessionAnalysisResponse"
            },
            "type": "array",
            "title": "Results"
          },
          "page": {
            "type": "integer",
            "title": "Page"
          },
          "pageSize": {
            "type": "integer",
            "title": "Pagesize"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "title": "Createdat"
          },
          "completedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Completedat"
          }
        },
        "type": "object",
        "required": [
          "batchId",
          "status",
          "totalSessions",
          "processedSessions",
          "failedSessions",
          "results",
          "page",
          "pageSize",
          "createdAt",
          "completedAt"
        ],
        "title": "BatchStatusResponse",
        "description": "Batch processing status with paginated results."
      },
      "BatchSubmitRequest": {
        "properties": {
          "sessions": {
            "items": {
              "$ref": "#/components/schemas/SessionCreateRequest"
            },
            "type": "array",
            "maxItems": 1000,
            "minItems": 1,
            "title": "Sessions"
          }
        },
        "type": "object",
        "required": [
          "sessions"
        ],
        "title": "BatchSubmitRequest",
        "description": "Request to submit multiple sessions for batch analysis."
      },
      "BatchSubmitResponse": {
        "properties": {
          "batchId": {
            "type": "string",
            "title": "Batchid"
          },
          "totalSessions": {
            "type": "integer",
            "title": "Totalsessions"
          },
          "status": {
            "$ref": "#/components/schemas/BatchStatus"
          }
        },
        "type": "object",
        "required": [
          "batchId",
          "totalSessions",
          "status"
        ],
        "title": "BatchSubmitResponse",
        "description": "Response after submitting a batch."
      },
      "ClientSessionStatus": {
        "type": "string",
        "enum": [
          "active",
          "pending",
          "completed",
          "invalid"
        ],
        "title": "ClientSessionStatus",
        "description": "Subset of SessionStatus values that clients are allowed to set."
      },
      "ConnectorEnergy": {
        "properties": {
          "connectorId": {
            "type": "string",
            "title": "Connectorid",
            "description": "Connector identifier"
          },
          "energy": {
            "items": {
              "$ref": "#/components/schemas/EnergyPoint"
            },
            "type": "array",
            "title": "Energy",
            "description": "Energy timeline for this connector"
          }
        },
        "type": "object",
        "required": [
          "connectorId",
          "energy"
        ],
        "title": "ConnectorEnergy",
        "description": "Per-connector energy timeline."
      },
      "ConnectorInfo": {
        "properties": {
          "connectorId": {
            "type": "string",
            "title": "Connectorid",
            "description": "Connector identifier within the charging point"
          },
          "totalSessions": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Totalsessions",
            "description": "Total charging sessions on this connector"
          },
          "anomalousSessions": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Anomaloussessions",
            "description": "Sessions with detected anomalies on this connector"
          }
        },
        "type": "object",
        "required": [
          "connectorId",
          "totalSessions",
          "anomalousSessions"
        ],
        "title": "ConnectorInfo",
        "description": "Connector summary within a station."
      },
      "CreateApiKeyRequest": {
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255,
            "minLength": 1,
            "title": "Name"
          },
          "description": {
            "type": "string",
            "maxLength": 1000,
            "title": "Description",
            "default": ""
          }
        },
        "type": "object",
        "required": [
          "name"
        ],
        "title": "CreateApiKeyRequest"
      },
      "CreateApiKeyResponse": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "name": {
            "type": "string",
            "title": "Name"
          },
          "key": {
            "type": "string",
            "title": "Key"
          },
          "tenantId": {
            "type": "string",
            "title": "Tenantid"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time",
            "title": "Expiresat"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "title": "Createdat"
          }
        },
        "type": "object",
        "required": [
          "id",
          "name",
          "key",
          "tenantId",
          "expiresAt",
          "createdAt"
        ],
        "title": "CreateApiKeyResponse"
      },
      "DetailMeterValue": {
        "properties": {
          "timestamp": {
            "type": "string",
            "title": "Timestamp",
            "description": "Meter reading timestamp"
          },
          "energy": {
            "type": "number",
            "title": "Energy",
            "description": "Energy value (kWh)"
          },
          "stateOfCharge": {
            "type": "number",
            "title": "Stateofcharge",
            "description": "State of charge (0.0\u20131.0)"
          },
          "power": {
            "type": "number",
            "title": "Power",
            "description": "Active power (kW)"
          }
        },
        "type": "object",
        "required": [
          "timestamp",
          "energy",
          "stateOfCharge",
          "power"
        ],
        "title": "DetailMeterValue",
        "description": "Meter value point for anomaly detail view."
      },
      "EnergyPoint": {
        "properties": {
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "title": "Timestamp",
            "description": "Point in time (UTC)"
          },
          "energy": {
            "type": "number",
            "title": "Energy",
            "description": "Cumulative energy delivered (kWh)"
          }
        },
        "type": "object",
        "required": [
          "timestamp",
          "energy"
        ],
        "title": "EnergyPoint",
        "description": "Single energy data point on a timeline."
      },
      "EnergyTimelinePoint": {
        "properties": {
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "title": "Timestamp",
            "description": "Point in time (UTC)"
          },
          "cumulativeKwh": {
            "type": "number",
            "title": "Cumulativekwh",
            "description": "Cumulative energy delivered up to this point (kWh)"
          }
        },
        "type": "object",
        "required": [
          "timestamp",
          "cumulativeKwh"
        ],
        "title": "EnergyTimelinePoint",
        "description": "Single point on the cumulative energy timeline."
      },
      "FineTuneDataSource": {
        "properties": {
          "type": {
            "type": "string",
            "title": "Type",
            "description": "'sessions' or 'upload'"
          },
          "sessionFilter": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sessionfilter"
          }
        },
        "type": "object",
        "required": [
          "type"
        ],
        "title": "FineTuneDataSource"
      },
      "FineTuneJobStatus": {
        "type": "string",
        "enum": [
          "queued",
          "running",
          "completed",
          "failed"
        ],
        "title": "FineTuneJobStatus",
        "description": "Processing status of a fine-tuning job."
      },
      "FineTuneRequest": {
        "properties": {
          "baseModelId": {
            "type": "string",
            "title": "Basemodelid"
          },
          "name": {
            "type": "string",
            "maxLength": 128,
            "title": "Name"
          },
          "trainingConfig": {
            "additionalProperties": true,
            "type": "object",
            "title": "Trainingconfig"
          },
          "dataSource": {
            "$ref": "#/components/schemas/FineTuneDataSource"
          }
        },
        "type": "object",
        "required": [
          "baseModelId",
          "name",
          "dataSource"
        ],
        "title": "FineTuneRequest",
        "description": "Request to trigger fine-tuning."
      },
      "FineTuneResponse": {
        "properties": {
          "jobId": {
            "type": "string",
            "title": "Jobid"
          },
          "status": {
            "$ref": "#/components/schemas/FineTuneJobStatus"
          },
          "baseModelId": {
            "type": "string",
            "title": "Basemodelid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "title": "Createdat"
          }
        },
        "type": "object",
        "required": [
          "jobId",
          "status",
          "baseModelId",
          "createdAt"
        ],
        "title": "FineTuneResponse",
        "description": "Response after submitting a fine-tune job."
      },
      "FineTuneStatusResponse": {
        "properties": {
          "jobId": {
            "type": "string",
            "title": "Jobid"
          },
          "status": {
            "$ref": "#/components/schemas/FineTuneJobStatus"
          },
          "baseModelId": {
            "type": "string",
            "title": "Basemodelid"
          },
          "resultModelId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Resultmodelid"
          },
          "config": {
            "additionalProperties": true,
            "type": "object",
            "title": "Config"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "title": "Createdat"
          },
          "startedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Startedat"
          },
          "completedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Completedat"
          },
          "errorMessage": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Errormessage"
          }
        },
        "type": "object",
        "required": [
          "jobId",
          "status",
          "baseModelId",
          "resultModelId",
          "config",
          "createdAt",
          "startedAt",
          "completedAt",
          "errorMessage"
        ],
        "title": "FineTuneStatusResponse",
        "description": "Fine-tune job status."
      },
      "HTTPValidationError": {
        "properties": {
          "detail": {
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
          }
        },
        "type": "object",
        "title": "HTTPValidationError"
      },
      "IssueResponse": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id",
            "description": "Issue identifier"
          },
          "statusName": {
            "type": "string",
            "title": "Statusname",
            "description": "Current issue status (e.g. OPEN, RESOLVED)"
          },
          "assignedTo": {
            "type": "string",
            "title": "Assignedto",
            "description": "Email of the assignee (empty if unassigned)",
            "default": ""
          }
        },
        "type": "object",
        "required": [
          "id",
          "statusName"
        ],
        "title": "IssueResponse",
        "description": "Issue linked to an anomaly."
      },
      "LegacyAnomalyCategoryDetail": {
        "properties": {
          "id": {
            "type": "integer",
            "title": "Id"
          },
          "name": {
            "type": "string",
            "title": "Name"
          },
          "description": {
            "type": "string",
            "title": "Description",
            "default": ""
          },
          "maxScore": {
            "type": "number",
            "title": "Maxscore"
          },
          "anomalyStart": {
            "type": "string",
            "format": "date-time",
            "title": "Anomalystart"
          },
          "anomalyEnd": {
            "type": "string",
            "format": "date-time",
            "title": "Anomalyend"
          },
          "occurrences": {
            "type": "integer",
            "title": "Occurrences",
            "default": 0
          },
          "riskScoreTimeline": {
            "items": {
              "$ref": "#/components/schemas/LegacyRiskScoreTimeline"
            },
            "type": "array",
            "title": "Riskscoretimeline"
          }
        },
        "type": "object",
        "required": [
          "id",
          "name",
          "maxScore",
          "anomalyStart",
          "anomalyEnd"
        ],
        "title": "LegacyAnomalyCategoryDetail",
        "description": "CPMS-compatible anomaly category with nested timeline. TODO(IR-318-REMOVE)."
      },
      "LegacyAnomalyConnectorListResponse": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/LegacyConnectorAnomalyItem"
            },
            "type": "array",
            "title": "Items"
          },
          "pagination": {
            "$ref": "#/components/schemas/LegacyPagination"
          }
        },
        "type": "object",
        "required": [
          "items",
          "pagination"
        ],
        "title": "LegacyAnomalyConnectorListResponse",
        "description": "CPMS-compatible connector-anomaly list response. TODO(IR-318-REMOVE)."
      },
      "LegacyAnomalyIssueInfo": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "status": {
            "type": "integer",
            "title": "Status",
            "default": 0
          },
          "statusName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Statusname"
          },
          "assignedTo": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Assignedto"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "title": "Createdat",
            "default": "1970-01-01T00:00:00Z"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "title": "Updatedat",
            "default": "1970-01-01T00:00:00Z"
          }
        },
        "type": "object",
        "required": [
          "id"
        ],
        "title": "LegacyAnomalyIssueInfo",
        "description": "CPMS-compatible anomaly issue info. TODO(IR-318-REMOVE).\n\nNote: IssueResponse (SaaS) does not expose createdAt/updatedAt, so those fields have no\nsource. EPOCH is an explicit \"unavailable\" sentinel \u2014 CPMS may render \"1970-01-01\" for\nthese timestamps. Parallel to LegacyExplainResponse.created_at, which documents a similar\nsynthetic-value choice at the mapper boundary."
      },
      "LegacyAnomalyItem": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "anomalyType": {
            "type": "string",
            "title": "Anomalytype"
          },
          "aiRiskScore": {
            "type": "number",
            "title": "Airiskscore"
          },
          "connectorId": {
            "type": "string",
            "title": "Connectorid"
          },
          "chargingPointId": {
            "type": "string",
            "title": "Chargingpointid"
          },
          "ocppChargingStationId": {
            "type": "string",
            "title": "Ocppchargingstationid"
          },
          "evseId": {
            "type": "string",
            "title": "Evseid"
          },
          "chargingSessionId": {
            "type": "string",
            "title": "Chargingsessionid"
          },
          "dateOfAnomalyOccurrence": {
            "type": "string",
            "format": "date-time",
            "title": "Dateofanomalyoccurrence"
          },
          "dateOfLastUpdate": {
            "type": "string",
            "format": "date-time",
            "title": "Dateoflastupdate"
          },
          "issues": {
            "items": {
              "$ref": "#/components/schemas/LegacyAnomalyIssueInfo"
            },
            "type": "array",
            "title": "Issues"
          }
        },
        "type": "object",
        "required": [
          "id",
          "anomalyType",
          "aiRiskScore",
          "connectorId",
          "chargingPointId",
          "ocppChargingStationId",
          "evseId",
          "chargingSessionId",
          "dateOfAnomalyOccurrence",
          "dateOfLastUpdate",
          "issues"
        ],
        "title": "LegacyAnomalyItem",
        "description": "CPMS-compatible anomaly list item. TODO(IR-318-REMOVE).\n\nMirrors AnomalyListItem exactly except anomaly_type_id is dropped."
      },
      "LegacyAnomalyListResponse": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/LegacyAnomalyItem"
            },
            "type": "array",
            "title": "Items"
          },
          "pagination": {
            "$ref": "#/components/schemas/LegacyPagination"
          }
        },
        "type": "object",
        "required": [
          "items",
          "pagination"
        ],
        "title": "LegacyAnomalyListResponse",
        "description": "CPMS-compatible anomalies list response. TODO(IR-318-REMOVE)."
      },
      "LegacyAnomalyOccurrence": {
        "properties": {
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "title": "Timestamp"
          },
          "score": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Score"
          },
          "anomalyId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Anomalyid"
          },
          "comments": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Comments"
          }
        },
        "type": "object",
        "required": [
          "timestamp"
        ],
        "title": "LegacyAnomalyOccurrence",
        "description": "CPMS-compatible anomaly occurrence. TODO(IR-318-REMOVE).\n\nSaaS exposes only timestamps; the other fields are not persisted in the SaaS DB."
      },
      "LegacyAnomalyPeriod": {
        "properties": {
          "start": {
            "type": "string",
            "format": "date-time",
            "title": "Start"
          },
          "end": {
            "type": "string",
            "format": "date-time",
            "title": "End"
          }
        },
        "type": "object",
        "required": [
          "start",
          "end"
        ],
        "title": "LegacyAnomalyPeriod",
        "description": "CPMS-compatible anomaly period. TODO(IR-318-REMOVE)."
      },
      "LegacyAnomalySessionListResponse": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/LegacySessionAnomalyItem"
            },
            "type": "array",
            "title": "Items"
          },
          "pagination": {
            "$ref": "#/components/schemas/LegacyPagination"
          }
        },
        "type": "object",
        "required": [
          "items",
          "pagination"
        ],
        "title": "LegacyAnomalySessionListResponse",
        "description": "CPMS-compatible session-anomaly list response. TODO(IR-318-REMOVE)."
      },
      "LegacyAnomalyTypeCount": {
        "properties": {
          "type": {
            "type": "string",
            "title": "Type"
          },
          "count": {
            "type": "integer",
            "title": "Count"
          }
        },
        "type": "object",
        "required": [
          "type",
          "count"
        ],
        "title": "LegacyAnomalyTypeCount",
        "description": "CPMS-compatible anomaly-type count. TODO(IR-318-REMOVE).\n\nMirrors AnomalyTypeCount except internal ``type_id`` is dropped."
      },
      "LegacyCategoryAnomalyDetailsResponse": {
        "properties": {
          "sessionId": {
            "type": "string",
            "title": "Sessionid"
          },
          "clientId": {
            "type": "string",
            "title": "Clientid"
          },
          "connectorId": {
            "type": "string",
            "title": "Connectorid"
          },
          "chargingPointId": {
            "type": "string",
            "title": "Chargingpointid"
          },
          "ocppChargingStationId": {
            "type": "string",
            "title": "Ocppchargingstationid"
          },
          "evseId": {
            "type": "string",
            "title": "Evseid"
          },
          "detectionLevel": {
            "type": "string",
            "title": "Detectionlevel"
          },
          "currentRiskScore": {
            "type": "number",
            "title": "Currentriskscore"
          },
          "anomalousInferences": {
            "type": "integer",
            "title": "Anomalousinferences",
            "default": 0
          },
          "firstDetectionDate": {
            "type": "string",
            "format": "date-time",
            "title": "Firstdetectiondate"
          },
          "lastUpdateDate": {
            "type": "string",
            "format": "date-time",
            "title": "Lastupdatedate"
          },
          "anomalyCategory": {
            "$ref": "#/components/schemas/LegacyAnomalyCategoryDetail"
          },
          "anomalyPeriod": {
            "$ref": "#/components/schemas/LegacyAnomalyPeriod"
          },
          "riskScoreTimeline": {
            "items": {
              "$ref": "#/components/schemas/LegacyRiskScoreTimeline"
            },
            "type": "array",
            "title": "Riskscoretimeline"
          },
          "meterValues": {
            "items": {
              "$ref": "#/components/schemas/LegacyMeterValuePoint"
            },
            "type": "array",
            "title": "Metervalues"
          },
          "issues": {
            "items": {
              "$ref": "#/components/schemas/LegacyAnomalyIssueInfo"
            },
            "type": "array",
            "title": "Issues"
          }
        },
        "type": "object",
        "required": [
          "sessionId",
          "clientId",
          "connectorId",
          "chargingPointId",
          "ocppChargingStationId",
          "evseId",
          "detectionLevel",
          "currentRiskScore",
          "firstDetectionDate",
          "lastUpdateDate",
          "anomalyCategory",
          "anomalyPeriod"
        ],
        "title": "LegacyCategoryAnomalyDetailsResponse",
        "description": "CPMS-compatible category anomaly details. TODO(IR-318-REMOVE)."
      },
      "LegacyConnectorAnomalyItem": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "connectorId": {
            "type": "string",
            "title": "Connectorid"
          },
          "anomalyCount": {
            "type": "integer",
            "title": "Anomalycount"
          },
          "chargingPointId": {
            "type": "string",
            "title": "Chargingpointid"
          },
          "evseId": {
            "type": "string",
            "title": "Evseid"
          },
          "detectionDate": {
            "type": "string",
            "format": "date-time",
            "title": "Detectiondate"
          },
          "lastUpdate": {
            "type": "string",
            "format": "date-time",
            "title": "Lastupdate"
          },
          "anomalyTypes": {
            "items": {
              "$ref": "#/components/schemas/LegacyAnomalyTypeCount"
            },
            "type": "array",
            "title": "Anomalytypes"
          }
        },
        "type": "object",
        "required": [
          "id",
          "connectorId",
          "anomalyCount",
          "chargingPointId",
          "evseId",
          "detectionDate",
          "lastUpdate",
          "anomalyTypes"
        ],
        "title": "LegacyConnectorAnomalyItem",
        "description": "CPMS-compatible connector-anomaly list item. TODO(IR-318-REMOVE).\n\nMirrors AnomalyConnectorListItem exactly except anomaly_types entries drop type_id."
      },
      "LegacyExplainResponse": {
        "properties": {
          "sessionId": {
            "type": "string",
            "title": "Sessionid"
          },
          "explanation": {
            "type": "string",
            "title": "Explanation"
          },
          "language": {
            "type": "string",
            "title": "Language"
          },
          "style": {
            "type": "string",
            "title": "Style"
          },
          "cached": {
            "type": "boolean",
            "title": "Cached"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "title": "Createdat"
          }
        },
        "type": "object",
        "required": [
          "sessionId",
          "explanation",
          "language",
          "style",
          "cached",
          "createdAt"
        ],
        "title": "LegacyExplainResponse",
        "description": "CPMS-compatible explain response shape. TODO(IR-318-REMOVE).\n\nAdds language, style, createdAt on top of SessionExplainResponse."
      },
      "LegacyIssueUpdateResponse": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "sessionId": {
            "type": "string",
            "title": "Sessionid"
          },
          "anomalyCategoryId": {
            "type": "integer",
            "title": "Anomalycategoryid"
          },
          "status": {
            "type": "integer",
            "title": "Status"
          },
          "statusName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Statusname"
          },
          "assignedTo": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Assignedto"
          }
        },
        "type": "object",
        "required": [
          "id",
          "sessionId",
          "anomalyCategoryId",
          "status"
        ],
        "title": "LegacyIssueUpdateResponse",
        "description": "CPMS-compatible shape for PUT /anomalies/issues/{id}. TODO(IR-318-REMOVE).\n\nNote: IssueResponse (SaaS) does not expose `sessionId` or `anomalyCategoryId`, so those fields\nhave no source. Empty string / 0 are explicit \"unavailable\" sentinels \u2014 parallel to\nLegacyAnomalyIssueInfo EPOCH timestamps, which document the same synthetic-value choice at the\nmapper boundary."
      },
      "LegacyMeterValuePoint": {
        "properties": {
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "title": "Timestamp"
          },
          "energy": {
            "type": "number",
            "title": "Energy"
          },
          "power": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Power"
          },
          "stateOfCharge": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Stateofcharge"
          }
        },
        "type": "object",
        "required": [
          "timestamp",
          "energy"
        ],
        "title": "LegacyMeterValuePoint",
        "description": "CPMS-compatible meter value (no `soc` field). TODO(IR-318-REMOVE)."
      },
      "LegacyPagination": {
        "properties": {
          "page": {
            "type": "integer",
            "title": "Page"
          },
          "limit": {
            "type": "integer",
            "title": "Limit"
          },
          "totalPages": {
            "type": "integer",
            "title": "Totalpages"
          },
          "totalCount": {
            "type": "integer",
            "title": "Totalcount"
          }
        },
        "type": "object",
        "required": [
          "page",
          "limit",
          "totalPages",
          "totalCount"
        ],
        "title": "LegacyPagination",
        "description": "CPMS-compatible pagination block. TODO(IR-318-REMOVE)."
      },
      "LegacyRiskScoreTimeline": {
        "properties": {
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "title": "Timestamp"
          },
          "riskScore": {
            "type": "number",
            "title": "Riskscore"
          },
          "inferenceId": {
            "type": "string",
            "title": "Inferenceid",
            "default": ""
          },
          "anomalyFound": {
            "type": "boolean",
            "title": "Anomalyfound",
            "default": true
          }
        },
        "type": "object",
        "required": [
          "timestamp",
          "riskScore"
        ],
        "title": "LegacyRiskScoreTimeline",
        "description": "CPMS-compatible risk score timeline point. TODO(IR-318-REMOVE)."
      },
      "LegacySessionAnomalyItem": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "chargingSessionId": {
            "type": "string",
            "title": "Chargingsessionid"
          },
          "anomalyCount": {
            "type": "integer",
            "title": "Anomalycount"
          },
          "detectionDate": {
            "type": "string",
            "format": "date-time",
            "title": "Detectiondate"
          },
          "lastUpdate": {
            "type": "string",
            "format": "date-time",
            "title": "Lastupdate"
          },
          "aiRiskScore": {
            "type": "number",
            "title": "Airiskscore"
          },
          "anomalyTypes": {
            "items": {
              "$ref": "#/components/schemas/LegacyAnomalyTypeCount"
            },
            "type": "array",
            "title": "Anomalytypes"
          }
        },
        "type": "object",
        "required": [
          "id",
          "chargingSessionId",
          "anomalyCount",
          "detectionDate",
          "lastUpdate",
          "aiRiskScore",
          "anomalyTypes"
        ],
        "title": "LegacySessionAnomalyItem",
        "description": "CPMS-compatible session-anomaly list item. TODO(IR-318-REMOVE).\n\nMirrors AnomalySessionListItem exactly except anomaly_types entries drop type_id."
      },
      "LegacyStationAnomalyListResponse": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/StationAnomalyItem"
            },
            "type": "array",
            "title": "Items"
          },
          "pagination": {
            "$ref": "#/components/schemas/LegacyPagination"
          }
        },
        "type": "object",
        "required": [
          "items",
          "pagination"
        ],
        "title": "LegacyStationAnomalyListResponse",
        "description": "CPMS-compatible station anomaly list response. TODO(IR-318-REMOVE)."
      },
      "LegacyStationEnergyResponse": {
        "properties": {
          "chargingStationId": {
            "type": "string",
            "title": "Chargingstationid"
          },
          "energyDelivered": {
            "type": "number",
            "title": "Energydelivered"
          },
          "energyConsumptionStation": {
            "items": {
              "$ref": "#/components/schemas/EnergyPoint"
            },
            "type": "array",
            "title": "Energyconsumptionstation"
          },
          "energyConsumptionConnectors": {
            "items": {
              "$ref": "#/components/schemas/ConnectorEnergy"
            },
            "type": "array",
            "title": "Energyconsumptionconnectors"
          },
          "anomalyOccurrences": {
            "items": {
              "$ref": "#/components/schemas/LegacyAnomalyOccurrence"
            },
            "type": "array",
            "title": "Anomalyoccurrences"
          }
        },
        "type": "object",
        "required": [
          "chargingStationId",
          "energyDelivered",
          "energyConsumptionStation",
          "energyConsumptionConnectors",
          "anomalyOccurrences"
        ],
        "title": "LegacyStationEnergyResponse",
        "description": "CPMS-compatible station energy response. TODO(IR-318-REMOVE).\n\nIdentical to SaaS StationEnergyResponse except anomaly_occurrences is a\nlist of objects instead of list of datetimes. Extra fields (score, anomaly_id,\ncomments) are always None \u2014 SaaS doesn't track them."
      },
      "LegacyStationItem": {
        "properties": {
          "ocppChargingStationId": {
            "type": "string",
            "title": "Ocppchargingstationid"
          },
          "chargingStationId": {
            "type": "string",
            "title": "Chargingstationid"
          },
          "aiScore": {
            "type": "number",
            "title": "Aiscore",
            "default": 0.0
          },
          "totalAnomalies": {
            "type": "integer",
            "title": "Totalanomalies"
          },
          "lastAnomalyDate": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Lastanomalydate"
          }
        },
        "type": "object",
        "required": [
          "ocppChargingStationId",
          "chargingStationId",
          "totalAnomalies"
        ],
        "title": "LegacyStationItem",
        "description": "CPMS-compatible station list item. TODO(IR-318-REMOVE).\n\nMirrors StationListItem but drops the internal ``id`` field (CPMS has no concept of it)."
      },
      "LegacyStationListResponse": {
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/LegacyStationItem"
            },
            "type": "array",
            "title": "Items"
          },
          "pagination": {
            "$ref": "#/components/schemas/LegacyPagination"
          }
        },
        "type": "object",
        "required": [
          "items",
          "pagination"
        ],
        "title": "LegacyStationListResponse",
        "description": "CPMS-compatible station list response. TODO(IR-318-REMOVE)."
      },
      "MemberItem": {
        "properties": {
          "userId": {
            "type": "string",
            "title": "Userid"
          },
          "email": {
            "type": "string",
            "title": "Email"
          },
          "role": {
            "type": "string",
            "title": "Role"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "pending"
            ],
            "title": "Status"
          },
          "joinedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Joinedat"
          },
          "invitedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Invitedat"
          },
          "expiresAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Expiresat"
          },
          "invitedBy": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Invitedby"
          },
          "invitationId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Invitationid"
          }
        },
        "type": "object",
        "required": [
          "userId",
          "email",
          "role",
          "status"
        ],
        "title": "MemberItem"
      },
      "MemberListResponse": {
        "properties": {
          "members": {
            "items": {
              "$ref": "#/components/schemas/MemberItem"
            },
            "type": "array",
            "title": "Members"
          }
        },
        "type": "object",
        "required": [
          "members"
        ],
        "title": "MemberListResponse"
      },
      "MeterValue": {
        "properties": {
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "title": "Timestamp",
            "description": "UTC timestamp of the meter reading (OCPP MeterValues timestamp)"
          },
          "value": {
            "type": "number",
            "maximum": 10000000000.0,
            "minimum": 0.0,
            "title": "Value",
            "description": "Measured value in the specified unit (0 to 10,000,000,000)"
          },
          "measurand": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/OcppMeasurand"
              },
              {
                "type": "null"
              }
            ],
            "description": "OCPP measurand type (e.g. Energy.Active.Import.Register, Power.Active.Import, SoC)"
          },
          "unit": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/OcppUnitOfMeasure"
              },
              {
                "type": "null"
              }
            ],
            "description": "OCPP unit of measure (e.g. kWh, kW, Percent, A, V)"
          },
          "phase": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/OcppPhase"
              },
              {
                "type": "null"
              }
            ],
            "description": "OCPP phase (e.g. L1, L2, L3, L1-N)"
          },
          "location": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/OcppLocation"
              },
              {
                "type": "null"
              }
            ],
            "description": "OCPP meter value location (e.g. Outlet, EV, Cable)"
          },
          "reconstructed": {
            "type": "boolean",
            "title": "Reconstructed",
            "description": "True if value was reconstructed by SORC model",
            "default": false
          }
        },
        "type": "object",
        "required": [
          "timestamp",
          "value"
        ],
        "title": "MeterValue",
        "description": "Single OCPP-compatible meter reading from a charging session.",
        "example": {
          "measurand": "Energy.Active.Import.Register",
          "timestamp": "2026-02-27T10:15:00Z",
          "unit": "kWh",
          "value": 12.34
        }
      },
      "ModelDetailResponse": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "name": {
            "type": "string",
            "title": "Name"
          },
          "type": {
            "$ref": "#/components/schemas/ModelType"
          },
          "version": {
            "type": "string",
            "title": "Version"
          },
          "isBase": {
            "type": "boolean",
            "title": "Isbase"
          },
          "baseModel": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Basemodel"
          },
          "metrics": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Metrics"
          },
          "status": {
            "$ref": "#/components/schemas/ModelStatus"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "title": "Createdat"
          },
          "s3Path": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "S3Path"
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          }
        },
        "type": "object",
        "required": [
          "id",
          "name",
          "type",
          "version",
          "isBase",
          "metrics",
          "status",
          "createdAt"
        ],
        "title": "ModelDetailResponse",
        "description": "Full model details."
      },
      "ModelListItem": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "name": {
            "type": "string",
            "title": "Name"
          },
          "type": {
            "$ref": "#/components/schemas/ModelType"
          },
          "version": {
            "type": "string",
            "title": "Version"
          },
          "isBase": {
            "type": "boolean",
            "title": "Isbase"
          },
          "baseModel": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Basemodel"
          },
          "metrics": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Metrics"
          },
          "status": {
            "$ref": "#/components/schemas/ModelStatus"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "title": "Createdat"
          }
        },
        "type": "object",
        "required": [
          "id",
          "name",
          "type",
          "version",
          "isBase",
          "metrics",
          "status",
          "createdAt"
        ],
        "title": "ModelListItem",
        "description": "Model summary."
      },
      "ModelListResponse": {
        "properties": {
          "models": {
            "items": {
              "$ref": "#/components/schemas/ModelListItem"
            },
            "type": "array",
            "title": "Models"
          }
        },
        "type": "object",
        "required": [
          "models"
        ],
        "title": "ModelListResponse"
      },
      "ModelStatus": {
        "type": "string",
        "enum": [
          "active",
          "training",
          "archived"
        ],
        "title": "ModelStatus",
        "description": "Lifecycle status of an ML model."
      },
      "ModelType": {
        "type": "string",
        "enum": [
          "csar_2",
          "csar_c_2",
          "shade",
          "sorc",
          "necro"
        ],
        "title": "ModelType",
        "description": "Type of ML model."
      },
      "OcppLocation": {
        "type": "string",
        "enum": [
          "Body",
          "Cable",
          "EV",
          "Inlet",
          "Outlet"
        ],
        "title": "OcppLocation",
        "description": "OCPP 1.6/2.0.1 meter value location."
      },
      "OcppMeasurand": {
        "type": "string",
        "enum": [
          "Current.Export",
          "Current.Import",
          "Current.Offered",
          "Energy.Active.Export.Register",
          "Energy.Active.Import.Register",
          "Energy.Reactive.Export.Register",
          "Energy.Reactive.Import.Register",
          "Energy.Active.Export.Interval",
          "Energy.Active.Import.Interval",
          "Energy.Reactive.Export.Interval",
          "Energy.Reactive.Import.Interval",
          "Frequency",
          "Power.Active.Export",
          "Power.Active.Import",
          "Power.Factor",
          "Power.Offered",
          "Power.Reactive.Export",
          "Power.Reactive.Import",
          "RPM",
          "SoC",
          "Temperature",
          "Voltage"
        ],
        "title": "OcppMeasurand",
        "description": "OCPP 1.6/2.0.1 measurand values for MeterValues."
      },
      "OcppPhase": {
        "type": "string",
        "enum": [
          "L1",
          "L2",
          "L3",
          "N",
          "L1-N",
          "L2-N",
          "L3-N",
          "L1-L2",
          "L2-L3",
          "L3-L1"
        ],
        "title": "OcppPhase",
        "description": "OCPP 1.6/2.0.1 phase values."
      },
      "OcppUnitOfMeasure": {
        "type": "string",
        "enum": [
          "Wh",
          "kWh",
          "W",
          "kW",
          "A",
          "V",
          "VA",
          "kVA",
          "var",
          "kvar",
          "varh",
          "kvarh",
          "Celsius",
          "Fahrenheit",
          "K",
          "Percent"
        ],
        "title": "OcppUnitOfMeasure",
        "description": "OCPP 1.6/2.0.1 unit of measure values."
      },
      "OrganizationResponse": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id"
          },
          "tenantId": {
            "type": "string",
            "title": "Tenantid"
          },
          "name": {
            "type": "string",
            "title": "Name"
          },
          "phone": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Phone"
          },
          "address": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Address"
          },
          "taxIdType": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Taxidtype"
          },
          "taxIdValue": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Taxidvalue"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "title": "Createdat"
          },
          "updatedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Updatedat"
          }
        },
        "type": "object",
        "required": [
          "id",
          "tenantId",
          "name",
          "createdAt"
        ],
        "title": "OrganizationResponse"
      },
      "OrganizationUpdate": {
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255,
            "minLength": 1,
            "title": "Name"
          },
          "phone": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 50
              },
              {
                "type": "null"
              }
            ],
            "title": "Phone"
          },
          "address": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 500
              },
              {
                "type": "null"
              }
            ],
            "title": "Address"
          },
          "taxIdType": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 30
              },
              {
                "type": "null"
              }
            ],
            "title": "Taxidtype"
          },
          "taxIdValue": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ],
            "title": "Taxidvalue"
          }
        },
        "type": "object",
        "required": [
          "name"
        ],
        "title": "OrganizationUpdate"
      },
      "PaginationInfo": {
        "properties": {
          "totalCount": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Totalcount",
            "description": "Total number of items matching the query"
          },
          "page": {
            "type": "integer",
            "minimum": 1.0,
            "title": "Page",
            "description": "Current page number (1-based)"
          },
          "size": {
            "type": "integer",
            "minimum": 1.0,
            "title": "Size",
            "description": "Number of items per page"
          }
        },
        "type": "object",
        "required": [
          "totalCount",
          "page",
          "size"
        ],
        "title": "PaginationInfo",
        "description": "Pagination metadata returned alongside list content."
      },
      "ProblemDetailResponse": {
        "properties": {
          "type": {
            "type": "string",
            "title": "Type",
            "description": "Machine-readable error type identifier.",
            "examples": [
              "session-not-found"
            ]
          },
          "title": {
            "type": "string",
            "title": "Title",
            "description": "Short human-readable summary of the error type.",
            "examples": [
              "Session Not Found"
            ]
          },
          "status": {
            "type": "integer",
            "title": "Status",
            "description": "HTTP status code.",
            "examples": [
              404
            ]
          },
          "detail": {
            "type": "string",
            "title": "Detail",
            "description": "Human-readable explanation of the specific error.",
            "examples": [
              "Session 'abc-123' not found."
            ]
          }
        },
        "type": "object",
        "required": [
          "type",
          "title",
          "status",
          "detail"
        ],
        "title": "ProblemDetailResponse",
        "description": "RFC 9457 Problem Details response shown in Swagger/OpenAPI docs."
      },
      "ReconstructedSocPoint": {
        "properties": {
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "title": "Timestamp",
            "description": "UTC timestamp matching the OCPP bucket"
          },
          "value": {
            "type": "number",
            "maximum": 100.0,
            "minimum": 0.0,
            "title": "Value",
            "description": "Predicted SoC in percent (0-100)"
          }
        },
        "type": "object",
        "required": [
          "timestamp",
          "value"
        ],
        "title": "ReconstructedSocPoint",
        "description": "One SoC point predicted by the SORC model (overlay only \u2014 never used for inference)."
      },
      "RiskScorePoint": {
        "properties": {
          "timestamp": {
            "type": "string",
            "title": "Timestamp",
            "description": "Timestamp of the risk score observation"
          },
          "riskScore": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Riskscore",
            "description": "Risk score at this point in time"
          }
        },
        "type": "object",
        "required": [
          "timestamp",
          "riskScore"
        ],
        "title": "RiskScorePoint",
        "description": "Single point on the risk score timeline."
      },
      "SaasDataQualityDimensionStats": {
        "properties": {
          "mean": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Mean"
          },
          "median": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Median"
          },
          "p10": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "P10"
          },
          "p90": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "P90"
          }
        },
        "type": "object",
        "required": [
          "mean",
          "median",
          "p10",
          "p90"
        ],
        "title": "SaasDataQualityDimensionStats",
        "description": "Per-dimension distribution stats."
      },
      "SaasDataQualityDimensions": {
        "properties": {
          "completeness": {
            "$ref": "#/components/schemas/SaasDataQualityDimensionStats"
          },
          "rangeValidity": {
            "$ref": "#/components/schemas/SaasDataQualityDimensionStats"
          },
          "monotonicity": {
            "$ref": "#/components/schemas/SaasDataQualityDimensionStats"
          },
          "density": {
            "$ref": "#/components/schemas/SaasDataQualityDimensionStats"
          },
          "consistency": {
            "$ref": "#/components/schemas/SaasDataQualityDimensionStats"
          }
        },
        "type": "object",
        "required": [
          "completeness",
          "rangeValidity",
          "monotonicity",
          "density",
          "consistency"
        ],
        "title": "SaasDataQualityDimensions",
        "description": "Five-dimensional quality breakdown."
      },
      "SaasDataQualityDistribution": {
        "properties": {
          "mean": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Mean"
          },
          "median": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Median"
          },
          "p10": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "P10"
          },
          "p25": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "P25"
          },
          "p75": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "P75"
          },
          "p90": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "P90"
          },
          "histogram": {
            "items": {
              "type": "integer"
            },
            "type": "array",
            "maxItems": 20,
            "minItems": 20,
            "title": "Histogram"
          }
        },
        "type": "object",
        "required": [
          "mean",
          "median",
          "p10",
          "p25",
          "p75",
          "p90",
          "histogram"
        ],
        "title": "SaasDataQualityDistribution",
        "description": "Distribution stats over session_quality across a range."
      },
      "SaasDataQualityRangeSnapshot": {
        "properties": {
          "totalSessions": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Totalsessions"
          },
          "socReconstructedCount": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Socreconstructedcount"
          },
          "sessionsClosedByClient": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Sessionsclosedbyclient",
            "description": "Sessions finalized by the client (hard close) in this range window.",
            "default": 0
          },
          "sessionsClosedByDaemon": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Sessionsclosedbydaemon",
            "description": "Sessions finalized by the session-closer daemon (soft close) in this range window.",
            "default": 0
          },
          "sessionQuality": {
            "$ref": "#/components/schemas/SaasDataQualityDistribution"
          },
          "aboveThreshold": {
            "additionalProperties": {
              "type": "number"
            },
            "type": "object",
            "title": "Abovethreshold"
          },
          "dimensions": {
            "$ref": "#/components/schemas/SaasDataQualityDimensions"
          },
          "topDefects": {
            "items": {
              "$ref": "#/components/schemas/SaasDataQualityTopDefect"
            },
            "type": "array",
            "title": "Topdefects"
          },
          "statusBreakdown": {
            "additionalProperties": {
              "type": "integer"
            },
            "type": "object",
            "title": "Statusbreakdown"
          }
        },
        "type": "object",
        "required": [
          "totalSessions",
          "socReconstructedCount",
          "sessionQuality",
          "aboveThreshold",
          "dimensions",
          "topDefects",
          "statusBreakdown"
        ],
        "title": "SaasDataQualityRangeSnapshot",
        "description": "Per-range aggregate, mirrors `build_report()` output."
      },
      "SaasDataQualityRanges": {
        "properties": {
          "7d": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SaasDataQualityRangeSnapshot"
              },
              {
                "type": "null"
              }
            ]
          },
          "30d": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SaasDataQualityRangeSnapshot"
              },
              {
                "type": "null"
              }
            ]
          },
          "all": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SaasDataQualityRangeSnapshot"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "type": "object",
        "title": "SaasDataQualityRanges",
        "description": "Three named time-window snapshots."
      },
      "SaasDataQualityResponse": {
        "properties": {
          "generatedAt": {
            "type": "string",
            "format": "date-time",
            "title": "Generatedat"
          },
          "ranges": {
            "$ref": "#/components/schemas/SaasDataQualityRanges"
          }
        },
        "type": "object",
        "required": [
          "generatedAt",
          "ranges"
        ],
        "title": "SaasDataQualityResponse",
        "description": "Top-level data quality block embedded into SaasStatisticsResponse."
      },
      "SaasDataQualityTopDefect": {
        "properties": {
          "code": {
            "type": "string",
            "title": "Code"
          },
          "count": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Count"
          }
        },
        "type": "object",
        "required": [
          "code",
          "count"
        ],
        "title": "SaasDataQualityTopDefect",
        "description": "One entry of the top_defects list."
      },
      "SaasStatisticsResponse": {
        "properties": {
          "activeAnomaliesCount": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Activeanomaliescount",
            "description": "Number of currently active (unresolved) anomalies"
          },
          "sessionsWithAnomaliesCount": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Sessionswithanomaliescount",
            "description": "Sessions with at least one detected anomaly"
          },
          "connectorsWithAnomaliesCount": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Connectorswithanomaliescount",
            "description": "Connectors with at least one detected anomaly"
          },
          "totalAnomaliesCount": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Totalanomaliescount",
            "description": "Total anomalies detected across all sessions"
          },
          "chargingStationsWithAnomaliesCount": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Chargingstationswithanomaliescount",
            "description": "Charging stations with at least one anomalous session"
          },
          "uptimePercentage": {
            "type": "number",
            "maximum": 100.0,
            "minimum": 0.0,
            "title": "Uptimepercentage",
            "description": "Overall system uptime percentage"
          },
          "uptimeDelta": {
            "type": "number",
            "title": "Uptimedelta",
            "description": "Change in uptime percentage compared to previous period"
          },
          "totalSessions": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Totalsessions",
            "description": "Total charging sessions for this tenant"
          },
          "totalRevenue": {
            "type": "number",
            "minimum": 0.0,
            "title": "Totalrevenue",
            "description": "Total revenue across all sessions"
          },
          "revenueAtRisk": {
            "type": "number",
            "minimum": 0.0,
            "title": "Revenueatrisk",
            "description": "Revenue associated with anomalous sessions"
          },
          "revenueLeakEstimate": {
            "type": "number",
            "minimum": 0.0,
            "title": "Revenueleakestimate",
            "description": "Estimated revenue loss due to anomalies"
          },
          "dataQuality": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SaasDataQualityResponse"
              },
              {
                "type": "null"
              }
            ],
            "description": "Data quality summary across 7d/30d/all ranges; None until first daemon run."
          }
        },
        "type": "object",
        "required": [
          "activeAnomaliesCount",
          "sessionsWithAnomaliesCount",
          "connectorsWithAnomaliesCount",
          "totalAnomaliesCount",
          "chargingStationsWithAnomaliesCount",
          "uptimePercentage",
          "uptimeDelta",
          "totalSessions",
          "totalRevenue",
          "revenueAtRisk",
          "revenueLeakEstimate"
        ],
        "title": "SaasStatisticsResponse",
        "description": "Tenant-wide AI observability statistics matching frontend AiObservabilityStatistics type.",
        "example": {
          "activeAnomaliesCount": 12,
          "chargingStationsWithAnomaliesCount": 4,
          "connectorsWithAnomaliesCount": 8,
          "revenueAtRisk": 1200.0,
          "revenueLeakEstimate": 380.25,
          "sessionsWithAnomaliesCount": 47,
          "totalAnomaliesCount": 134,
          "totalRevenue": 45200.5,
          "totalSessions": 1250,
          "uptimeDelta": 0.3,
          "uptimePercentage": 98.5
        }
      },
      "SessionAnalysisResponse": {
        "properties": {
          "sessionId": {
            "type": "string",
            "title": "Sessionid",
            "description": "Session identifier"
          },
          "chargingStationId": {
            "type": "string",
            "title": "Chargingstationid",
            "description": "Charging station identifier"
          },
          "connectorId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Connectorid",
            "description": "Connector identifier within the charging station"
          },
          "evseId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Evseid",
            "description": "EVSE identifier (EU standard)"
          },
          "status": {
            "$ref": "#/components/schemas/SessionStatus",
            "description": "Session status: pending, active, or failed"
          },
          "isAnomaly": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Isanomaly",
            "description": "Whether any anomaly was detected (null if pending). Value is from the last completed inference and may be null while a background analysis is in flight (eventual consistency)."
          },
          "anomalyScore": {
            "anyOf": [
              {
                "type": "number",
                "maximum": 1.0,
                "minimum": 0.0
              },
              {
                "type": "null"
              }
            ],
            "title": "Anomalyscore",
            "description": "Overall anomaly score (null if pending). Value is from the last completed inference and may be null while a background analysis is in flight (eventual consistency)."
          },
          "anomalyConfidence": {
            "anyOf": [
              {
                "type": "number",
                "maximum": 1.0,
                "minimum": 0.0
              },
              {
                "type": "null"
              }
            ],
            "title": "Anomalyconfidence",
            "description": "Overall model confidence (null if pending)"
          },
          "isIncident": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Isincident",
            "description": "Confirmed incident (null if pending)"
          },
          "isRecurring": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Isrecurring",
            "description": "Recurring pattern (null if pending)"
          },
          "anomalies": {
            "items": {
              "$ref": "#/components/schemas/AnomalyDetail"
            },
            "type": "array",
            "title": "Anomalies",
            "description": "Detected anomalies (empty if pending)"
          },
          "analyzedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Analyzedat",
            "description": "Timestamp of the last COMPLETED inference (UTC). May predate the meter values in this response while a background analysis is in flight (eventual consistency)."
          },
          "socReconstructed": {
            "type": "boolean",
            "title": "Socreconstructed",
            "description": "Whether SoC was reconstructed by SORC model",
            "default": false
          },
          "message": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Message",
            "description": "Informational message about the analysis status (e.g. why inference was not performed)"
          },
          "stopReason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Stopreason",
            "description": "OCPP stop reason (e.g. Local, Remote, EVDisconnected)"
          },
          "createdAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Createdat",
            "description": "Session creation timestamp (null if unavailable)"
          }
        },
        "type": "object",
        "required": [
          "sessionId",
          "chargingStationId",
          "status"
        ],
        "title": "SessionAnalysisResponse",
        "description": "Result of anomaly analysis for a single session inference run.",
        "example": {
          "analyzedAt": "2026-02-27T10:31:02Z",
          "anomalies": [
            {
              "bucketRange": {
                "endUnit": 7,
                "startUnit": 4
              },
              "category": "KWH_DECREASE",
              "confidence": 0.92,
              "score": 0.87
            }
          ],
          "anomalyConfidence": 0.92,
          "anomalyScore": 0.85,
          "chargingStationId": "CP-NL-AMS-0042",
          "connectorId": "1",
          "evseId": "NL*ABC*E12345",
          "isAnomaly": true,
          "isIncident": false,
          "isRecurring": true,
          "sessionId": "sess-abc-001",
          "status": "active"
        }
      },
      "SessionAskRequest": {
        "properties": {
          "question": {
            "type": "string",
            "maxLength": 2000,
            "minLength": 1,
            "title": "Question",
            "description": "Natural language question about the session"
          },
          "lang": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 5,
                "minLength": 2,
                "pattern": "^[a-z]{2,5}$"
              },
              {
                "type": "null"
              }
            ],
            "title": "Lang",
            "description": "Response language (e.g. 'en', 'pl'). If omitted, LLM responds in question language."
          }
        },
        "type": "object",
        "required": [
          "question"
        ],
        "title": "SessionAskRequest",
        "description": "Ask a question about a specific session.",
        "example": {
          "lang": "en",
          "question": "Why did the SoC drop unexpectedly?"
        }
      },
      "SessionAskResponse": {
        "properties": {
          "sessionId": {
            "type": "string",
            "title": "Sessionid",
            "description": "Session identifier"
          },
          "answer": {
            "type": "string",
            "title": "Answer",
            "description": "Answer to the question about this session"
          }
        },
        "type": "object",
        "required": [
          "sessionId",
          "answer"
        ],
        "title": "SessionAskResponse",
        "description": "LLM-generated answer about a session."
      },
      "SessionCreateRequest": {
        "properties": {
          "sessionId": {
            "type": "string",
            "maxLength": 255,
            "minLength": 1,
            "title": "Sessionid",
            "description": "Client's unique session identifier. Used for upsert (find-or-create)"
          },
          "chargingStationId": {
            "type": "string",
            "maxLength": 255,
            "title": "Chargingstationid",
            "description": "Charging station identifier (EVSE location)"
          },
          "connectorId": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 255
              },
              {
                "type": "null"
              }
            ],
            "title": "Connectorid",
            "description": "Connector identifier within the charging station"
          },
          "evseId": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 255
              },
              {
                "type": "null"
              }
            ],
            "title": "Evseid",
            "description": "EVSE identifier (EU standard)"
          },
          "meterValues": {
            "items": {
              "$ref": "#/components/schemas/MeterValue"
            },
            "type": "array",
            "title": "Metervalues",
            "description": "Initial meter readings. Optional \u2014 session can be created empty and populated later via PATCH or PUT."
          },
          "metadata": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Metadata",
            "description": "Optional client metadata for the session"
          },
          "status": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ClientSessionStatus"
              },
              {
                "type": "null"
              }
            ],
            "description": "Optional initial session status (active, pending, completed, or invalid)"
          },
          "stopReason": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 50
              },
              {
                "type": "null"
              }
            ],
            "title": "Stopreason",
            "description": "OCPP stop reason (e.g. Local, Remote, EVDisconnected)"
          }
        },
        "type": "object",
        "required": [
          "sessionId",
          "chargingStationId"
        ],
        "title": "SessionCreateRequest",
        "description": "Create a charging session and optionally provide initial meter values.\n\nIf enough meter values are provided (>= 3), inference runs automatically.\nOtherwise the session is created in pending status awaiting more data.",
        "example": {
          "chargingStationId": "CP-NL-AMS-0042",
          "connectorId": "1",
          "meterValues": [
            {
              "measurand": "Energy.Active.Import.Register",
              "timestamp": "2026-02-27T10:00:00Z",
              "unit": "kWh",
              "value": 0.0
            },
            {
              "measurand": "Power.Active.Import",
              "timestamp": "2026-02-27T10:00:00Z",
              "unit": "kW",
              "value": 0.0
            },
            {
              "measurand": "SoC",
              "timestamp": "2026-02-27T10:00:00Z",
              "unit": "Percent",
              "value": 80.0
            },
            {
              "measurand": "Energy.Active.Import.Register",
              "timestamp": "2026-02-27T10:15:00Z",
              "unit": "kWh",
              "value": 5.5
            },
            {
              "measurand": "Power.Active.Import",
              "timestamp": "2026-02-27T10:15:00Z",
              "unit": "kW",
              "value": 22.0
            },
            {
              "measurand": "SoC",
              "timestamp": "2026-02-27T10:15:00Z",
              "unit": "Percent",
              "value": 65.0
            },
            {
              "measurand": "Energy.Active.Import.Register",
              "timestamp": "2026-02-27T10:30:00Z",
              "unit": "kWh",
              "value": 11.1
            },
            {
              "measurand": "Power.Active.Import",
              "timestamp": "2026-02-27T10:30:00Z",
              "unit": "kW",
              "value": 22.0
            },
            {
              "measurand": "SoC",
              "timestamp": "2026-02-27T10:30:00Z",
              "unit": "Percent",
              "value": 50.0
            }
          ],
          "sessionId": "sess-abc-001"
        }
      },
      "SessionDetailResponse": {
        "properties": {
          "sessionId": {
            "type": "string",
            "title": "Sessionid",
            "description": "Session identifier"
          },
          "chargingStationId": {
            "type": "string",
            "title": "Chargingstationid",
            "description": "Charging station identifier"
          },
          "connectorId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Connectorid",
            "description": "Connector identifier within the charging station"
          },
          "evseId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Evseid",
            "description": "EVSE identifier (EU standard)"
          },
          "status": {
            "$ref": "#/components/schemas/SessionStatus",
            "description": "Session lifecycle status: pending \u2192 active \u2192 failed"
          },
          "isAnomaly": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Isanomaly",
            "description": "Whether any anomaly was detected (null if pending). Value is from the last completed inference and may be null while a background analysis is in flight (eventual consistency)."
          },
          "anomalyScore": {
            "anyOf": [
              {
                "type": "number",
                "maximum": 1.0,
                "minimum": 0.0
              },
              {
                "type": "null"
              }
            ],
            "title": "Anomalyscore",
            "description": "Overall anomaly score (null if pending). Value is from the last completed inference and may be null while a background analysis is in flight (eventual consistency)."
          },
          "anomalyConfidence": {
            "anyOf": [
              {
                "type": "number",
                "maximum": 1.0,
                "minimum": 0.0
              },
              {
                "type": "null"
              }
            ],
            "title": "Anomalyconfidence",
            "description": "Overall model confidence (null if pending)"
          },
          "isIncident": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Isincident",
            "description": "Confirmed incident (null if pending)"
          },
          "isRecurring": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Isrecurring",
            "description": "Recurring pattern (null if pending)"
          },
          "anomalies": {
            "items": {
              "$ref": "#/components/schemas/AnomalyDetail"
            },
            "type": "array",
            "title": "Anomalies",
            "description": "Detected anomalies (empty if pending)"
          },
          "analyzedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Analyzedat",
            "description": "Timestamp of the last COMPLETED inference (UTC). May predate the meter values in this response while a background analysis is in flight (eventual consistency)."
          },
          "socReconstructed": {
            "type": "boolean",
            "title": "Socreconstructed",
            "description": "Whether SoC was reconstructed by SORC model",
            "default": false
          },
          "message": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Message",
            "description": "Informational message about the analysis status (e.g. why inference was not performed)"
          },
          "stopReason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Stopreason",
            "description": "OCPP stop reason (e.g. Local, Remote, EVDisconnected)"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "title": "Createdat",
            "description": "Session creation timestamp (UTC)"
          },
          "meterValues": {
            "items": {
              "$ref": "#/components/schemas/MeterValue"
            },
            "type": "array",
            "title": "Metervalues",
            "description": "All meter readings received for this session"
          },
          "reconstructedSoc": {
            "items": {
              "$ref": "#/components/schemas/ReconstructedSocPoint"
            },
            "type": "array",
            "title": "Reconstructedsoc",
            "description": "SoC points predicted by the SORC model when raw OCPP SoC was insufficient. Provided as a separate overlay; not part of meter_values used for inference."
          },
          "sorcConfidence": {
            "anyOf": [
              {
                "type": "number",
                "maximum": 1.0,
                "minimum": 0.0
              },
              {
                "type": "null"
              }
            ],
            "title": "Sorcconfidence",
            "description": "Confidence of the SORC prediction (only set when reconstructed_soc is non-empty)"
          }
        },
        "type": "object",
        "required": [
          "sessionId",
          "chargingStationId",
          "status",
          "createdAt",
          "meterValues"
        ],
        "title": "SessionDetailResponse",
        "description": "Full session details including meter values and latest analysis result.",
        "example": {
          "analyzedAt": "2026-02-27T10:31:02Z",
          "anomalies": [
            {
              "bucketRange": {
                "endUnit": 7,
                "startUnit": 4
              },
              "category": "KWH_DECREASE",
              "confidence": 0.92,
              "score": 0.87
            }
          ],
          "anomalyConfidence": 0.92,
          "anomalyScore": 0.85,
          "chargingStationId": "CP-NL-AMS-0042",
          "connectorId": "1",
          "evseId": "NL*ABC*E12345",
          "isAnomaly": true,
          "isIncident": false,
          "isRecurring": true,
          "sessionId": "sess-abc-001",
          "status": "active"
        }
      },
      "SessionExplainRequest": {
        "properties": {
          "lang": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 5,
                "minLength": 2,
                "pattern": "^[a-z]{2,5}$"
              },
              {
                "type": "null"
              }
            ],
            "title": "Lang",
            "description": "Response language (e.g. 'en', 'pl'). If omitted, LLM responds in context language."
          },
          "regenerate": {
            "type": "boolean",
            "title": "Regenerate",
            "description": "Force regeneration of the explanation, replacing any cached version. Uses 1 AI credit.",
            "default": false
          }
        },
        "type": "object",
        "title": "SessionExplainRequest",
        "description": "Request LLM explanation of session anomalies.",
        "example": {
          "lang": "en",
          "regenerate": false
        }
      },
      "SessionExplainResponse": {
        "properties": {
          "sessionId": {
            "type": "string",
            "title": "Sessionid",
            "description": "Session identifier"
          },
          "explanation": {
            "type": "string",
            "title": "Explanation",
            "description": "Human-readable explanation of the detected anomalies"
          },
          "cached": {
            "type": "boolean",
            "title": "Cached",
            "description": "Whether this explanation was served from cache",
            "default": false
          }
        },
        "type": "object",
        "required": [
          "sessionId",
          "explanation"
        ],
        "title": "SessionExplainResponse",
        "description": "LLM-generated explanation of session anomalies."
      },
      "SessionListItem": {
        "properties": {
          "sessionId": {
            "type": "string",
            "title": "Sessionid",
            "description": "Client-provided session identifier"
          },
          "chargingStationId": {
            "type": "string",
            "title": "Chargingstationid",
            "description": "Charging station identifier"
          },
          "isAnomaly": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Isanomaly",
            "description": "Anomaly flag from latest inference (null if not yet analyzed)"
          },
          "anomalyScore": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Anomalyscore",
            "description": "Latest anomaly score (null if not yet analyzed)"
          },
          "anomalyCount": {
            "type": "integer",
            "title": "Anomalycount",
            "description": "Number of anomaly categories detected in latest inference"
          },
          "status": {
            "$ref": "#/components/schemas/SessionStatus",
            "description": "Session lifecycle status: pending \u2192 active \u2192 failed"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "title": "Createdat",
            "description": "Session creation timestamp (UTC)"
          },
          "lastAnalyzedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Lastanalyzedat",
            "description": "Last successful analysis timestamp (UTC)"
          },
          "defectCodes": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Defectcodes",
            "description": "Data-quality defect codes (S1\u2013S10) present in this session; empty if never scored"
          }
        },
        "type": "object",
        "required": [
          "sessionId",
          "chargingStationId",
          "isAnomaly",
          "anomalyScore",
          "anomalyCount",
          "status",
          "createdAt",
          "lastAnalyzedAt"
        ],
        "title": "SessionListItem",
        "description": "Summary of an analyzed session (from materialized view).",
        "example": {
          "anomalyCount": 2,
          "anomalyScore": 0.85,
          "chargingStationId": "CP-NL-AMS-0042",
          "createdAt": "2026-02-27T10:00:00Z",
          "defectCodes": [
            "S4",
            "S7"
          ],
          "isAnomaly": true,
          "lastAnalyzedAt": "2026-02-27T10:31:02Z",
          "sessionId": "sess-abc-001",
          "status": "active"
        }
      },
      "SessionListResponse": {
        "properties": {
          "content": {
            "items": {
              "$ref": "#/components/schemas/SessionListItem"
            },
            "type": "array",
            "title": "Content",
            "description": "Sessions on the current page"
          },
          "pagination": {
            "$ref": "#/components/schemas/PaginationInfo",
            "description": "Pagination metadata"
          }
        },
        "type": "object",
        "required": [
          "content",
          "pagination"
        ],
        "title": "SessionListResponse",
        "description": "Paginated list of analyzed sessions."
      },
      "SessionReplaceRequest": {
        "properties": {
          "meterValues": {
            "items": {
              "$ref": "#/components/schemas/MeterValue"
            },
            "type": "array",
            "minItems": 1,
            "title": "Metervalues",
            "description": "Complete set of meter readings (replaces all previous)"
          },
          "metadata": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Metadata",
            "description": "Optional client metadata to set/update"
          },
          "status": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ClientSessionStatus"
              },
              {
                "type": "null"
              }
            ],
            "description": "Optional session status update (completed or invalid)"
          },
          "stopReason": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 50
              },
              {
                "type": "null"
              }
            ],
            "title": "Stopreason",
            "description": "OCPP stop reason (e.g. Local, Remote, EVDisconnected)"
          }
        },
        "type": "object",
        "required": [
          "meterValues"
        ],
        "title": "SessionReplaceRequest",
        "description": "Replace all meter values for a session (PUT semantics).",
        "example": {
          "meterValues": [
            {
              "measurand": "Energy.Active.Import.Register",
              "timestamp": "2026-02-27T10:00:00Z",
              "unit": "kWh",
              "value": 0.0
            },
            {
              "measurand": "Energy.Active.Import.Register",
              "timestamp": "2026-02-27T10:15:00Z",
              "unit": "kWh",
              "value": 5.5
            },
            {
              "measurand": "Energy.Active.Import.Register",
              "timestamp": "2026-02-27T10:30:00Z",
              "unit": "kWh",
              "value": 11.1
            }
          ]
        }
      },
      "SessionStatus": {
        "type": "string",
        "enum": [
          "pending",
          "active",
          "completed",
          "invalid",
          "failed"
        ],
        "title": "SessionStatus",
        "description": "Processing status of a charging session."
      },
      "SessionUpdateRequest": {
        "properties": {
          "meterValues": {
            "items": {
              "$ref": "#/components/schemas/MeterValue"
            },
            "type": "array",
            "title": "Metervalues",
            "description": "Meter readings to append to the session"
          },
          "metadata": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Metadata",
            "description": "Optional client metadata to set/update"
          },
          "status": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ClientSessionStatus"
              },
              {
                "type": "null"
              }
            ],
            "description": "Optional session status update (completed or invalid)"
          },
          "stopReason": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 50
              },
              {
                "type": "null"
              }
            ],
            "title": "Stopreason",
            "description": "OCPP stop reason (e.g. Local, Remote, EVDisconnected)"
          }
        },
        "type": "object",
        "title": "SessionUpdateRequest",
        "description": "Append meter values to an existing session (PATCH semantics).",
        "example": {
          "meterValues": [
            {
              "measurand": "Energy.Active.Import.Register",
              "timestamp": "2026-02-27T10:45:00Z",
              "unit": "kWh",
              "value": 16.5
            }
          ]
        }
      },
      "ShadeOverviewResponse": {
        "properties": {
          "chargingStationId": {
            "type": "string",
            "title": "Chargingstationid",
            "description": "Station identifier"
          },
          "dayScore": {
            "type": "number",
            "title": "Dayscore",
            "description": "Overall day anomaly score"
          },
          "isAnomaly": {
            "type": "boolean",
            "title": "Isanomaly",
            "description": "Whether the station has active anomalies"
          },
          "energyTimeline": {
            "items": {
              "$ref": "#/components/schemas/EnergyTimelinePoint"
            },
            "type": "array",
            "title": "Energytimeline",
            "description": "Cumulative kWh over the analysis day"
          },
          "anomalyMarkers": {
            "items": {
              "$ref": "#/components/schemas/AnomalyMarker"
            },
            "type": "array",
            "title": "Anomalymarkers",
            "description": "SHADE-detected anomaly time ranges"
          },
          "analyzedAt": {
            "type": "string",
            "format": "date-time",
            "title": "Analyzedat",
            "description": "When the SHADE inference was run (UTC)"
          }
        },
        "type": "object",
        "required": [
          "chargingStationId",
          "dayScore",
          "isAnomaly",
          "energyTimeline",
          "anomalyMarkers",
          "analyzedAt"
        ],
        "title": "ShadeOverviewResponse",
        "description": "SHADE station overview: cumulative energy timeline with anomaly markers."
      },
      "StationAnomalyItem": {
        "properties": {
          "inferenceId": {
            "type": "string",
            "title": "Inferenceid",
            "description": "Inference run identifier"
          },
          "isAnomaly": {
            "type": "boolean",
            "title": "Isanomaly",
            "description": "Always true (only anomaly buckets are returned)"
          },
          "anomalyScore": {
            "type": "number",
            "minimum": 0.0,
            "title": "Anomalyscore",
            "description": "Anomaly score for this bucket"
          },
          "detectionDetails": {
            "additionalProperties": true,
            "type": "object",
            "title": "Detectiondetails",
            "description": "Bucket details (bucket_index, start_minute)"
          },
          "analyzedAt": {
            "type": "string",
            "format": "date-time",
            "title": "Analyzedat",
            "description": "Absolute UTC timestamp of the anomaly bucket"
          }
        },
        "type": "object",
        "required": [
          "inferenceId",
          "isAnomaly",
          "anomalyScore",
          "detectionDetails",
          "analyzedAt"
        ],
        "title": "StationAnomalyItem",
        "description": "Single anomaly bucket from the latest SHADE inference.\n\nEach item represents a 15-min anomaly bucket, mapped to the original\nresponse schema for frontend compatibility."
      },
      "StationAnomalyListResponse": {
        "properties": {
          "content": {
            "items": {
              "$ref": "#/components/schemas/StationAnomalyItem"
            },
            "type": "array",
            "title": "Content",
            "description": "Anomaly records on the current page"
          },
          "pagination": {
            "$ref": "#/components/schemas/PaginationInfo",
            "description": "Pagination metadata"
          }
        },
        "type": "object",
        "required": [
          "content",
          "pagination"
        ],
        "title": "StationAnomalyListResponse",
        "description": "Paginated station-level anomaly history."
      },
      "StationConnectorItem": {
        "properties": {
          "connectorId": {
            "type": "string",
            "title": "Connectorid",
            "description": "Connector identifier"
          },
          "totalSessions": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Totalsessions",
            "description": "Total sessions on this connector"
          },
          "anomalousSessions": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Anomaloussessions",
            "description": "Anomalous sessions on this connector"
          },
          "anomalyCategories": {
            "additionalProperties": {
              "type": "integer"
            },
            "propertyNames": {
              "$ref": "#/components/schemas/AnomalyCategory"
            },
            "type": "object",
            "title": "Anomalycategories",
            "description": "Anomaly count per category (e.g. KWH_DECREASE: 2)"
          }
        },
        "type": "object",
        "required": [
          "connectorId",
          "totalSessions",
          "anomalousSessions",
          "anomalyCategories"
        ],
        "title": "StationConnectorItem",
        "description": "Connector with per-category anomaly breakdown.",
        "example": {
          "anomalousSessions": 3,
          "anomalyCategories": {
            "ENERGY_PIT": 1,
            "KWH_DECREASE": 2
          },
          "connectorId": "1",
          "totalSessions": 80
        }
      },
      "StationConnectorsResponse": {
        "properties": {
          "chargingStationId": {
            "type": "string",
            "title": "Chargingstationid",
            "description": "Station identifier"
          },
          "connectors": {
            "items": {
              "$ref": "#/components/schemas/StationConnectorItem"
            },
            "type": "array",
            "title": "Connectors",
            "description": "Connectors with anomaly statistics"
          }
        },
        "type": "object",
        "required": [
          "chargingStationId",
          "connectors"
        ],
        "title": "StationConnectorsResponse",
        "description": "All connectors for a station with anomaly breakdowns."
      },
      "StationDetailResponse": {
        "properties": {
          "chargingStationId": {
            "type": "string",
            "title": "Chargingstationid",
            "description": "Client-provided station identifier"
          },
          "connectors": {
            "items": {
              "$ref": "#/components/schemas/ConnectorInfo"
            },
            "type": "array",
            "title": "Connectors",
            "description": "Connectors at this station with per-connector statistics"
          },
          "totalSessions": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Totalsessions",
            "description": "Total charging sessions at this station"
          },
          "anomalousSessions": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Anomaloussessions",
            "description": "Sessions with at least one detected anomaly"
          },
          "metadata": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Metadata",
            "description": "Station metadata (address, operator, etc.) as provided by client"
          }
        },
        "type": "object",
        "required": [
          "chargingStationId",
          "connectors",
          "totalSessions",
          "anomalousSessions"
        ],
        "title": "StationDetailResponse",
        "description": "Full station details with connectors and aggregated statistics.",
        "example": {
          "anomalousSessions": 7,
          "chargingStationId": "ST-NL-AMS-01",
          "connectors": [
            {
              "anomalousSessions": 3,
              "connectorId": "1",
              "totalSessions": 80
            },
            {
              "anomalousSessions": 4,
              "connectorId": "2",
              "totalSessions": 62
            }
          ],
          "metadata": {
            "address": "Keizersgracht 100, Amsterdam",
            "operator": "FastNed"
          },
          "totalSessions": 142
        }
      },
      "StationEnergyResponse": {
        "properties": {
          "chargingStationId": {
            "type": "string",
            "title": "Chargingstationid",
            "description": "Station identifier"
          },
          "energyDelivered": {
            "type": "number",
            "minimum": 0.0,
            "title": "Energydelivered",
            "description": "Total energy delivered in the window (kWh)"
          },
          "energyConsumptionStation": {
            "items": {
              "$ref": "#/components/schemas/EnergyPoint"
            },
            "type": "array",
            "title": "Energyconsumptionstation",
            "description": "Aggregated energy timeline (sum of all connectors)"
          },
          "energyConsumptionConnectors": {
            "items": {
              "$ref": "#/components/schemas/ConnectorEnergy"
            },
            "type": "array",
            "title": "Energyconsumptionconnectors",
            "description": "Per-connector energy timelines"
          },
          "anomalyOccurrences": {
            "items": {
              "type": "string",
              "format": "date-time"
            },
            "type": "array",
            "title": "Anomalyoccurrences",
            "description": "ISO timestamps of SHADE anomaly buckets in the window"
          }
        },
        "type": "object",
        "required": [
          "chargingStationId",
          "energyDelivered",
          "energyConsumptionStation",
          "energyConsumptionConnectors",
          "anomalyOccurrences"
        ],
        "title": "StationEnergyResponse",
        "description": "Station energy overview with per-connector breakdown.",
        "example": {
          "anomalyOccurrences": [
            "2026-04-05T22:30:00Z"
          ],
          "chargingStationId": "ST-NL-AMS-01",
          "energyConsumptionConnectors": [
            {
              "connectorId": "1",
              "energy": [
                {
                  "energy": 5.1,
                  "timestamp": "2026-04-05T17:00:00Z"
                }
              ]
            }
          ],
          "energyConsumptionStation": [
            {
              "energy": 0.0,
              "timestamp": "2026-04-05T17:00:00Z"
            },
            {
              "energy": 12.5,
              "timestamp": "2026-04-05T18:00:00Z"
            }
          ],
          "energyDelivered": 38.0
        }
      },
      "StationInferenceResponse": {
        "properties": {
          "chargingStationId": {
            "type": "string",
            "title": "Chargingstationid",
            "description": "Analyzed station identifier"
          },
          "isAnomaly": {
            "type": "boolean",
            "title": "Isanomaly",
            "description": "Whether a station-level anomaly was detected"
          },
          "anomalyScore": {
            "type": "number",
            "minimum": 0.0,
            "title": "Anomalyscore",
            "description": "Station anomaly severity score (SHADE reconstruction error)"
          },
          "detectionDetails": {
            "additionalProperties": true,
            "type": "object",
            "title": "Detectiondetails",
            "description": "SHADE detection breakdown (anomaly type, affected period, metrics)"
          },
          "analyzedAt": {
            "type": "string",
            "format": "date-time",
            "title": "Analyzedat",
            "description": "Analysis completion timestamp (UTC)"
          }
        },
        "type": "object",
        "required": [
          "chargingStationId",
          "isAnomaly",
          "anomalyScore",
          "detectionDetails",
          "analyzedAt"
        ],
        "title": "StationInferenceResponse",
        "description": "Result of SHADE station-level inference (GET response).",
        "example": {
          "analyzedAt": "2026-02-27T12:00:00Z",
          "anomalyScore": 0.72,
          "chargingStationId": "ST-NL-AMS-01",
          "detectionDetails": {
            "actual_energy_kwh": 980.2,
            "affected_period": "2026-02-27",
            "anomaly_type": "energy_drop",
            "expected_energy_kwh": 1200.0
          },
          "isAnomaly": true
        }
      },
      "StationListItem": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id",
            "description": "Internal station identifier"
          },
          "ocppChargingStationId": {
            "type": "string",
            "title": "Ocppchargingstationid",
            "description": "Client-provided station identifier"
          },
          "chargingStationId": {
            "type": "string",
            "title": "Chargingstationid",
            "description": "Client-provided station identifier (alias)"
          },
          "aiScore": {
            "type": "number",
            "title": "Aiscore",
            "description": "Highest anomaly score across all sessions",
            "default": 0.0
          },
          "totalAnomalies": {
            "type": "integer",
            "minimum": 0.0,
            "title": "Totalanomalies",
            "description": "Sessions with at least one detected anomaly"
          },
          "lastAnomalyDate": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Lastanomalydate",
            "description": "Timestamp of the most recent anomaly detection (UTC)"
          }
        },
        "type": "object",
        "required": [
          "id",
          "ocppChargingStationId",
          "chargingStationId",
          "totalAnomalies"
        ],
        "title": "StationListItem",
        "description": "Station summary with aggregated anomaly statistics (from materialized view).",
        "example": {
          "aiScore": 0.91,
          "chargingStationId": "ST-NL-AMS-01",
          "id": "019c...",
          "lastAnomalyDate": "2026-02-27T09:45:00Z",
          "ocppChargingStationId": "ST-NL-AMS-01",
          "totalAnomalies": 7
        }
      },
      "StationListResponse": {
        "properties": {
          "content": {
            "items": {
              "$ref": "#/components/schemas/StationListItem"
            },
            "type": "array",
            "title": "Content",
            "description": "Stations on the current page"
          },
          "pagination": {
            "$ref": "#/components/schemas/PaginationInfo",
            "description": "Pagination metadata"
          }
        },
        "type": "object",
        "required": [
          "content",
          "pagination"
        ],
        "title": "StationListResponse",
        "description": "Paginated list of charging stations."
      },
      "StationLookupResponse": {
        "properties": {
          "items": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Items",
            "description": "Distinct station identifiers for this tenant"
          }
        },
        "type": "object",
        "required": [
          "items"
        ],
        "title": "StationLookupResponse",
        "description": "Flat list of station IDs for UI filter dropdowns."
      },
      "UpdateIssueRequest": {
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "OPEN",
              "IN_PROGRESS",
              "RESOLVED",
              "DISMISSED",
              "ASSIGNED"
            ],
            "title": "Status",
            "description": "New issue status"
          },
          "assignedTo": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 255
              },
              {
                "type": "null"
              }
            ],
            "title": "Assignedto",
            "description": "Email of the assignee"
          }
        },
        "type": "object",
        "required": [
          "status"
        ],
        "title": "UpdateIssueRequest",
        "description": "Request body for updating an anomaly issue."
      },
      "ValidationError": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          },
          "input": {
            "title": "Input"
          },
          "ctx": {
            "type": "object",
            "title": "Context"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      },
      "WebhookCreateRequest": {
        "properties": {
          "url": {
            "type": "string",
            "maxLength": 2048,
            "title": "Url",
            "description": "Webhook target URL (must be HTTPS)"
          },
          "events": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "minItems": 1,
            "title": "Events",
            "description": "Event types to subscribe to"
          },
          "description": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 256
              },
              {
                "type": "null"
              }
            ],
            "title": "Description",
            "description": "Optional description"
          }
        },
        "type": "object",
        "required": [
          "url",
          "events"
        ],
        "title": "WebhookCreateRequest"
      },
      "WebhookCreateResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id"
          },
          "url": {
            "type": "string",
            "title": "Url"
          },
          "events": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Events"
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "enabled": {
            "type": "boolean",
            "title": "Enabled"
          },
          "failureCount": {
            "type": "integer",
            "title": "Failurecount"
          },
          "disabledAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Disabledat"
          },
          "createdAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Createdat"
          },
          "updatedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Updatedat"
          },
          "secret": {
            "type": "string",
            "title": "Secret"
          }
        },
        "type": "object",
        "required": [
          "id",
          "url",
          "events",
          "enabled",
          "failureCount",
          "secret"
        ],
        "title": "WebhookCreateResponse",
        "description": "Returned on create/rotate \u2014 includes the secret (shown only once)."
      },
      "WebhookDeliveryResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id"
          },
          "eventType": {
            "type": "string",
            "title": "Eventtype"
          },
          "status": {
            "type": "string",
            "title": "Status"
          },
          "httpStatus": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Httpstatus"
          },
          "attemptCount": {
            "type": "integer",
            "title": "Attemptcount"
          },
          "createdAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Createdat"
          },
          "completedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Completedat"
          }
        },
        "type": "object",
        "required": [
          "id",
          "eventType",
          "status",
          "attemptCount"
        ],
        "title": "WebhookDeliveryResponse"
      },
      "WebhookDetailResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id"
          },
          "url": {
            "type": "string",
            "title": "Url"
          },
          "events": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Events"
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "enabled": {
            "type": "boolean",
            "title": "Enabled"
          },
          "failureCount": {
            "type": "integer",
            "title": "Failurecount"
          },
          "disabledAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Disabledat"
          },
          "createdAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Createdat"
          },
          "updatedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Updatedat"
          },
          "recentDeliveries": {
            "items": {
              "$ref": "#/components/schemas/WebhookDeliveryResponse"
            },
            "type": "array",
            "title": "Recentdeliveries",
            "default": []
          }
        },
        "type": "object",
        "required": [
          "id",
          "url",
          "events",
          "enabled",
          "failureCount"
        ],
        "title": "WebhookDetailResponse",
        "description": "Webhook details with recent delivery history."
      },
      "WebhookEventType": {
        "type": "string",
        "enum": [
          "station.anomaly_detected",
          "station.anomaly_resolved",
          "station.restart_recommended"
        ],
        "title": "WebhookEventType",
        "description": "Event types that can trigger a webhook delivery."
      },
      "WebhookListResponse": {
        "properties": {
          "content": {
            "items": {
              "$ref": "#/components/schemas/WebhookResponse"
            },
            "type": "array",
            "title": "Content"
          },
          "pagination": {
            "$ref": "#/components/schemas/PaginationInfo"
          }
        },
        "type": "object",
        "required": [
          "content",
          "pagination"
        ],
        "title": "WebhookListResponse"
      },
      "WebhookResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id"
          },
          "url": {
            "type": "string",
            "title": "Url"
          },
          "events": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Events"
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "enabled": {
            "type": "boolean",
            "title": "Enabled"
          },
          "failureCount": {
            "type": "integer",
            "title": "Failurecount"
          },
          "disabledAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Disabledat"
          },
          "createdAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Createdat"
          },
          "updatedAt": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Updatedat"
          }
        },
        "type": "object",
        "required": [
          "id",
          "url",
          "events",
          "enabled",
          "failureCount"
        ],
        "title": "WebhookResponse"
      },
      "WebhookUpdateRequest": {
        "properties": {
          "url": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2048
              },
              {
                "type": "null"
              }
            ],
            "title": "Url"
          },
          "events": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array",
                "minItems": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Events"
          },
          "description": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 256
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "enabled": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Enabled"
          }
        },
        "type": "object",
        "title": "WebhookUpdateRequest"
      }
    },
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "SuperTokens session token or API key (sk-obs-... prefix)."
      }
    }
  },
  "tags": [
    {
      "name": "saas:sessions",
      "description": "Submit and browse charging session anomaly analysis."
    },
    {
      "name": "saas:llm",
      "description": "LLM-powered session explanations and Q&A."
    },
    {
      "name": "saas:batches",
      "description": "Batch session upload and processing."
    },
    {
      "name": "saas:stations",
      "description": "Charging stations and SHADE station-level detection."
    },
    {
      "name": "saas:anomalies",
      "description": "Detected anomalies and issue status / assignment."
    },
    {
      "name": "saas:models",
      "description": "ML model management and fine-tuning."
    },
    {
      "name": "saas:statistics",
      "description": "Tenant statistics and dashboards."
    },
    {
      "name": "saas:webhooks",
      "description": "Webhook subscriptions, event types, and signatures."
    },
    {
      "name": "saas:api-keys",
      "description": "API key management."
    },
    {
      "name": "saas:organization",
      "description": "Organization profile and settings."
    },
    {
      "name": "saas:members",
      "description": "Organization members and roles."
    }
  ],
  "servers": [
    {
      "url": "/api/saas/v1",
      "description": "SaaS API v1"
    }
  ],
  "security": [
    {
      "BearerAuth": []
    }
  ]
}
