From b6c8dad707bb52eae4cf308394a3745d6419fda0 Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 16 Apr 2026 11:06:58 +0900 Subject: [PATCH 01/11] chore: automate openapi v3 sync --- .github/workflows/sync-openapi-v3.yml | 52 + README.md | 10 + docs/plans/2026-04-16-openapi-sync-design.md | 76 + docs/plans/2026-04-16-openapi-sync.md | 79 + openapi/openapi-v3.json | 4186 ++++++++++++------ 5 files changed, 3161 insertions(+), 1242 deletions(-) create mode 100644 .github/workflows/sync-openapi-v3.yml create mode 100644 docs/plans/2026-04-16-openapi-sync-design.md create mode 100644 docs/plans/2026-04-16-openapi-sync.md diff --git a/.github/workflows/sync-openapi-v3.yml b/.github/workflows/sync-openapi-v3.yml new file mode 100644 index 0000000..0e4534b --- /dev/null +++ b/.github/workflows/sync-openapi-v3.yml @@ -0,0 +1,52 @@ +name: Sync OpenAPI v3 + +on: + workflow_dispatch: + schedule: + - cron: "0 0 * * 1" + +permissions: + contents: write + +concurrency: + group: sync-openapi-v3 + cancel-in-progress: false + +jobs: + sync: + runs-on: ubuntu-latest + + steps: + - name: Check out main + uses: actions/checkout@v4 + with: + ref: main + + - name: Install jq + run: | + sudo apt-get update + sudo apt-get install -y jq + + - name: Sync v3 OpenAPI snapshot + run: ./scripts/update-openapi-v3.sh + + - name: Detect snapshot changes + id: changes + run: | + if git diff --quiet -- openapi/openapi-v3.json; then + echo "changed=false" >> "$GITHUB_OUTPUT" + else + echo "changed=true" >> "$GITHUB_OUTPUT" + fi + + - name: Commit updated snapshot + if: steps.changes.outputs.changed == 'true' + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add openapi/openapi-v3.json + git commit -m "chore: sync openapi v3 snapshot" + + - name: Push to main + if: steps.changes.outputs.changed == 'true' + run: git push origin HEAD:main diff --git a/README.md b/README.md index a75cc30..6f50bc4 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,16 @@ Run: ./scripts/update-openapi-v3.sh ``` +## Automated spec sync + +GitHub Actions also keeps `openapi/openapi-v3.json` up to date automatically. + +- Weekly schedule: every Monday at 00:00 UTC, which is Monday 09:00 in Korea Standard Time +- Manual trigger: Actions -> `Sync OpenAPI v3` -> `Run workflow` +- Commit behavior: if the extracted v3 snapshot changed, the workflow commits the updated `openapi/openapi-v3.json` directly to `main` + +The workflow is defined in `.github/workflows/sync-openapi-v3.yml` and reuses `scripts/update-openapi-v3.sh` so local and automated sync stay consistent. + ## Local development ### TypeScript diff --git a/docs/plans/2026-04-16-openapi-sync-design.md b/docs/plans/2026-04-16-openapi-sync-design.md new file mode 100644 index 0000000..0c312f8 --- /dev/null +++ b/docs/plans/2026-04-16-openapi-sync-design.md @@ -0,0 +1,76 @@ +# OpenAPI Sync Workflow Design + +**Date:** 2026-04-16 + +## Goal + +Keep `openapi/openapi-v3.json` aligned with `https://patch-api.conalog.com/openapi.json` automatically, with a weekly schedule and a manual trigger, and commit changes directly to `main`. + +## Current Context + +- The repository already has a sync script at `scripts/update-openapi-v3.sh`. +- The script fetches the upstream OpenAPI document, filters `/api/v3/` paths, rewrites the API title, and writes the result to `openapi/openapi-v3.json`. +- There is no existing `.github/workflows` directory, so the automation can be introduced without conflicting with current CI conventions. + +## Recommended Approach + +Use a GitHub Actions workflow that runs on: + +- `schedule` once per week +- `workflow_dispatch` for manual runs + +The workflow should: + +1. Check out `main` +2. Install `jq` +3. Run `scripts/update-openapi-v3.sh` +4. Detect whether `openapi/openapi-v3.json` changed +5. Commit and push to `main` only when there is a real diff + +## Alternatives Considered + +### 1. GitHub Actions direct-to-main sync + +This is the recommended approach. + +- Matches the requested weekly plus manual trigger behavior +- Reuses the existing repository script +- Keeps operational logic close to the repository +- Avoids external scheduling infrastructure + +### 2. GitHub Actions with PR creation + +This is safer for review-heavy repositories, but it does not match the request to commit directly to `main` and adds operational overhead. + +### 3. External scheduler or local cron + +This would work technically, but it increases maintenance cost and moves a repository-owned concern outside GitHub. + +## Behavior Details + +- The scheduled run should happen weekly at a fixed UTC time. +- Manual runs should use the standard Actions "Run workflow" entry. +- The workflow should request `contents: write` so the default `GITHUB_TOKEN` can push to `main`. +- Concurrency should prevent overlapping sync jobs from racing each other. +- If there is no diff after running the sync script, the workflow exits without creating a commit. + +## Error Handling + +- `curl -fsSL` in the existing script already causes the job to fail on fetch errors. +- `set -euo pipefail` in the script ensures bad fetches or bad `jq` processing fail the job. +- A failed workflow should leave the repository unchanged. + +## Verification + +Local verification should cover: + +- Running `scripts/update-openapi-v3.sh` +- Confirming the workflow file is syntactically valid YAML +- Reviewing the generated diff to ensure only intended automation files and docs changed + +## Files To Change + +- Create: `.github/workflows/sync-openapi-v3.yml` +- Modify: `README.md` +- Create: `docs/plans/2026-04-16-openapi-sync.md` + diff --git a/docs/plans/2026-04-16-openapi-sync.md b/docs/plans/2026-04-16-openapi-sync.md new file mode 100644 index 0000000..7193610 --- /dev/null +++ b/docs/plans/2026-04-16-openapi-sync.md @@ -0,0 +1,79 @@ +# OpenAPI Sync Implementation Plan + +> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. + +**Goal:** Add a GitHub Actions workflow that refreshes the local v3 OpenAPI snapshot weekly and on manual trigger, then commits real changes directly to `main`. + +**Architecture:** Reuse the existing shell sync script as the single source of truth for generating `openapi/openapi-v3.json`. Wrap it in a GitHub Actions workflow that checks for diffs, commits only when needed, and documents the automation in the repository README. + +**Tech Stack:** GitHub Actions, Bash, `curl`, `jq`, Git + +--- + +### Task 1: Add the workflow + +**Files:** +- Create: `.github/workflows/sync-openapi-v3.yml` + +**Step 1: Draft workflow behavior** + +Define: +- `schedule` with a weekly cron +- `workflow_dispatch` +- `contents: write` permissions +- checkout, `jq` install, sync script run, diff detection, conditional commit and push + +**Step 2: Validate assumptions locally** + +Run: `scripts/update-openapi-v3.sh` +Expected: local snapshot refresh succeeds without manual edits + +**Step 3: Write minimal workflow** + +Create the YAML so it only automates the existing script and avoids unrelated build or release steps. + +**Step 4: Review for no-op safety** + +Confirm the commit step is gated so no commit is created when there is no diff. + +### Task 2: Document the automation + +**Files:** +- Modify: `README.md` + +**Step 1: Add automation section** + +Document: +- weekly schedule +- manual trigger path +- direct commit behavior + +**Step 2: Keep local workflow intact** + +Retain the existing local script instructions so the workflow and local operation stay aligned. + +### Task 3: Verify and finalize + +**Files:** +- Review: `.github/workflows/sync-openapi-v3.yml` +- Review: `README.md` + +**Step 1: Run the sync script** + +Run: `./scripts/update-openapi-v3.sh` +Expected: command succeeds and writes `openapi/openapi-v3.json` + +**Step 2: Inspect git diff** + +Run: `git diff -- .github/workflows/sync-openapi-v3.yml README.md docs/plans` +Expected: only the workflow, docs, and intentional README changes appear + +**Step 3: Commit** + +Run: +```bash +git add .github/workflows/sync-openapi-v3.yml README.md docs/plans +git commit -m "chore: automate openapi v3 sync" +``` + +Expected: a single commit capturing the workflow and docs diff --git a/openapi/openapi-v3.json b/openapi/openapi-v3.json index c3941ab..46f4efa 100644 --- a/openapi/openapi-v3.json +++ b/openapi/openapi-v3.json @@ -161,6 +161,34 @@ ], "type": "object" }, + "AuthMethodsBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/AuthMethodsBody.json" + ], + "format": "uri", + "readOnly": true, + "type": "string" + }, + "authProviders": { + "description": "List of available OAuth2 authentication providers.", + "items": { + "$ref": "#/components/schemas/AuthProvider" + }, + "type": [ + "array", + "null" + ] + } + }, + "required": [ + "authProviders" + ], + "type": "object" + }, "AuthOutputV3Body": { "additionalProperties": false, "properties": { @@ -229,6 +257,67 @@ ], "type": "object" }, + "AuthProvider": { + "additionalProperties": false, + "properties": { + "authUrl": { + "description": "The fully qualified URL to redirect the user to for authentication with the provider.", + "type": "string" + }, + "codeChallenge": { + "description": "The code challenge string used for PKCE (Proof Key for Code Exchange) to secure the flow.", + "type": "string" + }, + "codeChallengeMethod": { + "description": "The hashing method used for the code challenge (typically 'S256').", + "type": "string" + }, + "name": { + "description": "Unique name identifier for the authentication provider (e.g., 'google', 'github', 'discord').", + "type": "string" + }, + "state": { + "description": "A signed and encrypted state token for CSRF protection and carrying OAuth flow context.", + "type": "string" + } + }, + "required": [ + "name", + "state", + "codeChallenge", + "codeChallengeMethod", + "authUrl" + ], + "type": "object" + }, + "AuthWithOAuth2InputBody": { + "additionalProperties": false, + "properties": { + "code": { + "description": "The authorization code received from the OAuth2 provider after user consent.", + "type": "string" + }, + "codeVerifier": { + "description": "The PKCE code verifier that matches the challenge sent during the initial redirection.", + "type": "string" + }, + "provider": { + "description": "The name of the OAuth2 provider used (e.g., 'google').", + "type": "string" + }, + "redirectUrl": { + "description": "The redirect URL used during the initial authentication request.", + "type": "string" + } + }, + "required": [ + "provider", + "code", + "codeVerifier", + "redirectUrl" + ], + "type": "object" + }, "AuthWithPasswordBody": { "additionalProperties": false, "properties": { @@ -584,1211 +673,1230 @@ "title": "Plant Intraday Metrics", "type": "object" }, - "CreateAccountOutputBody": { + "BodySensorData": { "additionalProperties": false, + "description": "Time-series summary metrics for plant sensors at 5-minute intervals.", "properties": { - "$schema": { - "description": "A URL to the JSON Schema for this object.", - "examples": [ - "https://patch-api.conalog.com/schemas/CreateAccountOutputBody.json" - ], - "format": "uri", - "readOnly": true, - "type": "string" - }, - "email": { - "description": "The email address of the user. Only available for 'manager' and 'admin' account types.", - "examples": [ - "manager@example.com" - ], - "type": "string" - }, - "id": { - "description": "Unique identifier for the user within the system.", - "examples": [ - "user123" - ], - "type": "string" - }, - "metadata": { - "description": "Additional metadata associated with the user account. May include custom fields, preferences, or configuration data. Not available for viewer accounts." - }, - "name": { - "description": "The display name of the user.", - "examples": [ - "John Doe" - ], - "type": "string" + "before": { + "description": "Number of historical intervals included in the response", + "format": "int64", + "type": "integer" }, - "organizations": { - "description": "List of organizations that the user has access to. Each organization represents a separate tenant or business entity within the system.", + "data": { + "description": "Array of time-series data points matching the specified parameters", "items": { - "$ref": "#/components/schemas/OrganizationBody" + "$ref": "#/components/schemas/SensorData" }, "type": [ "array", "null" ] }, - "type": { - "description": "The type of account indicating the user's access level and permissions. Determines available operations and data access.", - "enum": [ - "manager", - "viewer", - "admin" - ], + "date": { + "description": "Target date for the data retrieval", "type": "string" }, - "username": { - "description": "The username of the user. Only available for 'viewer' account types.", - "examples": [ - "viewer_user" - ], - "type": "string" - } - }, - "required": [ - "id", - "type", - "name", - "organizations" - ], - "type": "object" - }, - "CreatePlantInput": { - "additionalProperties": false, - "properties": { - "$schema": { - "description": "A URL to the JSON Schema for this object.", - "examples": [ - "https://patch-api.conalog.com/schemas/CreatePlantInput.json" - ], - "format": "uri", - "readOnly": true, + "interval": { + "description": "Time interval used for data aggregation", "type": "string" }, - "metadata": { - "additionalProperties": {}, - "description": "Additional metadata and configuration details for the plant. May include address, capacity, equipment counts, and custom properties.", - "examples": [ - { - "address": "123 Solar Street, Green City", - "capacity": "100kW", - "inverters": 4, - "panels": 400 - } - ], - "type": "object" + "plant_id": { + "description": "Plant identifier that was queried", + "type": "string" }, - "name": { - "description": "Display name of the solar plant installation.", - "examples": [ - "Green Energy Solar Farm" - ], + "source": { + "description": "Data source type that was queried", "type": "string" }, - "organizationId": { - "description": "Organization ID that owns or manages this plant installation. Must be exactly 15 characters in length.", - "examples": [ - "org123456789012" - ], - "maxLength": 15, - "minLength": 15, - "patternDescription": "alphanum", + "unit": { + "description": "Data aggregation unit that was requested", "type": "string" } }, "required": [ - "name", - "organizationId" + "plant_id", + "unit", + "source", + "date", + "interval", + "data" ], + "title": "Sensor Intraday Metrics", "type": "object" }, - "Create_org_memberRequest": { + "CombinerItem": { "additionalProperties": false, "properties": { - "$schema": { - "description": "A URL to the JSON Schema for this object.", - "examples": [ - "https://patch-api.conalog.com/schemas/Create_org_memberRequest.json" - ], - "format": "uri", - "readOnly": true, + "cancellation_date": { + "description": "Cancellation date value from the combiners asset catalog view.", "type": "string" }, - "email": { - "description": "Email of the user. Required for manager/admin.", + "category": { + "description": "Category value from the combiners asset catalog view.", "type": "string" }, - "metadata": { - "description": "Additional metadata for the user account." + "certification_date": { + "description": "Certification date value from the combiners asset catalog view.", + "type": "string" }, - "name": { - "description": "Display name of the user.", + "certification_target_type": { + "description": "Certification target type value from the combiners asset catalog view.", "type": "string" }, - "type": { - "description": "The type of account for the new member.", - "enum": [ - "manager", - "viewer", - "admin" - ], + "created": { + "description": "Created timestamp value from the combiners asset catalog view.", "type": "string" }, - "username": { - "description": "Username of the user. Required for viewer.", + "depth_mm": { + "description": "Depth value from the combiners asset catalog view.", + "format": "double", + "type": "number" + }, + "equipment_code": { + "description": "Equipment code from the combiners asset catalog view.", "type": "string" - } - }, - "required": [ - "type", - "name" - ], - "type": "object" - }, - "Create_user_accountRequest": { - "additionalProperties": false, - "properties": { - "email": { - "description": "The email address of the user. Only available for 'manager' and 'admin' account types.", - "examples": [ - "manager@example.com" - ], + }, + "has_diode": { + "description": "Diode presence flag from the combiners asset catalog view.", + "format": "int64", + "type": "integer" + }, + "height_fuse_mm": { + "description": "Height fuse value from the combiners asset catalog view.", + "format": "double", + "type": "number" + }, + "height_mm": { + "description": "Height value from the combiners asset catalog view.", + "format": "double", + "type": "number" + }, + "id": { + "description": "PocketBase record ID from the combiners asset catalog view.", "type": "string" }, - "metadata": { - "description": "Additional metadata associated with the user account. May include custom fields, preferences, or configuration data. Not available for viewer accounts." + "importer": { + "description": "Importer value from the combiners asset catalog view.", + "type": "string" }, - "name": { - "description": "The display name of the user.", - "examples": [ - "John Doe" - ], + "importer_address": { + "description": "Importer address value from the combiners asset catalog view.", "type": "string" }, - "password": { - "description": "The user's password for authentication", - "examples": [ - "securepassword123" - ], + "importer_fax_number": { + "description": "Importer fax number value from the combiners asset catalog view.", "type": "string" }, - "type": { - "description": "The type of account indicating the user's access level and permissions. Determines available operations and data access.", - "enum": [ - "manager", - "viewer" - ], + "importer_phone_number": { + "description": "Importer phone number value from the combiners asset catalog view.", "type": "string" }, - "username": { - "description": "The username of the user. Only available for 'viewer' account types.", - "examples": [ - "viewer_user" - ], + "inspection_agency": { + "description": "Inspection agency value from the combiners asset catalog view.", "type": "string" - } - }, + }, + "install_position": { + "description": "Install position value from the combiners asset catalog view.", + "type": "string" + }, + "ip_rating": { + "description": "IP rating value from the combiners asset catalog view.", + "format": "int64", + "type": "integer" + }, + "manufacturer": { + "description": "Manufacturer value from the combiners asset catalog view.", + "type": "string" + }, + "manufacturer_address": { + "description": "Manufacturer address value from the combiners asset catalog view.", + "type": "string" + }, + "manufacturing_country": { + "description": "Manufacturing country value from the combiners asset catalog view.", + "type": "string" + }, + "max_current_a": { + "description": "Maximum current value from the combiners asset catalog view.", + "format": "double", + "type": "number" + }, + "max_current_per_string_a": { + "description": "Maximum current per string value from the combiners asset catalog view.", + "format": "double", + "type": "number" + }, + "max_input_voltage_v": { + "description": "Maximum input voltage value from the combiners asset catalog view.", + "format": "double", + "type": "number" + }, + "max_voltage_v": { + "description": "Maximum voltage value from the combiners asset catalog view.", + "format": "double", + "type": "number" + }, + "model_name": { + "description": "Model name from the combiners asset catalog view.", + "type": "string" + }, + "open_circuit_voltage_v": { + "description": "Open-circuit voltage value from the combiners asset catalog view.", + "format": "double", + "type": "number" + }, + "operation_status": { + "description": "Operation status value from the combiners asset catalog view.", + "type": "string" + }, + "rated_current_a": { + "description": "Rated current value from the combiners asset catalog view.", + "format": "double", + "type": "number" + }, + "rated_output_power_kva": { + "description": "Rated output power value from the combiners asset catalog view.", + "format": "double", + "type": "number" + }, + "string_count": { + "description": "String count value from the combiners asset catalog view.", + "format": "int64", + "type": "integer" + }, + "technical_standard": { + "description": "Technical standard value from the combiners asset catalog view.", + "type": "string" + }, + "updated": { + "description": "Updated timestamp value from the combiners asset catalog view.", + "type": "string" + }, + "weight_kg": { + "description": "Weight value from the combiners asset catalog view.", + "format": "double", + "type": "number" + }, + "width_mm": { + "description": "Width value from the combiners asset catalog view.", + "format": "double", + "type": "number" + } + }, "required": [ - "type", - "password", - "name" + "id" ], "type": "object" }, - "ErrorDetail": { + "Comment": { "additionalProperties": false, "properties": { - "location": { - "description": "Where the error occurred, e.g. 'body.items[3].tags' or 'path.thing-id'", + "created": { "type": "string" }, - "message": { - "description": "Error message text", + "expand": { + "additionalProperties": {}, + "type": "object" + }, + "id": { "type": "string" }, - "value": { - "description": "The value at the given location" + "images": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "isArchive": { + "type": [ + "boolean", + "null" + ] + }, + "isPrivate": { + "type": [ + "boolean", + "null" + ] + }, + "parent": { + "type": [ + "string", + "null" + ] + }, + "plant": { + "type": "string" + }, + "related": { + "type": [ + "string", + "null" + ] + }, + "resolved": { + "type": [ + "string", + "null" + ] + }, + "tag": {}, + "text": { + "type": "string" + }, + "title": { + "type": "string" + }, + "updated": { + "type": "string" + }, + "user": { + "type": "string" } }, + "required": [ + "id", + "plant", + "user", + "title", + "text", + "images", + "tag", + "parent", + "resolved", + "related", + "isPrivate", + "isArchive", + "created", + "updated" + ], "type": "object" }, - "ErrorModel": { + "CreateAccountOutputBody": { "additionalProperties": false, "properties": { "$schema": { "description": "A URL to the JSON Schema for this object.", "examples": [ - "https://patch-api.conalog.com/schemas/ErrorModel.json" + "https://patch-api.conalog.com/schemas/CreateAccountOutputBody.json" ], "format": "uri", "readOnly": true, "type": "string" }, - "detail": { - "description": "A human-readable explanation specific to this occurrence of the problem.", + "email": { + "description": "The email address of the user. Only available for 'manager' and 'admin' account types.", "examples": [ - "Property foo is required but is missing." + "manager@example.com" ], "type": "string" }, - "errors": { - "description": "Optional list of individual error details", - "items": { - "$ref": "#/components/schemas/ErrorDetail" - }, - "type": [ - "array", - "null" - ] - }, - "instance": { - "description": "A URI reference that identifies the specific occurrence of the problem.", + "id": { + "description": "Unique identifier for the user within the system.", "examples": [ - "https://example.com/error-log/abc123" + "user123" ], - "format": "uri", "type": "string" }, - "status": { - "description": "HTTP status code", - "examples": [ - 400 - ], - "format": "int64", - "type": "integer" + "metadata": { + "description": "Additional metadata associated with the user account. May include custom fields, preferences, or configuration data. Not available for viewer accounts." }, - "title": { - "description": "A short, human-readable summary of the problem type. This value should not change between occurrences of the error.", + "name": { + "description": "The display name of the user.", "examples": [ - "Bad Request" + "John Doe" ], "type": "string" }, + "organizations": { + "description": "List of organizations that the user has access to. Each organization represents a separate tenant or business entity within the system.", + "items": { + "$ref": "#/components/schemas/OrganizationBody" + }, + "type": [ + "array", + "null" + ] + }, "type": { - "default": "about:blank", - "description": "A URI reference to human-readable documentation for the error.", + "description": "The type of account indicating the user's access level and permissions. Determines available operations and data access.", + "enum": [ + "manager", + "viewer", + "admin" + ], + "type": "string" + }, + "username": { + "description": "The username of the user. Only available for 'viewer' account types.", "examples": [ - "https://example.com/errors/example" + "viewer_user" ], - "format": "uri", "type": "string" } }, + "required": [ + "id", + "type", + "name", + "organizations" + ], "type": "object" }, - "FileUploadResponse": { + "CreateOrganizationMemberRequestBody": { "additionalProperties": false, "properties": { "$schema": { "description": "A URL to the JSON Schema for this object.", "examples": [ - "https://patch-api.conalog.com/schemas/FileUploadResponse.json" + "https://patch-api.conalog.com/schemas/CreateOrganizationMemberRequestBody.json" ], "format": "uri", "readOnly": true, "type": "string" }, - "created": { - "description": "Timestamp when the file was created", + "email": { + "description": "Email of the user. Required for manager.", "type": "string" }, - "filename": { - "description": "Original filename of the uploaded file", - "type": "string" + "metadata": { + "description": "Additional metadata for the user account." }, - "id": { - "description": "Unique identifier of the uploaded file record", + "name": { + "description": "Display name of the user.", "type": "string" }, - "plant_id": { - "description": "Plant ID associated with the uploaded file", + "type": { + "description": "The type of account for the new member.", + "enum": [ + "manager", + "viewer" + ], "type": "string" }, - "size": { - "description": "File size in bytes", - "format": "int64", - "type": "integer" - }, - "updated": { - "description": "Timestamp when the file was last updated", + "username": { + "description": "Username of the user. Required for viewer.", "type": "string" } }, "required": [ - "id", - "plant_id", - "filename", - "size", - "created", - "updated" + "type", + "name" ], "type": "object" }, - "HealthLevelBody": { + "CreatePlantInput": { "additionalProperties": false, "properties": { "$schema": { "description": "A URL to the JSON Schema for this object.", "examples": [ - "https://patch-api.conalog.com/schemas/HealthLevelBody.json" + "https://patch-api.conalog.com/schemas/CreatePlantInput.json" ], "format": "uri", "readOnly": true, "type": "string" }, - "best": { - "$ref": "#/components/schemas/HealthLevelCategory" + "metadata": { + "additionalProperties": {}, + "description": "Additional metadata and configuration details for the plant. May include address, capacity, equipment counts, and custom properties.", + "examples": [ + { + "address": "123 Solar Street, Green City", + "capacity": "100kW", + "inverters": 4, + "panels": 400 + } + ], + "type": "object" }, - "caution": { - "$ref": "#/components/schemas/HealthLevelCategory" + "name": { + "description": "Display name of the solar plant installation.", + "examples": [ + "Green Energy Solar Farm" + ], + "type": "string" }, - "faulty": { - "$ref": "#/components/schemas/HealthLevelCategory" + "organizationId": { + "description": "Organization ID that owns or manages this plant installation. Must be exactly 15 characters in length.", + "examples": [ + "org123456789012" + ], + "maxLength": 15, + "minLength": 15, + "patternDescription": "alphanum", + "type": "string" } }, "required": [ - "best", - "caution", - "faulty" + "name", + "organizationId" ], "type": "object" }, - "HealthLevelCategory": { + "CreateRequestBody": { "additionalProperties": false, "properties": { - "count": { - "format": "int64", - "type": "integer" - }, - "ids": { + "images": { "items": { "type": "string" }, - "type": "array" - } - }, - "required": [ - "count" - ], - "type": "object" - }, - "InverterDailyData": { - "additionalProperties": false, - "properties": { - "date": { - "description": "Date of the data point in YYYY-MM-DD format", - "type": "string" + "type": [ + "array", + "null" + ] }, - "energy": { - "description": "Total daily energy production (kWh)", - "format": "double", - "type": "number" + "isArchive": { + "type": "boolean" }, - "id": { - "description": "Unique identifier for the inverter", + "isPrivate": { + "type": "boolean" + }, + "parent": { "type": "string" - } - }, - "required": [ - "id", - "date", - "energy" - ], - "type": "object" - }, - "InverterData": { - "additionalProperties": false, - "properties": { - "energy": { - "description": "Energy production for the time interval (kWh)", - "format": "double", - "type": "number" }, - "id": { - "description": "Unique identifier for the inverter", + "related": { "type": "string" }, - "time": { - "description": "Time of the measurement in ISO 8601 format", + "resolved": { "type": "string" }, - "timestamp": { - "description": "Unix timestamp of the measurement", - "format": "double", - "type": "number" + "tag": {}, + "text": { + "type": "string" + }, + "title": { + "type": "string" } }, - "required": [ - "id", - "time", - "energy", - "timestamp" - ], "type": "object" }, - "InverterDataBody": { + "Create_user_accountRequest": { "additionalProperties": false, "properties": { - "asset_id": { - "type": "string" - }, - "asset_type": { - "type": "string" - }, - "data": { - "$ref": "#/components/schemas/InverterLatestData" - }, - "edge_id": { + "email": { + "description": "The email address of the user. Only available for 'manager' and 'admin' account types.", + "examples": [ + "manager@example.com" + ], "type": "string" }, - "map_id": { - "type": "string" + "metadata": { + "description": "Additional metadata associated with the user account. May include custom fields, preferences, or configuration data. Not available for viewer accounts." }, - "map_type": { + "name": { + "description": "The display name of the user.", + "examples": [ + "John Doe" + ], "type": "string" }, - "model": { + "password": { + "description": "The user's password for authentication", + "examples": [ + "securepassword123" + ], "type": "string" }, - "plant_id": { + "type": { + "description": "The type of account indicating the user's access level and permissions. Determines available operations and data access.", + "enum": [ + "manager", + "viewer" + ], "type": "string" }, - "timestamp": { - "format": "date-time", + "username": { + "description": "The username of the user. Only available for 'viewer' account types.", + "examples": [ + "viewer_user" + ], "type": "string" } }, "required": [ - "timestamp", - "asset_id", - "asset_type", - "map_id", - "map_type", - "edge_id", - "plant_id", - "data", - "model" + "type", + "password", + "name" ], "type": "object" }, - "InverterLatestData": { + "DeviceModelStat": { "additionalProperties": false, "properties": { - "daily_energy": { - "format": "double", - "type": [ - "number", - "null" - ] - }, - "logs": { - "items": { - "$ref": "#/components/schemas/InverterLogItem" - }, - "type": [ - "array", - "null" - ] - }, - "state": { - "type": "string" + "count": { + "description": "Active device count for the model name at the end of the requested day.", + "format": "int64", + "type": "integer" }, - "total_energy": { + "installed_capacity_w": { + "description": "Installed capacity in watts attributed to the device model at the end of the requested day.", "format": "double", - "type": [ - "number", - "null" - ] - } - }, - "required": [ - "logs", - "state", - "daily_energy", - "total_energy" - ], - "type": "object" - }, - "InverterLogItem": { - "additionalProperties": false, - "properties": { - "inverterId": { - "type": "string" - }, - "level": { - "type": "string" - }, - "message": { - "$ref": "#/components/schemas/InverterLogMessage" - }, - "plantId": { - "type": "string" - }, - "raw": { - "$ref": "#/components/schemas/InverterLogRawElement" + "type": "number" }, - "timestamp": { - "format": "date-time", + "name": { + "description": "Active device model name at the end of the requested day.", "type": "string" } }, "required": [ - "plantId", - "level", - "inverterId", - "timestamp", - "message", - "raw" + "name", + "count", + "installed_capacity_w" ], "type": "object" }, - "InverterLogMessage": { - "additionalProperties": false, - "properties": { - "ko": { - "type": "string" - } - }, - "type": "object" - }, - "InverterLogRawElement": { + "ErrorDetail": { "additionalProperties": false, "properties": { - "code": { - "description": "WIP", - "type": "string" - }, - "lcd": { - "description": "WIP", + "location": { + "description": "Where the error occurred, e.g. 'body.items[3].tags' or 'path.thing-id'", "type": "string" }, - "status": { + "message": { + "description": "Error message text", "type": "string" }, "value": { - "description": "WIP" + "description": "The value at the given location" } }, - "required": [ - "status" - ], "type": "object" }, - "InverterLogsResponse": { + "ErrorModel": { "additionalProperties": false, "properties": { "$schema": { "description": "A URL to the JSON Schema for this object.", "examples": [ - "https://patch-api.conalog.com/schemas/InverterLogsResponse.json" + "https://patch-api.conalog.com/schemas/ErrorModel.json" ], "format": "uri", "readOnly": true, "type": "string" }, - "items": { + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.", + "examples": [ + "Property foo is required but is missing." + ], + "type": "string" + }, + "errors": { + "description": "Optional list of individual error details", "items": { - "$ref": "#/components/schemas/InverterLogItem" + "$ref": "#/components/schemas/ErrorDetail" }, "type": [ "array", "null" ] }, - "page": { - "format": "int64", - "type": "integer" - }, - "perPage": { - "format": "int64", - "type": "integer" - }, - "totalPages": { - "format": "int64", - "type": "integer" + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem.", + "examples": [ + "https://example.com/error-log/abc123" + ], + "format": "uri", + "type": "string" }, - "totalSizes": { + "status": { + "description": "HTTP status code", + "examples": [ + 400 + ], "format": "int64", "type": "integer" + }, + "title": { + "description": "A short, human-readable summary of the problem type. This value should not change between occurrences of the error.", + "examples": [ + "Bad Request" + ], + "type": "string" + }, + "type": { + "default": "about:blank", + "description": "A URI reference to human-readable documentation for the error.", + "examples": [ + "https://example.com/errors/example" + ], + "format": "uri", + "type": "string" + } + }, + "type": "object" + }, + "ExchangeTokenInputBody": { + "additionalProperties": false, + "properties": { + "code": { + "description": "The short-lived exchange code received from the OAuth redirect.", + "minLength": 1, + "type": "string" } }, "required": [ - "totalPages", - "totalSizes", - "page", - "perPage", - "items" + "code" ], "type": "object" }, - "LatestDeviceBody": { + "FileUploadResponse": { "additionalProperties": false, "properties": { - "asset_id": { - "type": "string" - }, - "asset_type": { - "type": "string" - }, - "edge_id": { + "created": { + "description": "Timestamp when the file was created", "type": "string" }, - "map_id": { + "filename": { + "description": "Original filename of the uploaded file", "type": "string" }, - "map_type": { + "id": { + "description": "Unique identifier of the uploaded file record", "type": "string" }, - "metrics": { - "$ref": "#/components/schemas/LatestDeviceBodyMetricsStruct" - }, "plant_id": { + "description": "Plant ID associated with the uploaded file", "type": "string" }, - "state": { - "additionalProperties": { - "type": "boolean" - }, - "type": "object" + "size": { + "description": "File size in bytes", + "format": "int64", + "type": "integer" }, - "timestamp": { - "format": "date-time", + "updated": { + "description": "Timestamp when the file was last updated", "type": "string" } }, "required": [ - "timestamp", - "asset_id", - "asset_type", - "map_id", - "map_type", + "id", "plant_id", - "edge_id", - "metrics", - "state" + "filename", + "size", + "created", + "updated" ], "type": "object" }, - "LatestDeviceBodyMetricsStruct": { + "HealthLevelBody": { "additionalProperties": false, "properties": { - "i_out": { - "format": "double", - "type": "number" + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/HealthLevelBody.json" + ], + "format": "uri", + "readOnly": true, + "type": "string" }, - "temp": { - "format": "double", - "type": "number" + "best": { + "$ref": "#/components/schemas/HealthLevelCategory" }, - "v_in": { - "format": "double", - "type": "number" + "caution": { + "$ref": "#/components/schemas/HealthLevelCategory" }, - "v_out": { - "format": "double", - "type": "number" + "faulty": { + "$ref": "#/components/schemas/HealthLevelCategory" } }, "required": [ - "i_out", - "v_in", - "v_out", - "temp" + "best", + "caution", + "faulty" ], "type": "object" }, - "OrgAddPermissionInputBody": { + "HealthLevelCategory": { "additionalProperties": false, "properties": { - "$schema": { - "description": "A URL to the JSON Schema for this object.", - "examples": [ - "https://patch-api.conalog.com/schemas/OrgAddPermissionInputBody.json" - ], - "format": "uri", - "readOnly": true, - "type": "string" - }, - "email": { - "description": "User email to grant access for. Used when Role is manager", - "examples": [ - "usr123456789012@conalog.com" - ], - "type": "string" - }, - "plantId": { - "description": "Target plant ID to grant access to.", - "examples": [ - "pln123456789012" - ], - "maxLength": 15, - "minLength": 15, - "type": "string" + "count": { + "format": "int64", + "type": "integer" }, - "type": { - "description": "Account type of user.", - "enum": [ - "viewer", - "manager" - ], - "examples": [ - "viewer" - ], - "type": "string" + "ids": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "count" + ], + "type": "object" + }, + "InternalWarmCacheBody": { + "additionalProperties": false, + "properties": { + "accepted": { + "type": "boolean" }, - "username": { - "description": "User username to grant access for. Used when Role is viewer", - "examples": [ - "usr123456789012" - ], - "type": "string" + "scheduled": { + "format": "int64", + "type": "integer" } }, "required": [ - "plantId", - "type" + "accepted", + "scheduled" ], "type": "object" }, - "OrgAddPermissionOutputBody": { + "InternalWarmTarget": { "additionalProperties": false, "properties": { - "$schema": { - "description": "A URL to the JSON Schema for this object.", - "examples": [ - "https://patch-api.conalog.com/schemas/OrgAddPermissionOutputBody.json" + "date": { + "format": "date", + "type": "string" + }, + "interval": { + "enum": [ + "5m", + "15m", + "1h", + "1d", + "1M", + "1y" ], - "format": "uri", - "readOnly": true, "type": "string" }, - "email": { - "description": "User email to grant access for. Used when Role is manager", - "examples": [ - "usr123456789012@conalog.com" + "kind": { + "enum": [ + "metrics" ], "type": "string" }, "plant_id": { + "maxLength": 15, + "minLength": 15, "type": "string" }, - "type": { - "description": "The type of account indicating the user's access level and permissions. Determines available operations and data access.", + "source": { "enum": [ - "manager", - "viewer" + "device", + "inverter" ], "type": "string" }, - "username": { - "description": "User username to grant access for. Used when Role is viewer", - "examples": [ - "usr123456789012" + "ts": { + "description": "Whether to target the time-series cache path. If true, the request schedules 'ts/...' cache keys via the TS fetcher.", + "type": "boolean" + }, + "unit": { + "enum": [ + "panel", + "inverter", + "string", + "plant" ], "type": "string" } }, "required": [ + "kind", "plant_id", - "type" + "source", + "unit", + "interval", + "date" ], "type": "object" }, - "OrgInfo": { + "InverterDailyData": { "additionalProperties": false, "properties": { - "icon": { - "type": "string" - }, - "id": { - "type": "string" - }, - "logo": { + "date": { + "description": "Date of the data point in YYYY-MM-DD format", "type": "string" }, - "name": { - "type": "string" + "energy": { + "description": "Total daily energy production (kWh)", + "format": "double", + "type": "number" }, - "owner": { + "id": { + "description": "Unique identifier for the inverter", "type": "string" } }, "required": [ "id", - "name" + "date", + "energy" ], "type": "object" }, - "OrganizationBody": { + "InverterData": { "additionalProperties": false, "properties": { - "icon": { - "description": "URL to the organization's icon image. Used for small-scale branding in UI elements.", - "examples": [ - "https://example.org/icon.png" - ], - "type": "string" + "energy": { + "description": "Energy production for the time interval (kWh)", + "format": "double", + "type": "number" }, "id": { - "description": "Unique identifier for the organization within the system.", - "examples": [ - "org123" - ], + "description": "Unique identifier for the inverter", "type": "string" }, - "logo": { - "description": "URL to the organization's logo image. Used for larger branding elements and official documentation.", - "examples": [ - "https://example.org/logo.png" - ], + "time": { + "description": "Time of the measurement in ISO 8601 format", "type": "string" }, - "name": { - "description": "Display name of the organization.", - "examples": [ - "Solar Energy Corp" - ], - "type": "string" + "timestamp": { + "description": "Unix timestamp of the measurement", + "format": "double", + "type": "number" } }, "required": [ "id", - "name" + "time", + "energy", + "timestamp" ], "type": "object" }, - "PanelDailyData": { + "InverterDataBody": { "additionalProperties": false, "properties": { - "energy": { - "description": "Total daily energy production (kWh)", - "format": "double", - "type": "number" + "asset_id": { + "type": "string" }, - "id": { - "description": "Unique identifier for the solar panel", + "asset_type": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/InverterLatestData" + }, + "edge_id": { + "type": "string" + }, + "map_id": { + "type": "string" + }, + "map_type": { + "type": "string" + }, + "model": { + "type": "string" + }, + "plant_id": { + "type": "string" + }, + "timestamp": { + "format": "date-time", "type": "string" } }, "required": [ - "id", - "energy" + "timestamp", + "asset_id", + "asset_type", + "map_id", + "map_type", + "edge_id", + "plant_id", + "data", + "model" ], "type": "object" }, - "PanelData": { + "InverterItem": { "additionalProperties": false, "properties": { - "cumulative_energy": { - "description": "Cumulative energy production up to this point (kWh)", - "format": "double", - "type": "number" + "cancellation_date": { + "description": "Cancellation date value from the inverters asset catalog view.", + "type": "string" }, - "date": { - "description": "Date of the data point in YYYY-MM-DD format", + "certification_date": { + "description": "Certification date value from the inverters asset catalog view.", "type": "string" }, - "energy": { - "description": "Energy production for the time interval (kWh)", + "certification_target_type": { + "description": "Certification target type value from the inverters asset catalog view.", + "type": "string" + }, + "cooling_type": { + "description": "Cooling type value from the inverters asset catalog view.", + "type": "string" + }, + "created": { + "description": "Created timestamp value from the inverters asset catalog view.", + "type": "string" + }, + "depth_mm": { + "description": "Depth value from the inverters asset catalog view.", "format": "double", "type": "number" }, - "i_out": { - "description": "Output current measurement (Amperes)", + "efficiency_percent": { + "description": "Efficiency percent value from the inverters asset catalog view.", "format": "double", "type": "number" }, - "id": { - "description": "Unique identifier for the solar panel", + "equipment_code": { + "description": "Equipment code from the inverters asset catalog view.", "type": "string" }, - "p": { - "description": "Power output measurement (Watts)", + "frequency_hz": { + "description": "Frequency value from the inverters asset catalog view.", "format": "double", "type": "number" }, - "temp": { - "description": "Panel temperature measurement (Celsius)", + "height_fuse_mm": { + "description": "Height fuse value from the inverters asset catalog view.", "format": "double", "type": "number" }, - "timestamp": { - "description": "Unix timestamp of the measurement", - "format": "int64", - "type": "integer" + "height_mm": { + "description": "Height value from the inverters asset catalog view.", + "format": "double", + "type": "number" }, - "v_in": { - "description": "Input voltage measurement (Volts)", + "id": { + "description": "PocketBase record ID from the inverters asset catalog view.", + "type": "string" + }, + "importer": { + "description": "Importer value from the inverters asset catalog view.", + "type": "string" + }, + "importer_address": { + "description": "Importer address value from the inverters asset catalog view.", + "type": "string" + }, + "importer_fax_number": { + "description": "Importer fax number value from the inverters asset catalog view.", + "type": "string" + }, + "importer_phone_number": { + "description": "Importer phone number value from the inverters asset catalog view.", + "type": "string" + }, + "input_voltage_max_v": { + "description": "Maximum input voltage value from the inverters asset catalog view.", "format": "double", "type": "number" }, - "v_out": { - "description": "Output voltage measurement (Volts)", + "input_voltage_min_v": { + "description": "Minimum input voltage value from the inverters asset catalog view.", "format": "double", "type": "number" - } - }, - "required": [ - "id", - "date", - "timestamp", - "energy", - "cumulative_energy", - "i_out", - "p", - "v_in", - "v_out", - "temp" - ], - "type": "object" - }, - "PlantBody": { - "additionalProperties": false, - "properties": { - "$schema": { - "description": "A URL to the JSON Schema for this object.", - "examples": [ - "https://patch-api.conalog.com/schemas/PlantBody.json" - ], - "format": "uri", - "readOnly": true, + }, + "inspection_agency": { + "description": "Inspection agency value from the inverters asset catalog view.", "type": "string" }, - "created": { - "description": "Timestamp when the plant record was created in the system. Uses ISO 8601 format with timezone information.", - "examples": [ - "2025-01-01 00:00:00.000Z" - ], + "installation_type": { + "description": "Installation type value from the inverters asset catalog view.", "type": "string" }, - "id": { - "description": "Unique identifier for the solar plant installation. Must be exactly 15 characters in length.", - "examples": [ - "ask123456789" - ], + "insulation_type": { + "description": "Insulation type value from the inverters asset catalog view.", "type": "string" }, - "images": { - "description": "Array of image URLs associated with the plant. These may include installation photos, aerial views, or equipment images.", - "examples": [ - [ - "https://example.org/plant1.jpg", - "https://example.org/plant2.jpg" - ] - ], - "items": { - "type": "string" - }, - "type": [ - "array", - "null" - ] + "manufacturer": { + "description": "Manufacturer value from the inverters asset catalog view.", + "type": "string" }, - "metadata": { - "additionalProperties": {}, - "description": "Additional metadata and configuration details for the plant. May include address, capacity, equipment counts, and custom properties.", - "examples": [ - { - "address": "123 Solar Street, Green City", - "capacity": "100kW", - "inverters": 4, - "panels": 400 - } - ], - "type": "object" + "manufacturer_address": { + "description": "Manufacturer address value from the inverters asset catalog view.", + "type": "string" }, - "name": { - "description": "Display name of the solar plant installation.", - "examples": [ - "Green Energy Solar Farm" - ], + "manufacturing_country": { + "description": "Manufacturing country value from the inverters asset catalog view.", "type": "string" }, - "organization": { - "description": "Organization identifier that owns or manages this plant installation.", + "model_name": { + "description": "Model name from the inverters asset catalog view.", "type": "string" }, - "organizationData": { - "$ref": "#/components/schemas/OrgInfo", - "description": "Detailed information about the organization associated with this plant, including name, contact details, and branding." + "mppt_voltage_max_v": { + "description": "Maximum MPPT voltage value from the inverters asset catalog view.", + "format": "double", + "type": "number" + }, + "mppt_voltage_min_v": { + "description": "Minimum MPPT voltage value from the inverters asset catalog view.", + "format": "double", + "type": "number" + }, + "mppt_working_max_v": { + "description": "Maximum MPPT working voltage value from the inverters asset catalog view.", + "format": "double", + "type": "number" + }, + "mppt_working_min_v": { + "description": "Minimum MPPT working voltage value from the inverters asset catalog view.", + "format": "double", + "type": "number" + }, + "operation_status": { + "description": "Operation status value from the inverters asset catalog view.", + "type": "string" + }, + "rated_capacity_w": { + "description": "Rated capacity value from the inverters asset catalog view.", + "format": "double", + "type": "number" + }, + "rated_output_voltage_v": { + "description": "Rated output voltage value from the inverters asset catalog view.", + "format": "double", + "type": "number" + }, + "specification": { + "description": "Specification value from the inverters asset catalog view.", + "type": "string" + }, + "technical_standard": { + "description": "Technical standard value from the inverters asset catalog view.", + "type": "string" }, "updated": { - "description": "Timestamp when the plant record was last modified. Uses ISO 8601 format with timezone information.", - "examples": [ - "2025-01-01 00:00:00.000Z" - ], + "description": "Updated timestamp value from the inverters asset catalog view.", "type": "string" + }, + "weight_kg": { + "description": "Weight value from the inverters asset catalog view.", + "format": "double", + "type": "number" + }, + "width_mm": { + "description": "Width value from the inverters asset catalog view.", + "format": "double", + "type": "number" } }, "required": [ - "created", - "id", - "images", - "metadata", - "name", - "organization", - "organizationData", - "updated" + "id" ], "type": "object" }, - "PlantBodyV3": { + "InverterLatestData": { "additionalProperties": false, "properties": { - "$schema": { - "description": "A URL to the JSON Schema for this object.", - "examples": [ - "https://patch-api.conalog.com/schemas/PlantBodyV3.json" - ], - "format": "uri", - "readOnly": true, - "type": "string" + "daily_energy": { + "format": "double", + "type": [ + "number", + "null" + ] }, - "created": { - "description": "Timestamp when the plant record was created in the system. Uses ISO 8601 format with timezone information.", - "examples": [ - "2025-01-01 00:00:00.000Z" - ], - "type": "string" - }, - "id": { - "description": "Unique identifier for the solar plant installation. Must be exactly 15 characters in length.", - "examples": [ - "ask123456789" - ], - "type": "string" - }, - "images": { - "description": "Array of image URLs associated with the plant. These may include installation photos, aerial views, or equipment images.", - "examples": [ - [ - "https://example.org/plant1.jpg", - "https://example.org/plant2.jpg" - ] - ], + "logs": { "items": { - "type": "string" + "$ref": "#/components/schemas/InverterLogItem" }, "type": [ "array", "null" ] }, - "metadata": { - "additionalProperties": {}, - "description": "Additional metadata and configuration details for the plant. May include address, capacity, equipment counts, and custom properties.", - "examples": [ - { - "address": "123 Solar Street, Green City", - "capacity": "100kW", - "inverters": 4, - "panels": 400 - } - ], - "type": "object" - }, - "name": { - "description": "Display name of the solar plant installation.", - "examples": [ - "Green Energy Solar Farm" - ], + "state": { "type": "string" }, - "organization": { - "$ref": "#/components/schemas/OrgInfo", - "description": "Detailed information about the organization that owns or manages this plant, including name, contact details, and branding." - }, - "updated": { - "description": "Timestamp when the plant record was last modified. Uses ISO 8601 format with timezone information.", - "examples": [ - "2025-01-01 00:00:00.000Z" - ], - "type": "string" + "total_energy": { + "format": "double", + "type": [ + "number", + "null" + ] } }, "required": [ - "created", - "id", - "images", - "metadata", - "name", - "organization", - "updated" + "logs", + "state", + "daily_energy", + "total_energy" ], "type": "object" }, - "PlantDailyData": { + "InverterLogItem": { "additionalProperties": false, "properties": { - "date": { - "description": "Date of the data point in YYYY-MM-DD format", + "inverterId": { "type": "string" }, - "energy": { - "description": "Total daily energy production (kWh)", - "format": "double", - "type": "number" + "level": { + "type": "string" }, - "id": { - "description": "Plant identifier (optional for plant-level aggregation)", + "message": { + "$ref": "#/components/schemas/InverterLogMessage" + }, + "plantId": { + "type": "string" + }, + "raw": { + "$ref": "#/components/schemas/InverterLogRawElement" + }, + "timestamp": { + "format": "date-time", "type": "string" } }, "required": [ - "energy", - "date" + "plantId", + "level", + "inverterId", + "timestamp", + "message", + "raw" ], "type": "object" }, - "PlantData": { + "InverterLogMessage": { "additionalProperties": false, "properties": { - "cumulative_energy": { - "description": "Cumulative energy production up to this point (kWh)", - "format": "double", - "type": "number" + "ko": { + "type": "string" + } + }, + "type": "object" + }, + "InverterLogRawElement": { + "additionalProperties": false, + "properties": { + "code": { + "description": "WIP", + "type": "string" }, - "date": { - "description": "Date of the data point in YYYY-MM-DD format", + "lcd": { + "description": "WIP", "type": "string" }, - "energy": { - "description": "Total energy production for the time interval (kWh)", - "format": "double", - "type": "number" + "status": { + "type": "string" }, - "timestamp": { - "description": "Unix timestamp of the measurement", - "format": "int64", - "type": "integer" + "value": { + "description": "WIP" } }, "required": [ - "date", - "energy", - "cumulative_energy", - "timestamp" + "status" ], "type": "object" }, - "PlantsListV3OutputBody": { + "InverterLogsResponse": { "additionalProperties": false, "properties": { "$schema": { "description": "A URL to the JSON Schema for this object.", "examples": [ - "https://patch-api.conalog.com/schemas/PlantsListV3OutputBody.json" + "https://patch-api.conalog.com/schemas/InverterLogsResponse.json" ], "format": "uri", "readOnly": true, "type": "string" }, "items": { - "description": "Array of plant installations for the current page", "items": { - "$ref": "#/components/schemas/PlantBodyV3" + "$ref": "#/components/schemas/InverterLogItem" }, "type": [ "array", @@ -1796,263 +1904,1666 @@ ] }, "page": { - "description": "Current page number (1-based indexing)", "format": "int64", "type": "integer" }, "perPage": { - "description": "Number of items included per page", "format": "int64", "type": "integer" }, - "totalItems": { - "description": "Total number of plant installations available across all pages", + "totalPages": { "format": "int64", "type": "integer" }, - "totalPages": { - "description": "Total number of pages available based on the current page size", + "totalSizes": { "format": "int64", "type": "integer" } }, "required": [ "totalPages", - "totalItems", + "totalSizes", "page", "perPage", "items" ], "type": "object" }, - "RegisterBody": { + "LatestDeviceBody": { "additionalProperties": false, "properties": { "asset_id": { - "description": "Unique identifier for the physical asset to be registered (e.g., device serial number, inverter ID)", - "examples": [ - "DEV001234" - ], "type": "string" }, "asset_type": { - "description": "Classification of the physical asset being registered", - "enum": [ - "device", - "inverter", - "edge" - ], - "examples": [ - "device" - ], + "type": "string" + }, + "edge_id": { "type": "string" }, "map_id": { - "description": "Logical identifier that maps the asset to its position within the plant's system layout", - "examples": [ - "STRING_01_PANEL_05" - ], "type": "string" }, "map_type": { - "description": "Type of logical mapping used to organize the asset within the plant hierarchy", - "enum": [ - "device", - "string", - "edge", - "inverter", - "combiner", - "panel" - ], - "examples": [ - "panel" - ], "type": "string" }, - "registered": { - "description": "Timestamp when the asset should be considered registered. Must be in RFC3339 format.", - "examples": [ - "2024-01-24T00:00:00Z" - ], - "format": "date-time", - "type": "string" + "metrics": { + "$ref": "#/components/schemas/LatestDeviceBodyMetricsStruct" }, - "registered_meta": { - "description": "Additional metadata associated with the registration event (JSON string or custom format)", - "examples": [ - "{\"installer\": \"John Doe\", \"warranty\": \"2029-01-24\"}" - ], + "plant_id": { "type": "string" }, - "tag": { - "description": "Optional descriptive tag or label for the asset (e.g., location, purpose, or custom identifier)", - "examples": [ - "North Array Panel 5" - ], + "state": { + "additionalProperties": { + "type": "boolean" + }, + "type": "object" + }, + "timestamp": { + "format": "date-time", "type": "string" } }, "required": [ + "timestamp", "asset_id", "asset_type", "map_id", "map_type", - "registered" + "plant_id", + "edge_id", + "metrics", + "state" ], "type": "object" }, - "RegistryOutputBody": { + "LatestDeviceBodyMetricsStruct": { "additionalProperties": false, "properties": { - "asset_id": { - "description": "Unique identifier for the physical asset (device, inverter, etc.)", - "type": "string" + "i_out": { + "format": "double", + "type": "number" }, - "asset_type": { - "description": "Type classification of the asset", - "enum": [ - "device", - "inverter", - "edge" - ], - "type": "string" + "temp": { + "format": "double", + "type": "number" }, - "map_id": { - "description": "Logical mapping identifier within the plant's system layout", - "type": "string" + "v_in": { + "format": "double", + "type": "number" }, - "map_type": { - "description": "Type of logical mapping used for the asset", - "enum": [ - "device", - "string", - "edge", - "inverter", - "combiner", - "panel" + "v_out": { + "format": "double", + "type": "number" + } + }, + "required": [ + "i_out", + "v_in", + "v_out", + "temp" + ], + "type": "object" + }, + "ListOutputCombinerItemBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/ListOutputCombinerItemBody.json" ], + "format": "uri", + "readOnly": true, "type": "string" }, - "registered": { - "description": "Timestamp when the asset was registered in RFC3339 format", + "items": { + "description": "Model info rows returned from the asset catalog view.", + "items": { + "$ref": "#/components/schemas/CombinerItem" + }, + "type": [ + "array", + "null" + ] + } + }, + "required": [ + "items" + ], + "type": "object" + }, + "ListOutputInverterItemBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/ListOutputInverterItemBody.json" + ], + "format": "uri", + "readOnly": true, "type": "string" }, - "tag": { + "items": { + "description": "Model info rows returned from the asset catalog view.", + "items": { + "$ref": "#/components/schemas/InverterItem" + }, + "type": [ + "array", + "null" + ] + } + }, + "required": [ + "items" + ], + "type": "object" + }, + "ListOutputModuleItemBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/ListOutputModuleItemBody.json" + ], + "format": "uri", + "readOnly": true, + "type": "string" + }, + "items": { + "description": "Model info rows returned from the asset catalog view.", + "items": { + "$ref": "#/components/schemas/ModuleItem" + }, + "type": [ + "array", + "null" + ] + } + }, + "required": [ + "items" + ], + "type": "object" + }, + "ModuleItem": { + "additionalProperties": false, + "properties": { + "cancellation_date": { + "description": "Cancellation date value from the modules asset catalog view.", + "type": "string" + }, + "cell_specification": { "additionalProperties": {}, - "description": "Additional metadata and tags associated with the asset registration", + "description": "Cell specification object from the modules asset catalog view.", "type": "object" }, - "unregistered": { - "description": "Timestamp when the asset was unregistered in RFC3339 format (empty if still registered)", + "certification_date": { + "description": "Certification date value from the modules asset catalog view.", + "type": "string" + }, + "created": { + "description": "Created timestamp value from the modules asset catalog view.", + "type": "string" + }, + "equipment_code": { + "description": "Equipment code from the modules asset catalog view.", + "type": "string" + }, + "id": { + "description": "PocketBase record ID from the modules asset catalog view.", + "type": "string" + }, + "imax_a": { + "description": "Maximum current value from the modules asset catalog view.", + "format": "double", + "type": "number" + }, + "importer": { + "description": "Importer value from the modules asset catalog view.", + "type": "string" + }, + "importer_address": { + "description": "Importer address value from the modules asset catalog view.", + "type": "string" + }, + "importer_fax_number": { + "description": "Importer fax number value from the modules asset catalog view.", + "type": "string" + }, + "importer_phone_number": { + "description": "Importer phone number value from the modules asset catalog view.", + "type": "string" + }, + "inspection_agency": { + "description": "Inspection agency value from the modules asset catalog view.", + "type": "string" + }, + "isc_a": { + "description": "Short-circuit current value from the modules asset catalog view.", + "format": "double", + "type": "number" + }, + "length_mm": { + "description": "Length value from the modules asset catalog view.", + "format": "double", + "type": "number" + }, + "manufacturer": { + "description": "Manufacturer value from the modules asset catalog view.", + "type": "string" + }, + "manufacturer_address": { + "description": "Manufacturer address value from the modules asset catalog view.", + "type": "string" + }, + "manufacturing_country": { + "description": "Manufacturing country value from the modules asset catalog view.", "type": "string" + }, + "model_name": { + "description": "Model name from the modules asset catalog view.", + "type": "string" + }, + "pmax_w": { + "description": "Maximum power value from the modules asset catalog view.", + "format": "double", + "type": "number" + }, + "rated_efficiency": { + "description": "Rated efficiency value from the modules asset catalog view.", + "format": "double", + "type": "number" + }, + "technical_standard": { + "description": "Technical standard value from the modules asset catalog view.", + "type": "string" + }, + "thickness_mm": { + "description": "Thickness value from the modules asset catalog view.", + "format": "double", + "type": "number" + }, + "updated": { + "description": "Updated timestamp value from the modules asset catalog view.", + "type": "string" + }, + "vmax_v": { + "description": "Voltage at maximum power value from the modules asset catalog view.", + "format": "double", + "type": "number" + }, + "voc_v": { + "description": "Open-circuit voltage value from the modules asset catalog view.", + "format": "double", + "type": "number" + }, + "vsm_v": { + "description": "Maximum system voltage value from the modules asset catalog view.", + "format": "double", + "type": "number" + }, + "weight_kg": { + "description": "Weight value from the modules asset catalog view.", + "format": "double", + "type": "number" + }, + "width_mm": { + "description": "Width value from the modules asset catalog view.", + "format": "double", + "type": "number" } }, "required": [ - "asset_id", - "asset_type", - "map_id", - "map_type", - "registered", - "tag", - "unregistered" + "id" ], "type": "object" }, - "UnregisterBody": { + "OrgAddPermissionInputBody": { "additionalProperties": false, "properties": { - "asset_id": { - "description": "Unique identifier for the physical asset to be unregistered (must match the originally registered asset ID)", + "$schema": { + "description": "A URL to the JSON Schema for this object.", "examples": [ - "DEV001234" + "https://patch-api.conalog.com/schemas/OrgAddPermissionInputBody.json" ], + "format": "uri", + "readOnly": true, "type": "string" }, - "asset_type": { - "description": "Classification of the physical asset being unregistered (must match the originally registered asset type)", - "enum": [ - "device", - "inverter", - "edge" - ], + "email": { + "description": "User email to grant access for. Used when Role is manager", "examples": [ - "device" + "usr123456789012@conalog.com" ], "type": "string" }, - "map_id": { - "description": "Logical identifier that maps the asset within the plant's system layout (must match the originally registered map ID)", + "plantId": { + "description": "Target plant ID to grant access to.", "examples": [ - "STRING_01_PANEL_05" + "pln123456789012" ], + "maxLength": 15, + "minLength": 15, "type": "string" }, - "map_type": { - "description": "Type of logical mapping used for the asset (must match the originally registered map type)", + "type": { + "description": "Account type of user.", "enum": [ - "device", - "string", - "edge", - "inverter", - "combiner", - "panel" + "viewer", + "manager" ], "examples": [ - "panel" + "viewer" ], "type": "string" }, - "tag": { - "description": "Optional descriptive tag or label for the asset (should match the originally registered tag if applicable)", + "username": { + "description": "User username to grant access for. Used when Role is viewer", "examples": [ - "North Array Panel 5" + "usr123456789012" + ], + "type": "string" + } + }, + "required": [ + "plantId", + "type" + ], + "type": "object" + }, + "OrgAddPermissionOutputBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/OrgAddPermissionOutputBody.json" + ], + "format": "uri", + "readOnly": true, + "type": "string" + }, + "email": { + "description": "User email to grant access for. Used when Role is manager", + "examples": [ + "usr123456789012@conalog.com" + ], + "type": "string" + }, + "plant_id": { + "type": "string" + }, + "type": { + "description": "The type of account indicating the user's access level and permissions. Determines available operations and data access.", + "enum": [ + "manager", + "viewer" ], "type": "string" }, - "unregistered": { - "description": "Timestamp when the asset should be considered unregistered. Must be in RFC3339 format and should be after the original registration date.", - "examples": [ - "2024-01-24T00:00:00Z" - ], - "format": "date-time", - "type": "string" + "username": { + "description": "User username to grant access for. Used when Role is viewer", + "examples": [ + "usr123456789012" + ], + "type": "string" + } + }, + "required": [ + "plant_id", + "type" + ], + "type": "object" + }, + "OrgInfo": { + "additionalProperties": false, + "properties": { + "icon": { + "type": "string" + }, + "id": { + "type": "string" + }, + "logo": { + "type": "string" + }, + "name": { + "type": "string" + }, + "owner": { + "type": "string" + }, + "updated": { + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + }, + "OrganizationBody": { + "additionalProperties": false, + "properties": { + "icon": { + "description": "URL to the organization's icon image. Used for small-scale branding in UI elements.", + "examples": [ + "https://example.org/icon.png" + ], + "type": "string" + }, + "id": { + "description": "Unique identifier for the organization within the system.", + "examples": [ + "org123" + ], + "type": "string" + }, + "logo": { + "description": "URL to the organization's logo image. Used for larger branding elements and official documentation.", + "examples": [ + "https://example.org/logo.png" + ], + "type": "string" + }, + "name": { + "description": "Display name of the organization.", + "examples": [ + "Solar Energy Corp" + ], + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + }, + "PanelDailyData": { + "additionalProperties": false, + "properties": { + "energy": { + "description": "Total daily energy production (kWh)", + "format": "double", + "type": "number" + }, + "id": { + "description": "Unique identifier for the solar panel", + "type": "string" + } + }, + "required": [ + "id", + "energy" + ], + "type": "object" + }, + "PanelData": { + "additionalProperties": false, + "properties": { + "cumulative_energy": { + "description": "Cumulative energy production up to this point (kWh)", + "format": "double", + "type": "number" + }, + "date": { + "description": "Date of the data point in YYYY-MM-DD format", + "type": "string" + }, + "energy": { + "description": "Energy production for the time interval (kWh)", + "format": "double", + "type": "number" + }, + "i_out": { + "description": "Output current measurement (Amperes)", + "format": "double", + "type": "number" + }, + "id": { + "description": "Unique identifier for the solar panel", + "type": "string" + }, + "p": { + "description": "Power output measurement (Watts)", + "format": "double", + "type": "number" + }, + "temp": { + "description": "Panel temperature measurement (Celsius)", + "format": "double", + "type": "number" + }, + "timestamp": { + "description": "Unix timestamp of the measurement", + "format": "int64", + "type": "integer" + }, + "v_in": { + "description": "Input voltage measurement (Volts)", + "format": "double", + "type": "number" + }, + "v_out": { + "description": "Output voltage measurement (Volts)", + "format": "double", + "type": "number" + } + }, + "required": [ + "id", + "date", + "timestamp", + "energy", + "cumulative_energy", + "i_out", + "p", + "v_in", + "v_out", + "temp" + ], + "type": "object" + }, + "PlantBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/PlantBody.json" + ], + "format": "uri", + "readOnly": true, + "type": "string" + }, + "created": { + "description": "Timestamp when the plant record was created in the system. Uses ISO 8601 format with timezone information.", + "examples": [ + "2025-01-01 00:00:00.000Z" + ], + "type": "string" + }, + "id": { + "description": "Unique identifier for the solar plant installation. Must be exactly 15 characters in length.", + "examples": [ + "ask123456789" + ], + "type": "string" + }, + "images": { + "description": "Array of image URLs associated with the plant. These may include installation photos, aerial views, or equipment images.", + "examples": [ + [ + "https://example.org/plant1.jpg", + "https://example.org/plant2.jpg" + ] + ], + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "metadata": { + "additionalProperties": {}, + "description": "Additional metadata and configuration details for the plant. May include address, capacity, equipment counts, and custom properties.", + "examples": [ + { + "address": "123 Solar Street, Green City", + "capacity": "100kW", + "inverters": 4, + "panels": 400 + } + ], + "type": "object" + }, + "name": { + "description": "Display name of the solar plant installation.", + "examples": [ + "Green Energy Solar Farm" + ], + "type": "string" + }, + "organization": { + "description": "Organization identifier that owns or manages this plant installation.", + "type": "string" + }, + "organizationData": { + "$ref": "#/components/schemas/OrgInfo", + "description": "Detailed information about the organization associated with this plant, including name, contact details, and branding." + }, + "refPlant": { + "description": "Referenced physical plant ID when this plant is a virtual or derived plant.", + "type": "string" + }, + "updated": { + "description": "Timestamp when the plant record was last modified. Uses ISO 8601 format with timezone information.", + "examples": [ + "2025-01-01 00:00:00.000Z" + ], + "type": "string" + } + }, + "required": [ + "created", + "id", + "images", + "metadata", + "name", + "organization", + "organizationData", + "updated" + ], + "type": "object" + }, + "PlantBodyV3": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/PlantBodyV3.json" + ], + "format": "uri", + "readOnly": true, + "type": "string" + }, + "created": { + "description": "Timestamp when the plant record was created in the system. Uses ISO 8601 format with timezone information.", + "examples": [ + "2025-01-01 00:00:00.000Z" + ], + "type": "string" + }, + "id": { + "description": "Unique identifier for the solar plant installation. Must be exactly 15 characters in length.", + "examples": [ + "ask123456789" + ], + "type": "string" + }, + "images": { + "description": "Array of image URLs associated with the plant. These may include installation photos, aerial views, or equipment images.", + "examples": [ + [ + "https://example.org/plant1.jpg", + "https://example.org/plant2.jpg" + ] + ], + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "metadata": { + "additionalProperties": {}, + "description": "Additional metadata and configuration details for the plant. May include address, capacity, equipment counts, and custom properties.", + "examples": [ + { + "address": "123 Solar Street, Green City", + "capacity": "100kW", + "inverters": 4, + "panels": 400 + } + ], + "type": "object" + }, + "name": { + "description": "Display name of the solar plant installation.", + "examples": [ + "Green Energy Solar Farm" + ], + "type": "string" + }, + "organization": { + "$ref": "#/components/schemas/OrgInfo", + "description": "Detailed information about the organization that owns or manages this plant, including name, contact details, and branding." + }, + "refPlant": { + "description": "Referenced physical plant ID when this plant is a virtual or derived plant.", + "type": "string" + }, + "updated": { + "description": "Timestamp when the plant record was last modified. Uses ISO 8601 format with timezone information.", + "examples": [ + "2025-01-01 00:00:00.000Z" + ], + "type": "string" + } + }, + "required": [ + "created", + "id", + "images", + "metadata", + "name", + "organization", + "updated" + ], + "type": "object" + }, + "PlantDailyData": { + "additionalProperties": false, + "properties": { + "date": { + "description": "Date of the data point in YYYY-MM-DD format", + "type": "string" + }, + "energy": { + "description": "Total daily energy production (kWh)", + "format": "double", + "type": "number" + }, + "id": { + "description": "Plant identifier (optional for plant-level aggregation)", + "type": "string" + } + }, + "required": [ + "energy", + "date" + ], + "type": "object" + }, + "PlantData": { + "additionalProperties": false, + "properties": { + "cumulative_energy": { + "description": "Cumulative energy production up to this point (kWh)", + "format": "double", + "type": "number" + }, + "date": { + "description": "Date of the data point in YYYY-MM-DD format", + "type": "string" + }, + "energy": { + "description": "Total energy production for the time interval (kWh)", + "format": "double", + "type": "number" + }, + "timestamp": { + "description": "Unix timestamp of the measurement", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "date", + "energy", + "cumulative_energy", + "timestamp" + ], + "type": "object" + }, + "PlantsListV3OutputBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/PlantsListV3OutputBody.json" + ], + "format": "uri", + "readOnly": true, + "type": "string" + }, + "items": { + "description": "Array of plant installations for the current page", + "items": { + "$ref": "#/components/schemas/PlantBodyV3" + }, + "type": [ + "array", + "null" + ] + }, + "page": { + "description": "Current page number (1-based indexing)", + "format": "int64", + "type": "integer" + }, + "perPage": { + "description": "Number of items included per page", + "format": "int64", + "type": "integer" + }, + "totalItems": { + "description": "Total number of plant installations available across all pages", + "format": "int64", + "type": "integer" + }, + "totalPages": { + "description": "Total number of pages available based on the current page size", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "totalPages", + "totalItems", + "page", + "perPage", + "items" + ], + "type": "object" + }, + "RegisterBody": { + "additionalProperties": false, + "properties": { + "asset_id": { + "description": "Unique identifier for the physical asset to be registered (e.g., device serial number, inverter ID)", + "examples": [ + "DEV001234" + ], + "type": "string" + }, + "asset_type": { + "description": "Classification of the physical asset being registered", + "enum": [ + "device", + "inverter", + "edge" + ], + "examples": [ + "device" + ], + "type": "string" + }, + "map_id": { + "description": "Logical identifier that maps the asset to its position within the plant's system layout", + "examples": [ + "STRING_01_PANEL_05" + ], + "type": "string" + }, + "map_type": { + "description": "Type of logical mapping used to organize the asset within the plant hierarchy", + "enum": [ + "device", + "string", + "edge", + "inverter", + "combiner", + "panel" + ], + "examples": [ + "panel" + ], + "type": "string" + }, + "registered": { + "description": "Timestamp when the asset should be considered registered. Must be in RFC3339 format.", + "examples": [ + "2024-01-24T00:00:00Z" + ], + "format": "date-time", + "type": "string" + }, + "registered_meta": { + "description": "Additional metadata associated with the registration event (JSON string or custom format)", + "examples": [ + "{\"installer\": \"John Doe\", \"warranty\": \"2029-01-24\"}" + ], + "type": "string" + }, + "tag": { + "description": "Optional descriptive tag or label for the asset (e.g., location, purpose, or custom identifier)", + "examples": [ + "North Array Panel 5" + ], + "type": "string" + } + }, + "required": [ + "asset_id", + "asset_type", + "map_id", + "map_type", + "registered" + ], + "type": "object" + }, + "RegistryOutputBody": { + "additionalProperties": false, + "properties": { + "asset_id": { + "description": "Unique identifier for the physical asset (device, inverter, etc.)", + "type": "string" + }, + "asset_model": { + "additionalProperties": {}, + "description": "Asset model information", + "type": "object" + }, + "asset_type": { + "description": "Type classification of the asset", + "enum": [ + "device", + "inverter", + "edge" + ], + "type": "string" + }, + "map_id": { + "description": "Logical mapping identifier within the plant's system layout", + "type": "string" + }, + "map_type": { + "description": "Type of logical mapping used for the asset", + "enum": [ + "device", + "string", + "edge", + "inverter", + "combiner", + "panel" + ], + "type": "string" + }, + "registered": { + "description": "Timestamp when the asset was registered in RFC3339 format", + "type": "string" + }, + "tag": { + "additionalProperties": {}, + "description": "Additional metadata and tags associated with the asset registration", + "type": "object" + }, + "unregistered": { + "description": "Timestamp when the asset was unregistered in RFC3339 format (empty if still registered)", + "type": "string" + } + }, + "required": [ + "asset_id", + "asset_type", + "map_id", + "map_type", + "asset_model", + "registered", + "tag", + "unregistered" + ], + "type": "object" + }, + "Report": { + "additionalProperties": false, + "properties": { + "created": { + "type": "string" + }, + "description": { + "type": "string" + }, + "end": { + "type": "string" + }, + "expand": { + "additionalProperties": {}, + "type": "object" + }, + "id": { + "type": "string" + }, + "organization": { + "type": "string" + }, + "plants": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "start": { + "type": "string" + }, + "title": { + "type": "string" + }, + "updated": { + "type": "string" + } + }, + "required": [ + "id", + "organization", + "title" + ], + "type": "object" + }, + "SensorData": { + "additionalProperties": false, + "properties": { + "date": { + "description": "Date of the data point in YYYY-MM-DD format", + "type": "string" + }, + "id": { + "description": "Unique identifier for the sensor", + "type": "string" + }, + "max": { + "description": "Maximum measured value for the interval", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "mean": { + "description": "Mean measured value for the interval", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "median": { + "description": "Median measured value for the interval", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "min": { + "description": "Minimum measured value for the interval", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "timestamp": { + "description": "Unix timestamp of the measurement", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "id", + "date", + "timestamp", + "min", + "max", + "mean", + "median" + ], + "type": "object" + }, + "StatModelCount": { + "additionalProperties": false, + "properties": { + "count": { + "description": "Active row count for the model name at the timestamp.", + "format": "int64", + "type": "integer" + }, + "name": { + "description": "Model name for the active panel or panel_group rows at the timestamp.", + "type": "string" + } + }, + "required": [ + "name", + "count" + ], + "type": "object" + }, + "StatPoint": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/StatPoint.json" + ], + "format": "uri", + "readOnly": true, + "type": "string" + }, + "device_models": { + "description": "Active device model stats at the end of the requested day.", + "items": { + "$ref": "#/components/schemas/DeviceModelStat" + }, + "type": [ + "array", + "null" + ] + }, + "installed_capacity_w": { + "description": "Installed capacity in watts at the end of the requested day.", + "format": "double", + "type": "number" + }, + "module_models": { + "description": "Active panel and panel_group model counts at the end of the requested day.", + "items": { + "$ref": "#/components/schemas/StatModelCount" + }, + "type": [ + "array", + "null" + ] + }, + "timestamp": { + "description": "UTC timestamp for the end of the requested KST day.", + "type": "string" + } + }, + "required": [ + "timestamp", + "installed_capacity_w", + "module_models", + "device_models" + ], + "type": "object" + }, + "UnregisterBody": { + "additionalProperties": false, + "properties": { + "asset_id": { + "description": "Unique identifier for the physical asset to be unregistered (must match the originally registered asset ID)", + "examples": [ + "DEV001234" + ], + "type": "string" + }, + "asset_type": { + "description": "Classification of the physical asset being unregistered (must match the originally registered asset type)", + "enum": [ + "device", + "inverter", + "edge" + ], + "examples": [ + "device" + ], + "type": "string" + }, + "map_id": { + "description": "Logical identifier that maps the asset within the plant's system layout (must match the originally registered map ID)", + "examples": [ + "STRING_01_PANEL_05" + ], + "type": "string" + }, + "map_type": { + "description": "Type of logical mapping used for the asset (must match the originally registered map type)", + "enum": [ + "device", + "string", + "edge", + "inverter", + "combiner", + "panel" + ], + "examples": [ + "panel" + ], + "type": "string" + }, + "tag": { + "description": "Optional descriptive tag or label for the asset (should match the originally registered tag if applicable)", + "examples": [ + "North Array Panel 5" + ], + "type": "string" + }, + "unregistered": { + "description": "Timestamp when the asset should be considered unregistered. Must be in RFC3339 format and should be after the original registration date.", + "examples": [ + "2024-01-24T00:00:00Z" + ], + "format": "date-time", + "type": "string" + }, + "unregistered_meta": { + "description": "Additional metadata associated with the unregistration event (JSON string or custom format)", + "examples": [ + "{\"reason\": \"Equipment replacement\", \"technician\": \"Jane Smith\"}" + ], + "type": "string" + } + }, + "required": [ + "asset_id", + "asset_type", + "map_id", + "map_type", + "unregistered" + ], + "type": "object" + }, + "UpdateRequestBody": { + "additionalProperties": false, + "properties": { + "images": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "isArchive": { + "type": "boolean" + }, + "isPrivate": { + "type": "boolean" + }, + "parent": { + "type": "string" + }, + "related": { + "type": "string" + }, + "resolved": { + "type": "string" + }, + "tag": {}, + "text": { + "type": "string" + }, + "title": { + "type": "string" + } + }, + "type": "object" + } + }, + "securitySchemes": { + "bearer": { + "bearerFormat": "JWT", + "scheme": "bearer", + "type": "http" + } + } + }, + "info": { + "title": "patch-client (v3)", + "version": "3.0.0" + }, + "openapi": "3.1.0", + "paths": { + "/api/v3/account/": { + "get": { + "description": "Retrieves comprehensive account information for the authenticated user. Includes account type, email/username, name, metadata, and associated organizations.", + "operationId": "get_account_info", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "enum": [ + "viewer", + "manager", + "admin" + ], + "type": "string" + } + }, + { + "description": "Succeeds if the server's resource matches one of the passed values.", + "in": "header", + "name": "If-Match", + "schema": { + "description": "Succeeds if the server's resource matches one of the passed values.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "in": "header", + "name": "If-None-Match", + "schema": { + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "Succeeds if the server's resource date is more recent than the passed date.", + "in": "header", + "name": "If-Modified-Since", + "schema": { + "description": "Succeeds if the server's resource date is more recent than the passed date.", + "format": "date-time-http", + "type": "string" + } + }, + { + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "in": "header", + "name": "If-Unmodified-Since", + "schema": { + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "format": "date-time-http", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountOutputBody", + "description": "Response body containing complete account information" + } + } + }, + "description": "OK", + "headers": { + "ETag": { + "schema": { + "description": "Weak entity tag for conditional requests.", + "type": "string" + } + } + } + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Get Account Information", + "tags": [ + "v3/account" + ] + } + }, + "/api/v3/account/auth-methods": { + "get": { + "description": "Retrieves a list of available OAuth2 authentication providers (e.g., Google, GitHub). The authUrl for each provider is proxied through patch-api with a signed state for CSRF protection.", + "operationId": "list_oauth_methods", + "parameters": [ + { + "description": "Optional OAuth2 provider name to filter for.", + "explode": false, + "in": "query", + "name": "provider", + "schema": { + "description": "Optional OAuth2 provider name to filter for.", + "examples": [ + "google" + ], + "type": "string" + } + }, + { + "description": "Optional client redirect URL for deep linking (e.g., myscheme://callback). After OAuth2 completes, the user is redirected to this URL with a short-lived exchange code.", + "explode": false, + "in": "query", + "name": "redirect_url", + "schema": { + "description": "Optional client redirect URL for deep linking (e.g., myscheme://callback). After OAuth2 completes, the user is redirected to this URL with a short-lived exchange code.", + "examples": [ + "myscheme://callback" + ], + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthMethodsBody" + } + } + }, + "description": "OK" + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [], + "summary": "List OAuth2 Auth Methods", + "tags": [ + "v3/account" + ] + } + }, + "/api/v3/account/auth-with-password": { + "post": { + "description": "Authenticates users using either email (for managers) or username (for viewers) with password. The response includes an authentication token for subsequent API calls. This endpoint does not require the Authorization header.", + "operationId": "authenticate_user", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthWithPasswordBody", + "description": "Request body containing authentication credentials and account type" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthOutputV3Body", + "description": "Response body containing complete account information and authentication token" + } + } + }, + "description": "OK" + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [], + "summary": "Authentication", + "tags": [ + "v3/account" + ] + } + }, + "/api/v3/account/login-with-oauth2": { + "get": { + "description": "Starts an OAuth2 login flow by redirecting the user to the provider's authentication URL. Requires a 'provider' query parameter (e.g., 'google').", + "operationId": "start_oauth_login", + "parameters": [ + { + "description": "The OAuth2 provider name to log in with (e.g., 'google').", + "explode": false, + "in": "query", + "name": "provider", + "required": true, + "schema": { + "description": "The OAuth2 provider name to log in with (e.g., 'google').", + "examples": [ + "google" + ], + "type": "string" + } + }, + { + "description": "Optional client redirect URL for deep linking (e.g., myscheme://callback). After OAuth2 completes, the user is redirected to this URL with a short-lived exchange code.", + "explode": false, + "in": "query", + "name": "redirect_url", + "schema": { + "description": "Optional client redirect URL for deep linking (e.g., myscheme://callback). After OAuth2 completes, the user is redirected to this URL with a short-lived exchange code.", + "examples": [ + "myscheme://callback" + ], + "type": "string" + } + } + ], + "responses": { + "302": { + "description": "Found", + "headers": { + "Location": { + "schema": { + "description": "Redirect to this URL for authentication.", + "type": "string" + } + } + } + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [], + "summary": "OAuth2 Login Starter", + "tags": [ + "v3/account" + ] + } + }, + "/api/v3/account/refresh-token": { + "post": { + "description": "Refreshes the authentication token for the user. Requires a valid existing token in the Authorization header. Returns a new JWT token for subsequent API calls.", + "operationId": "refresh_user_token", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } }, - "unregistered_meta": { - "description": "Additional metadata associated with the unregistration event (JSON string or custom format)", - "examples": [ - "{\"reason\": \"Equipment replacement\", \"technician\": \"Jane Smith\"}" - ], - "type": "string" + { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "enum": [ + "viewer", + "manager", + "admin" + ], + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthBody", + "description": "Response body containing authentication details" + } + } + }, + "description": "OK" + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" } }, - "required": [ - "asset_id", - "asset_type", - "map_id", - "map_type", - "unregistered" + "security": [ + { + "bearer": [] + } ], - "type": "object" + "summary": "Refresh Authentication Token", + "tags": [ + "v3/account" + ] } }, - "securitySchemes": { - "bearer": { - "bearerFormat": "JWT", - "scheme": "bearer", - "type": "http" - } - } - }, - "info": { - "title": "patch-client (v3)", - "version": "3.0.0" - }, - "openapi": "3.1.0", - "paths": { - "/api/v3/account/": { + "/api/v3/model-info/combiners": { "get": { - "description": "Retrieves comprehensive account information for the authenticated user. Includes account type, email/username, name, metadata, and associated organizations.", - "operationId": "get_account_info", + "description": "Lists combiner model information from the asset catalog.", + "operationId": "list_combiner_model_info", "parameters": [ { "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", @@ -2085,8 +3596,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AccountOutputBody", - "description": "Response body containing complete account information" + "$ref": "#/components/schemas/ListOutputCombinerItemBody" } } }, @@ -2108,34 +3618,49 @@ "bearer": [] } ], - "summary": "Get Account Information", + "summary": "List Combiner Model Info", "tags": [ - "v3/account" + "v3/model-info" ] } }, - "/api/v3/account/auth-with-password": { - "post": { - "description": "Authenticates users using either email (for managers) or username (for viewers) with password. The response includes an authentication token for subsequent API calls. This endpoint does not require the Authorization header.", - "operationId": "authenticate_user", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AuthWithPasswordBody", - "description": "Request body containing authentication credentials and account type" - } + "/api/v3/model-info/inverters": { + "get": { + "description": "Lists inverter model information from the asset catalog.", + "operationId": "list_inverter_model_info", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" } }, - "required": true - }, + { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "enum": [ + "viewer", + "manager", + "admin" + ], + "type": "string" + } + } + ], "responses": { "200": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AuthOutputV3Body", - "description": "Response body containing complete account information and authentication token" + "$ref": "#/components/schemas/ListOutputInverterItemBody" } } }, @@ -2152,17 +3677,21 @@ "description": "Error" } }, - "security": [], - "summary": "Authentication", + "security": [ + { + "bearer": [] + } + ], + "summary": "List Inverter Model Info", "tags": [ - "v3/account" + "v3/model-info" ] } }, - "/api/v3/account/refresh-token": { - "post": { - "description": "Refreshes the authentication token for the user. Requires a valid existing token in the Authorization header. Returns a new JWT token for subsequent API calls.", - "operationId": "refresh_user_token", + "/api/v3/model-info/modules": { + "get": { + "description": "Lists module model information from the asset catalog.", + "operationId": "list_module_model_info", "parameters": [ { "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", @@ -2195,8 +3724,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AuthBody", - "description": "Response body containing authentication details" + "$ref": "#/components/schemas/ListOutputModuleItemBody" } } }, @@ -2218,9 +3746,9 @@ "bearer": [] } ], - "summary": "Refresh Authentication Token", + "summary": "List Module Model Info", "tags": [ - "v3/account" + "v3/model-info" ] } }, @@ -2256,7 +3784,6 @@ }, { "description": "Organization ID to which the new member will be added.", - "example": "org123456789012", "in": "path", "name": "organization_id", "required": true, @@ -2275,7 +3802,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Create_org_memberRequest" + "$ref": "#/components/schemas/CreateOrganizationMemberRequestBody" } } }, @@ -2346,7 +3873,6 @@ }, { "description": "Organization ID that owns the target plant.", - "example": "org123456789012", "in": "path", "name": "organization_id", "required": true, @@ -2463,6 +3989,17 @@ "type": "integer" } }, + { + "description": "When true, ignores page and size and returns the full plant list by internally fetching sequential 500-item pages.", + "explode": false, + "in": "query", + "name": "full", + "schema": { + "default": false, + "description": "When true, ignores page and size and returns the full plant list by internally fetching sequential 500-item pages.", + "type": "boolean" + } + }, { "description": "Succeeds if the server's resource matches one of the passed values.", "in": "header", @@ -2524,7 +4061,15 @@ } } }, - "description": "OK" + "description": "OK", + "headers": { + "ETag": { + "schema": { + "description": "Weak entity tag for conditional requests.", + "type": "string" + } + } + } }, "default": { "content": { @@ -2550,6 +4095,33 @@ "post": { "description": "Creates a new solar plant associated with the user's account.", "operationId": "create_plant", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "enum": [ + "viewer", + "manager", + "admin" + ], + "type": "string" + } + } + ], "requestBody": { "content": { "application/json": { @@ -2627,7 +4199,6 @@ }, { "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation to fetch detailed information for. Must be exactly 15 characters in length.", - "example": "unw4id41ud2p0wt", "in": "path", "name": "plant_id", "required": true, @@ -2703,7 +4274,15 @@ } } }, - "description": "OK" + "description": "OK", + "headers": { + "ETag": { + "schema": { + "description": "Weak entity tag for conditional requests.", + "type": "string" + } + } + } }, "default": { "content": { @@ -2759,7 +4338,6 @@ }, { "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation to fetch blueprint data for. Must be exactly 15 characters in length.", - "example": "unw4id41ud2p0wt", "in": "path", "name": "plant_id", "required": true, @@ -2776,7 +4354,6 @@ }, { "description": "Target date for blueprint data retrieval. The date for which you want to retrieve the plant's blueprint configuration. Must follow the ISO 8601 date format 'YYYY-MM-DD'.", - "example": "2024-01-24", "explode": false, "in": "query", "name": "date", @@ -2829,38 +4406,21 @@ "format": "date-time-http", "type": "string" } - }, - { - "description": "Succeeds if the server's resource date is older or the same as the passed date.", - "in": "header", - "name": "If-Unmodified-Since", - "schema": { - "description": "Succeeds if the server's resource date is older or the same as the passed date.", - "format": "date-time-http", - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "contentEncoding": "base64", - "description": "Binary blueprint data containing system layout and component mapping information", - "type": "string" - } - } - }, - "description": "OK", - "headers": { - "Content-Type": { - "schema": { - "description": "MIME type of the returned blueprint data (e.g., application/json, application/octet-stream)", - "type": "string" - } - } + }, + { + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "in": "header", + "name": "If-Unmodified-Since", + "schema": { + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "format": "date-time-http", + "type": "string" } + } + ], + "responses": { + "200": { + "description": "OK" }, "default": { "content": { @@ -2884,10 +4444,10 @@ ] } }, - "/api/v3/plants/{plant_id}/files": { - "post": { - "description": "Uploads files related to a specific plant including blueprints, images, and configuration files. Authorization header and Account-Type header are required.", - "operationId": "upload_plant_files", + "/api/v3/plants/{plant_id}/indicator/device-state": { + "get": { + "description": "Retrieves device or panel state indicator data at 5-minute interval. Use the `kind` query parameter with one of: seqnum, relay, rsd.", + "operationId": "get_device_state", "parameters": [ { "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", @@ -2915,55 +4475,64 @@ } }, { - "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation to upload files for. Must be exactly 15 characters in length.", - "example": "unw4id41ud2p0wt", + "description": "Succeeds when none of the supplied ETags match the current representation.", + "in": "header", + "name": "If-None-Match", + "schema": { + "description": "Succeeds when none of the supplied ETags match the current representation.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "The ID of the plant.", "in": "path", "name": "plant_id", "required": true, "schema": { - "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation to upload files for. Must be exactly 15 characters in length.", + "description": "The ID of the plant.", + "type": "string" + } + }, + { + "description": "Target date (YYYY-MM-DD).", + "explode": false, + "in": "query", + "name": "date", + "required": true, + "schema": { + "description": "Target date (YYYY-MM-DD).", "examples": [ - "unw4id41ud2p0wt" + "2025-08-14" + ], + "format": "date", + "type": "string" + } + }, + { + "description": "Indicator kind to retrieve. One of: seqnum, relay, rsd.", + "explode": false, + "in": "query", + "name": "kind", + "required": true, + "schema": { + "description": "Indicator kind to retrieve. One of: seqnum, relay, rsd.", + "enum": [ + "seqnum", + "relay", + "rsd" ], - "maxLength": 15, - "minLength": 15, - "patternDescription": "alphanum", "type": "string" } } ], - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "properties": { - "filename": { - "contentMediaType": "application/octet-stream", - "description": "filename of the file being uploaded", - "format": "binary", - "type": "string" - }, - "name": { - "description": "general purpose name for multipart form value", - "type": "string" - } - }, - "type": "object" - } - } - }, - "required": true - }, "responses": { "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/FileUploadResponse", - "description": "Response body containing file upload details and metadata" - } - } - }, "description": "OK" }, "default": { @@ -2982,9 +4551,9 @@ "bearer": [] } ], - "summary": "Upload Plant Files", + "summary": "Retrieve Device State (5m avg)", "tags": [ - "v3/plants/files" + "v3/plants/indicator" ] } }, @@ -3018,6 +4587,21 @@ "type": "string" } }, + { + "description": "Succeeds when none of the supplied ETags match the current representation.", + "in": "header", + "name": "If-None-Match", + "schema": { + "description": "Succeeds when none of the supplied ETags match the current representation.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, { "description": "The ID of the plant to calculate health levels for.", "in": "path", @@ -3030,7 +4614,6 @@ }, { "description": "The unit to calculate health levels for (e.g., panel).", - "example": "panel", "in": "path", "name": "unit", "required": true, @@ -3045,7 +4628,6 @@ }, { "description": "The specific date for health level calculation (YYYY-MM-DD).", - "example": "2025-08-14", "explode": false, "in": "query", "name": "date", @@ -3061,7 +4643,6 @@ }, { "description": "The view type for the response (summary or detail).", - "example": "summary", "explode": false, "in": "query", "name": "view", @@ -3088,90 +4669,14 @@ } } }, - "description": "OK" - }, - "default": { - "content": { - "application/problem+json": { + "description": "OK", + "headers": { + "ETag": { "schema": { - "$ref": "#/components/schemas/ErrorModel" + "type": "string" } } - }, - "description": "Error" - } - }, - "security": [ - { - "bearer": [] - } - ], - "summary": "Retrieve Panel Health Levels", - "tags": [ - "v3/plants/indicator" - ] - } - }, - "/api/v3/plants/{plant_id}/indicator/seqnum": { - "get": { - "description": "Retrieves panel-level seq_num time-series at 5-minute interval.", - "operationId": "get_panel_seqnum", - "parameters": [ - { - "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", - "in": "header", - "name": "Authorization", - "required": true, - "schema": { - "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", - "type": "string" - } - }, - { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", - "in": "header", - "name": "Account-Type", - "required": true, - "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", - "enum": [ - "viewer", - "manager", - "admin" - ], - "type": "string" - } - }, - { - "description": "The ID of the plant.", - "in": "path", - "name": "plant_id", - "required": true, - "schema": { - "description": "The ID of the plant.", - "type": "string" - } - }, - { - "description": "Target date (YYYY-MM-DD).", - "example": "2025-08-14", - "explode": false, - "in": "query", - "name": "date", - "required": true, - "schema": { - "description": "Target date (YYYY-MM-DD).", - "examples": [ - "2025-08-14" - ], - "format": "date", - "type": "string" } - } - ], - "responses": { - "200": { - "description": "OK" }, "default": { "content": { @@ -3189,7 +4694,7 @@ "bearer": [] } ], - "summary": "Retrieve Panel SeqNum (5m avg)", + "summary": "Retrieve Panel Health Levels", "tags": [ "v3/plants/indicator" ] @@ -3227,7 +4732,6 @@ }, { "description": "Plant ID. A unique alphanumeric identifier representing the plant to fetch data for. Must be exactly 15 characters in length.", - "example": "bsajtokt84s2byf", "in": "path", "name": "plant_id", "required": true, @@ -3267,26 +4771,11 @@ } }, { - "description": "Succeeds if the server's resource matches one of the passed values.", - "in": "header", - "name": "If-Match", - "schema": { - "description": "Succeeds if the server's resource matches one of the passed values.", - "items": { - "type": "string" - }, - "type": [ - "array", - "null" - ] - } - }, - { - "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "description": "Succeeds when none of the supplied ETags match the current representation.", "in": "header", "name": "If-None-Match", "schema": { - "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "description": "Succeeds when none of the supplied ETags match the current representation.", "items": { "type": "string" }, @@ -3295,26 +4784,6 @@ "null" ] } - }, - { - "description": "Succeeds if the server's resource date is more recent than the passed date.", - "in": "header", - "name": "If-Modified-Since", - "schema": { - "description": "Succeeds if the server's resource date is more recent than the passed date.", - "format": "date-time-http", - "type": "string" - } - }, - { - "description": "Succeeds if the server's resource date is older or the same as the passed date.", - "in": "header", - "name": "If-Unmodified-Since", - "schema": { - "description": "Succeeds if the server's resource date is older or the same as the passed date.", - "format": "date-time-http", - "type": "string" - } } ], "responses": { @@ -3326,7 +4795,15 @@ } } }, - "description": "OK" + "description": "OK", + "headers": { + "ETag": { + "schema": { + "description": "Weak entity tag for conditional requests.", + "type": "string" + } + } + } }, "default": { "content": { @@ -3382,7 +4859,6 @@ }, { "description": "Plant ID. A unique alphanumeric identifier representing the plant to fetch data for. Must be exactly 15 characters in length.", - "example": "bsajtokt84s2byf", "in": "path", "name": "plant_id", "required": true, @@ -3432,26 +4908,11 @@ } }, { - "description": "Succeeds if the server's resource matches one of the passed values.", - "in": "header", - "name": "If-Match", - "schema": { - "description": "Succeeds if the server's resource matches one of the passed values.", - "items": { - "type": "string" - }, - "type": [ - "array", - "null" - ] - } - }, - { - "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "description": "Succeeds when none of the supplied ETags match the current representation.", "in": "header", "name": "If-None-Match", "schema": { - "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "description": "Succeeds when none of the supplied ETags match the current representation.", "items": { "type": "string" }, @@ -3460,26 +4921,6 @@ "null" ] } - }, - { - "description": "Succeeds if the server's resource date is more recent than the passed date.", - "in": "header", - "name": "If-Modified-Since", - "schema": { - "description": "Succeeds if the server's resource date is more recent than the passed date.", - "format": "date-time-http", - "type": "string" - } - }, - { - "description": "Succeeds if the server's resource date is older or the same as the passed date.", - "in": "header", - "name": "If-Unmodified-Since", - "schema": { - "description": "Succeeds if the server's resource date is older or the same as the passed date.", - "format": "date-time-http", - "type": "string" - } } ], "responses": { @@ -3487,11 +4928,19 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/InverterLogsResponse" + "$ref": "#/components/schemas/InverterLogsResponse" + } + } + }, + "description": "OK", + "headers": { + "ETag": { + "schema": { + "description": "Weak entity tag for conditional requests.", + "type": "string" } } - }, - "description": "OK" + } }, "default": { "content": { @@ -3547,7 +4996,6 @@ }, { "description": "Plant ID. A unique alphanumeric identifier representing the plant to fetch data for. Must be exactly 15 characters in length.", - "example": "unw4id41ud2p0wt", "in": "path", "name": "plant_id", "required": true, @@ -3573,7 +5021,6 @@ }, { "description": "The time range in minutes for filtering active devices. Only devices that have sent data within the last 'ago' minutes will be included in the response. This helps exclude inactive or unresponsive devices. The maximum allowed value is 600 minutes.", - "example": 15, "explode": false, "in": "query", "name": "ago", @@ -3655,7 +5102,15 @@ } } }, - "description": "OK" + "description": "OK", + "headers": { + "ETag": { + "schema": { + "description": "Weak entity tag for conditional requests", + "type": "string" + } + } + } }, "default": { "content": { @@ -3711,7 +5166,6 @@ }, { "description": "Plant ID. A unique alphanumeric identifier representing the plant to fetch data for. Must be exactly 15 characters in length.", - "example": "bsajtokt84s2byf", "in": "path", "name": "plant_id", "required": true, @@ -3789,7 +5243,15 @@ } } }, - "description": "OK" + "description": "OK", + "headers": { + "ETag": { + "schema": { + "description": "Weak entity tag for conditional requests", + "type": "string" + } + } + } }, "default": { "content": { @@ -3843,9 +5305,23 @@ "type": "string" } }, + { + "description": "Succeeds when none of the supplied ETags match the current representation.", + "in": "header", + "name": "If-None-Match", + "schema": { + "description": "Succeeds when none of the supplied ETags match the current representation.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, { "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation to fetch metrics data for. Must be exactly 15 characters in length.", - "example": "unw4id41ud2p0wt", "in": "path", "name": "plant_id", "required": true, @@ -3861,17 +5337,17 @@ } }, { - "description": "Data source type. Indicates the origin of the data collection system. 'device' refers to panel-level monitoring devices, while 'inverter' refers to inverter-level data collection.", - "example": "device", + "description": "Data source type. Indicates the origin of the data collection system. 'device' refers to panel-level monitoring devices, 'inverter' refers to inverter-level data collection, and 'sensor' refers to sensor data collection.", "in": "path", "name": "source", "required": true, "schema": { "default": "device", - "description": "Data source type. Indicates the origin of the data collection system. 'device' refers to panel-level monitoring devices, while 'inverter' refers to inverter-level data collection.", + "description": "Data source type. Indicates the origin of the data collection system. 'device' refers to panel-level monitoring devices, 'inverter' refers to inverter-level data collection, and 'sensor' refers to sensor data collection.", "enum": [ "device", - "inverter" + "inverter", + "sensor" ], "examples": [ "device" @@ -3880,19 +5356,20 @@ } }, { - "description": "Data aggregation unit. Specifies the hierarchical level of data aggregation within the solar installation. 'panel' provides individual panel data, 'inverter' aggregates by inverter, 'string' aggregates by string configuration, and 'plant' provides plant-wide aggregated data.", - "example": "plant", + "description": "Data aggregation unit. Specifies the hierarchical level of data aggregation within the solar installation. 'panel' provides individual panel data, 'inverter' aggregates by inverter, 'string' aggregates by string configuration, 'plant' provides plant-wide aggregated data, and 'temperature'/'insolation' are sensor-specific units.", "in": "path", "name": "unit", "required": true, "schema": { "default": "plant", - "description": "Data aggregation unit. Specifies the hierarchical level of data aggregation within the solar installation. 'panel' provides individual panel data, 'inverter' aggregates by inverter, 'string' aggregates by string configuration, and 'plant' provides plant-wide aggregated data.", + "description": "Data aggregation unit. Specifies the hierarchical level of data aggregation within the solar installation. 'panel' provides individual panel data, 'inverter' aggregates by inverter, 'string' aggregates by string configuration, 'plant' provides plant-wide aggregated data, and 'temperature'/'insolation' are sensor-specific units.", "enum": [ "panel", "inverter", "string", - "plant" + "plant", + "temperature", + "insolation" ], "examples": [ "plant" @@ -3902,7 +5379,6 @@ }, { "description": "Time interval for data aggregation. Determines the temporal granularity of the returned time-series data. Supported intervals: '5m' (5 minutes), '15m' (15 minutes), '1h' (1 hour), '1d' (1 day), '1M' (1 month), '1y' (1 year).", - "example": "5m", "in": "path", "name": "interval", "required": true, @@ -3924,7 +5400,6 @@ }, { "description": "Target date for data retrieval. The specific date for which you want to retrieve solar plant metrics data. Must follow the ISO 8601 date format 'YYYY-MM-DD'.", - "example": "2024-01-24", "explode": false, "in": "query", "name": "date", @@ -3940,7 +5415,6 @@ }, { "description": "Historical data range. Number of time intervals before the specified date to include in the response. This parameter allows retrieval of historical trend data. Note: Only applicable for daily and longer intervals (1d, 1M, 1y), not for intraday intervals (5m, 15m, 1h).", - "example": 1, "explode": false, "in": "query", "name": "before", @@ -3958,10 +5432,6 @@ }, { "description": "Data fields selection. Specifies which metrics or parameters to include in the response. Use 'all' to retrieve all available measurement fields, or specify individual field names (e.g., 'i_out' for output current, 'p' for power, 'energy' for energy production).", - "example": [ - "i_out", - "p" - ], "explode": false, "in": "query", "name": "fields", @@ -3984,6 +5454,28 @@ "null" ] } + }, + { + "description": "Panel ID filters. Supported only when source=device and unit=panel. Multiple id query parameters are allowed (e.g., id=pnl-001&id=pnl-002).", + "explode": false, + "in": "query", + "name": "id", + "schema": { + "description": "Panel ID filters. Supported only when source=device and unit=panel. Multiple id query parameters are allowed (e.g., id=pnl-001&id=pnl-002).", + "examples": [ + [ + "pnl-001", + "pnl-002" + ] + ], + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } } ], "responses": { @@ -4247,6 +5739,57 @@ "title": "Plant Intraday Metrics", "type": "object" }, + { + "additionalProperties": false, + "description": "Time-series summary metrics for plant sensors at 5-minute intervals.", + "properties": { + "before": { + "description": "Number of historical intervals included in the response", + "format": "int64", + "type": "integer" + }, + "data": { + "description": "Array of time-series data points matching the specified parameters", + "items": { + "$ref": "#/components/schemas/SensorData" + }, + "type": [ + "array", + "null" + ] + }, + "date": { + "description": "Target date for the data retrieval", + "type": "string" + }, + "interval": { + "description": "Time interval used for data aggregation", + "type": "string" + }, + "plant_id": { + "description": "Plant identifier that was queried", + "type": "string" + }, + "source": { + "description": "Data source type that was queried", + "type": "string" + }, + "unit": { + "description": "Data aggregation unit that was requested", + "type": "string" + } + }, + "required": [ + "plant_id", + "unit", + "source", + "date", + "interval", + "data" + ], + "title": "Sensor Intraday Metrics", + "type": "object" + }, { "additionalProperties": false, "description": "Aggregated metrics for entire plant at 1-day, 1-month, and 1-year intervals.", @@ -4326,6 +5869,160 @@ ] } }, + "/api/v3/plants/{plant_id}/registry/stat": { + "get": { + "description": "Retrieves the end-of-day installed capacity, module model counts, and device model stats for the specified plant and date from the registry origin, while computing the response ETag within patch-api.", + "operationId": "get_plant_registry_stat", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "enum": [ + "viewer", + "manager", + "admin" + ], + "type": "string" + } + }, + { + "description": "Patch Plant ID. A unique alphanumeric identifier representing the plant to fetch data for. Must be exactly 15 characters in length.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Patch Plant ID. A unique alphanumeric identifier representing the plant to fetch data for. Must be exactly 15 characters in length.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "patternDescription": "alphanum", + "type": "string" + } + }, + { + "description": "Target date of data. Must follow the format 'YYYY-MM-DD'.", + "explode": false, + "in": "query", + "name": "date", + "required": true, + "schema": { + "description": "Target date of data. Must follow the format 'YYYY-MM-DD'.", + "examples": [ + "2024-01-24" + ], + "format": "date", + "type": "string" + } + }, + { + "description": "Succeeds if the server's resource matches one of the passed values.", + "in": "header", + "name": "If-Match", + "schema": { + "description": "Succeeds if the server's resource matches one of the passed values.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "in": "header", + "name": "If-None-Match", + "schema": { + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "Succeeds if the server's resource date is more recent than the passed date.", + "in": "header", + "name": "If-Modified-Since", + "schema": { + "description": "Succeeds if the server's resource date is more recent than the passed date.", + "format": "date-time-http", + "type": "string" + } + }, + { + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "in": "header", + "name": "If-Unmodified-Since", + "schema": { + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "format": "date-time-http", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StatPoint", + "description": "Installed panel capacity, module model counts, and device model stats at the end of the requested day." + } + } + }, + "description": "OK", + "headers": { + "ETag": { + "schema": { + "description": "Weak entity tag for conditional requests.", + "type": "string" + } + } + } + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Retrieve Plant Registry Stat", + "tags": [ + "v3/plants/registry" + ] + } + }, "/api/v3/plants/{plant_id}/registry/{record_type}": { "get": { "description": "Retrieves asset registry information for a specific plant filtered by record type. Includes registration status, mapping information, and historical data for the specified asset type. Authorization header and Account-Type header are required.", @@ -4358,7 +6055,6 @@ }, { "description": "Patch Plant ID. A unique alphanumeric identifier representing the plant to fetch data for. Must be exactly 15 characters in length.", - "example": "unw4id41ud2p0wt", "in": "path", "name": "plant_id", "required": true, @@ -4375,7 +6071,6 @@ }, { "description": "The type of data to retrieve. Possible values:'logs': Returns all records that have changed on the specified date., 'snapshots': Returns all records that can be evaluated as 'registered' on the specified date.", - "example": "logs", "in": "path", "name": "record_type", "required": true, @@ -4393,7 +6088,6 @@ }, { "description": "Target date of data. Must follow the format 'YYYY-MM-DD'.", - "example": "2024-01-24", "explode": false, "in": "query", "name": "date", @@ -4494,7 +6188,15 @@ } } }, - "description": "OK" + "description": "OK", + "headers": { + "ETag": { + "schema": { + "description": "Weak entity tag for conditional requests.", + "type": "string" + } + } + } }, "default": { "content": { From fd879673628ff3d2e75e4490e2f7547554624c09 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 00:52:47 +0000 Subject: [PATCH 02/11] chore: sync openapi v3 snapshot --- openapi/openapi-v3.json | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/openapi/openapi-v3.json b/openapi/openapi-v3.json index 46f4efa..1235568 100644 --- a/openapi/openapi-v3.json +++ b/openapi/openapi-v3.json @@ -758,8 +758,7 @@ }, "has_diode": { "description": "Diode presence flag from the combiners asset catalog view.", - "format": "int64", - "type": "integer" + "type": "boolean" }, "height_fuse_mm": { "description": "Height fuse value from the combiners asset catalog view.", @@ -801,8 +800,8 @@ }, "ip_rating": { "description": "IP rating value from the combiners asset catalog view.", - "format": "int64", - "type": "integer" + "format": "double", + "type": "number" }, "manufacturer": { "description": "Manufacturer value from the combiners asset catalog view.", @@ -851,8 +850,7 @@ }, "rated_current_a": { "description": "Rated current value from the combiners asset catalog view.", - "format": "double", - "type": "number" + "type": "string" }, "rated_output_power_kva": { "description": "Rated output power value from the combiners asset catalog view.", @@ -861,8 +859,8 @@ }, "string_count": { "description": "String count value from the combiners asset catalog view.", - "format": "int64", - "type": "integer" + "format": "double", + "type": "number" }, "technical_standard": { "description": "Technical standard value from the combiners asset catalog view.", @@ -2097,9 +2095,7 @@ "type": "string" }, "cell_specification": { - "additionalProperties": {}, - "description": "Cell specification object from the modules asset catalog view.", - "type": "object" + "description": "Cell specification value from the modules asset catalog view." }, "certification_date": { "description": "Certification date value from the modules asset catalog view.", From b086e5172e67324be26eeb2ddc150eb2d2c4d5e7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 4 May 2026 00:59:00 +0000 Subject: [PATCH 03/11] chore: sync openapi v3 snapshot --- openapi/openapi-v3.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openapi/openapi-v3.json b/openapi/openapi-v3.json index 1235568..69c510f 100644 --- a/openapi/openapi-v3.json +++ b/openapi/openapi-v3.json @@ -2897,6 +2897,7 @@ "Report": { "additionalProperties": false, "properties": { + "content": {}, "created": { "type": "string" }, @@ -2928,6 +2929,7 @@ "start": { "type": "string" }, + "summary": {}, "title": { "type": "string" }, From a5cf7d4c5c3af70a5d1478b6efe501f1870331af Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 11 May 2026 01:02:56 +0000 Subject: [PATCH 04/11] chore: sync openapi v3 snapshot --- openapi/openapi-v3.json | 50 +++++++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/openapi/openapi-v3.json b/openapi/openapi-v3.json index 69c510f..57af761 100644 --- a/openapi/openapi-v3.json +++ b/openapi/openapi-v3.json @@ -1927,6 +1927,31 @@ ], "type": "object" }, + "InverterModelStat": { + "additionalProperties": false, + "properties": { + "count": { + "description": "Active inverter count for the model name at the end of the requested day.", + "format": "int64", + "type": "integer" + }, + "installed_capacity_w": { + "description": "Installed capacity in watts attributed to the inverter model at the end of the requested day.", + "format": "double", + "type": "number" + }, + "name": { + "description": "Active inverter model name at the end of the requested day.", + "type": "string" + } + }, + "required": [ + "name", + "count", + "installed_capacity_w" + ], + "type": "object" + }, "LatestDeviceBody": { "additionalProperties": false, "properties": { @@ -1948,9 +1973,6 @@ "metrics": { "$ref": "#/components/schemas/LatestDeviceBodyMetricsStruct" }, - "plant_id": { - "type": "string" - }, "state": { "additionalProperties": { "type": "boolean" @@ -1968,7 +1990,6 @@ "asset_type", "map_id", "map_type", - "plant_id", "edge_id", "metrics", "state" @@ -3050,6 +3071,16 @@ "format": "double", "type": "number" }, + "inverter_models": { + "description": "Active inverter model stats at the end of the requested day.", + "items": { + "$ref": "#/components/schemas/InverterModelStat" + }, + "type": [ + "array", + "null" + ] + }, "module_models": { "description": "Active panel and panel_group model counts at the end of the requested day.", "items": { @@ -3069,7 +3100,8 @@ "timestamp", "installed_capacity_w", "module_models", - "device_models" + "device_models", + "inverter_models" ], "type": "object" }, @@ -4557,7 +4589,7 @@ }, "/api/v3/plants/{plant_id}/indicator/health-level/{unit}": { "get": { - "description": "Calculates and retrieves the health level of panels for a specific plant based on daily energy production. Panels are categorized as 'best', 'caution', or 'faulty'.", + "description": "Calculates panel health indicators from daily energy production. The response reports the top ten panels as 'best' and reports panels outside the top ten only when they fall into 'caution' or 'faulty' thresholds.", "operationId": "get_asset_health_level", "parameters": [ { @@ -5454,12 +5486,12 @@ } }, { - "description": "Panel ID filters. Supported only when source=device and unit=panel. Multiple id query parameters are allowed (e.g., id=pnl-001&id=pnl-002).", + "description": "Device panel or inverter ID filters. Supported only for intraday device/panel and inverter/inverter requests (5m, 15m, 1h). Multiple id query parameters are allowed (e.g., id=pnl-001&id=pnl-002).", "explode": false, "in": "query", "name": "id", "schema": { - "description": "Panel ID filters. Supported only when source=device and unit=panel. Multiple id query parameters are allowed (e.g., id=pnl-001&id=pnl-002).", + "description": "Device panel or inverter ID filters. Supported only for intraday device/panel and inverter/inverter requests (5m, 15m, 1h). Multiple id query parameters are allowed (e.g., id=pnl-001&id=pnl-002).", "examples": [ [ "pnl-001", @@ -5985,7 +6017,7 @@ "application/json": { "schema": { "$ref": "#/components/schemas/StatPoint", - "description": "Installed panel capacity, module model counts, and device model stats at the end of the requested day." + "description": "Installed panel capacity, module model counts, device model stats, and inverter model stats at the end of the requested day." } } }, From 5ce8b2850e575a76d4f4a124d442c4b7a142b2fe Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 18 May 2026 01:05:05 +0000 Subject: [PATCH 05/11] chore: sync openapi v3 snapshot --- openapi/openapi-v3.json | 2951 +++++++++++++++++++++++++++++++-------- 1 file changed, 2394 insertions(+), 557 deletions(-) diff --git a/openapi/openapi-v3.json b/openapi/openapi-v3.json index 57af761..7718258 100644 --- a/openapi/openapi-v3.json +++ b/openapi/openapi-v3.json @@ -367,6 +367,237 @@ ], "type": "object" }, + "BlueprintListItem": { + "additionalProperties": false, + "properties": { + "created": { + "description": "Blueprint record creation timestamp.", + "type": "string" + }, + "date": { + "description": "Blueprint effective date.", + "type": "string" + }, + "id": { + "description": "Blueprint record ID.", + "type": "string" + }, + "updated": { + "description": "Blueprint record update timestamp.", + "type": "string" + } + }, + "required": [ + "id", + "date", + "updated" + ], + "type": "object" + }, + "BodyESSPlantDailyData": { + "additionalProperties": false, + "description": "Plant-level energy storage system daily metrics at 1-day intervals.", + "properties": { + "before": { + "description": "Number of historical intervals included in the response", + "format": "int64", + "type": "integer" + }, + "data": { + "description": "Array of time-series data points matching the specified parameters", + "items": { + "$ref": "#/components/schemas/ESSPlantDailyData" + }, + "type": [ + "array", + "null" + ] + }, + "date": { + "description": "Target date for the data retrieval", + "type": "string" + }, + "interval": { + "description": "Time interval used for data aggregation", + "type": "string" + }, + "plant_id": { + "description": "Plant identifier that was queried", + "type": "string" + }, + "source": { + "description": "Data source type that was queried", + "type": "string" + }, + "unit": { + "description": "Data aggregation unit that was requested", + "type": "string" + } + }, + "required": [ + "plant_id", + "unit", + "source", + "date", + "interval", + "data" + ], + "title": "ESS Plant Daily Metrics", + "type": "object" + }, + "BodyESSPlantIntradayData": { + "additionalProperties": false, + "description": "Plant-level energy storage system metrics at 5-minute, 15-minute, and 1-hour intervals.", + "properties": { + "before": { + "description": "Number of historical intervals included in the response", + "format": "int64", + "type": "integer" + }, + "data": { + "description": "Array of time-series data points matching the specified parameters", + "items": { + "$ref": "#/components/schemas/ESSPlantIntradayData" + }, + "type": [ + "array", + "null" + ] + }, + "date": { + "description": "Target date for the data retrieval", + "type": "string" + }, + "interval": { + "description": "Time interval used for data aggregation", + "type": "string" + }, + "plant_id": { + "description": "Plant identifier that was queried", + "type": "string" + }, + "source": { + "description": "Data source type that was queried", + "type": "string" + }, + "unit": { + "description": "Data aggregation unit that was requested", + "type": "string" + } + }, + "required": [ + "plant_id", + "unit", + "source", + "date", + "interval", + "data" + ], + "title": "ESS Plant Intraday Metrics", + "type": "object" + }, + "BodyESSUnitDailyData": { + "additionalProperties": false, + "description": "Energy storage system unit daily metrics at 1-day intervals.", + "properties": { + "before": { + "description": "Number of historical intervals included in the response", + "format": "int64", + "type": "integer" + }, + "data": { + "description": "Array of time-series data points matching the specified parameters", + "items": { + "$ref": "#/components/schemas/ESSUnitDailyData" + }, + "type": [ + "array", + "null" + ] + }, + "date": { + "description": "Target date for the data retrieval", + "type": "string" + }, + "interval": { + "description": "Time interval used for data aggregation", + "type": "string" + }, + "plant_id": { + "description": "Plant identifier that was queried", + "type": "string" + }, + "source": { + "description": "Data source type that was queried", + "type": "string" + }, + "unit": { + "description": "Data aggregation unit that was requested", + "type": "string" + } + }, + "required": [ + "plant_id", + "unit", + "source", + "date", + "interval", + "data" + ], + "title": "ESS Unit Daily Metrics", + "type": "object" + }, + "BodyESSUnitIntradayData": { + "additionalProperties": false, + "description": "Energy storage system unit metrics at 5-minute, 15-minute, and 1-hour intervals.", + "properties": { + "before": { + "description": "Number of historical intervals included in the response", + "format": "int64", + "type": "integer" + }, + "data": { + "description": "Array of time-series data points matching the specified parameters", + "items": { + "$ref": "#/components/schemas/ESSUnitIntradayData" + }, + "type": [ + "array", + "null" + ] + }, + "date": { + "description": "Target date for the data retrieval", + "type": "string" + }, + "interval": { + "description": "Time interval used for data aggregation", + "type": "string" + }, + "plant_id": { + "description": "Plant identifier that was queried", + "type": "string" + }, + "source": { + "description": "Data source type that was queried", + "type": "string" + }, + "unit": { + "description": "Data aggregation unit that was requested", + "type": "string" + } + }, + "required": [ + "plant_id", + "unit", + "source", + "date", + "interval", + "data" + ], + "title": "ESS Unit Intraday Metrics", + "type": "object" + }, "BodyInverterDailyData": { "additionalProperties": false, "description": "Daily aggregated metrics for individual inverters at 1-day intervals.", @@ -1247,43 +1478,372 @@ ], "type": "object" }, - "ErrorDetail": { + "ESSPlantDailyData": { "additionalProperties": false, "properties": { - "location": { - "description": "Where the error occurred, e.g. 'body.items[3].tags' or 'path.thing-id'", + "charge_energy": { + "description": "Daily charged energy total (kWh)", + "format": "double", + "type": "number" + }, + "date": { + "description": "Asia/Seoul local date represented by the row", "type": "string" }, - "message": { - "description": "Error message text", + "discharge_energy": { + "description": "Daily discharged or output energy total (kWh)", + "format": "double", + "type": "number" + }, + "energy": { + "description": "Daily positive output energy total (kWh)", + "format": "double", + "type": "number" + }, + "plant_id": { + "description": "Plant identifier for the local date partition", "type": "string" }, - "value": { - "description": "The value at the given location" + "pv_energy": { + "description": "Daily PV-side generated energy total (kWh)", + "format": "double", + "type": "number" } }, + "required": [ + "plant_id", + "date", + "energy", + "charge_energy", + "discharge_energy", + "pv_energy" + ], "type": "object" }, - "ErrorModel": { + "ESSPlantIntradayData": { "additionalProperties": false, "properties": { - "$schema": { - "description": "A URL to the JSON Schema for this object.", - "examples": [ - "https://patch-api.conalog.com/schemas/ErrorModel.json" - ], - "format": "uri", - "readOnly": true, - "type": "string" + "battery_current": { + "description": "Battery current (A); positive means net discharge and negative means net charge", + "format": "double", + "type": "number" }, - "detail": { - "description": "A human-readable explanation specific to this occurrence of the problem.", - "examples": [ - "Property foo is required but is missing." - ], - "type": "string" + "battery_power": { + "description": "Battery power magnitude during the interval (kW)", + "format": "double", + "type": "number" }, - "errors": { + "battery_voltage": { + "description": "Battery voltage (V)", + "format": "double", + "type": "number" + }, + "charge_energy": { + "description": "Energy charged into the battery during the interval (kWh)", + "format": "double", + "type": "number" + }, + "discharge_energy": { + "description": "Energy discharged or output from the battery during the interval (kWh)", + "format": "double", + "type": "number" + }, + "output_a_current": { + "description": "AC output phase A current (A)", + "format": "double", + "type": "number" + }, + "output_a_voltage": { + "description": "AC output phase A voltage (V)", + "format": "double", + "type": "number" + }, + "output_b_current": { + "description": "AC output phase B current (A)", + "format": "double", + "type": "number" + }, + "output_b_voltage": { + "description": "AC output phase B voltage (V)", + "format": "double", + "type": "number" + }, + "output_c_current": { + "description": "AC output phase C current (A)", + "format": "double", + "type": "number" + }, + "output_c_voltage": { + "description": "AC output phase C voltage (V)", + "format": "double", + "type": "number" + }, + "pv_current": { + "description": "PV DC current (A)", + "format": "double", + "type": "number" + }, + "pv_energy": { + "description": "PV-side generated energy during the interval (kWh)", + "format": "double", + "type": "number" + }, + "pv_voltage": { + "description": "PV DC voltage (V)", + "format": "double", + "type": "number" + }, + "time": { + "description": "Asia/Seoul interval start time label in HH:MM format", + "type": "string" + }, + "timestamp": { + "description": "Interval start Unix timestamp interpreted from the local date", + "format": "int64", + "type": "integer" + }, + "total_charge_energy": { + "description": "Cumulative charge energy display value at the interval timestamp (kWh)", + "format": "double", + "type": "number" + }, + "total_discharge_energy": { + "description": "Cumulative discharge energy display value at the interval timestamp (kWh)", + "format": "double", + "type": "number" + } + }, + "required": [ + "charge_energy", + "discharge_energy", + "pv_energy", + "battery_power", + "output_a_voltage", + "output_b_voltage", + "output_c_voltage", + "output_a_current", + "output_b_current", + "output_c_current", + "battery_voltage", + "battery_current", + "pv_voltage", + "pv_current", + "total_charge_energy", + "total_discharge_energy", + "time", + "timestamp" + ], + "type": "object" + }, + "ESSUnitDailyData": { + "additionalProperties": false, + "properties": { + "charge_energy": { + "description": "Daily charged energy total (kWh)", + "format": "double", + "type": "number" + }, + "date": { + "description": "Asia/Seoul local date represented by the row", + "type": "string" + }, + "discharge_energy": { + "description": "Daily discharged or output energy total (kWh)", + "format": "double", + "type": "number" + }, + "energy": { + "description": "Daily positive output energy total (kWh)", + "format": "double", + "type": "number" + }, + "id": { + "description": "ESS device identifier", + "type": "string" + }, + "plant_id": { + "description": "Plant identifier for the local date partition", + "type": "string" + }, + "pv_energy": { + "description": "Daily PV-side generated energy total (kWh)", + "format": "double", + "type": "number" + }, + "updated": { + "description": "Timestamp with time zone indicating when the daily row was updated", + "type": "string" + } + }, + "required": [ + "plant_id", + "id", + "date", + "energy", + "charge_energy", + "discharge_energy", + "pv_energy", + "updated" + ], + "type": "object" + }, + "ESSUnitIntradayData": { + "additionalProperties": false, + "properties": { + "battery_current": { + "description": "Battery current (A); positive means net discharge and negative means net charge", + "format": "double", + "type": "number" + }, + "battery_power": { + "description": "Battery power magnitude during the interval (kW)", + "format": "double", + "type": "number" + }, + "battery_voltage": { + "description": "Battery voltage (V)", + "format": "double", + "type": "number" + }, + "charge_energy": { + "description": "Energy charged into the battery during the interval (kWh)", + "format": "double", + "type": "number" + }, + "discharge_energy": { + "description": "Energy discharged or output from the battery during the interval (kWh)", + "format": "double", + "type": "number" + }, + "id": { + "description": "ESS device identifier", + "type": "string" + }, + "output_a_current": { + "description": "AC output phase A current (A)", + "format": "double", + "type": "number" + }, + "output_a_voltage": { + "description": "AC output phase A voltage (V)", + "format": "double", + "type": "number" + }, + "output_b_current": { + "description": "AC output phase B current (A)", + "format": "double", + "type": "number" + }, + "output_b_voltage": { + "description": "AC output phase B voltage (V)", + "format": "double", + "type": "number" + }, + "output_c_current": { + "description": "AC output phase C current (A)", + "format": "double", + "type": "number" + }, + "output_c_voltage": { + "description": "AC output phase C voltage (V)", + "format": "double", + "type": "number" + }, + "pv_current": { + "description": "PV DC current (A)", + "format": "double", + "type": "number" + }, + "pv_energy": { + "description": "PV-side generated energy during the interval (kWh)", + "format": "double", + "type": "number" + }, + "pv_voltage": { + "description": "PV DC voltage (V)", + "format": "double", + "type": "number" + }, + "time": { + "description": "Asia/Seoul interval start time label in HH:MM format", + "type": "string" + }, + "timestamp": { + "description": "Interval start Unix timestamp interpreted from the local date", + "format": "int64", + "type": "integer" + }, + "total_charge_energy": { + "description": "Cumulative charge energy display value at the interval timestamp (kWh)", + "format": "double", + "type": "number" + }, + "total_discharge_energy": { + "description": "Cumulative discharge energy display value at the interval timestamp (kWh)", + "format": "double", + "type": "number" + } + }, + "required": [ + "id", + "charge_energy", + "discharge_energy", + "pv_energy", + "battery_power", + "output_a_voltage", + "output_b_voltage", + "output_c_voltage", + "output_a_current", + "output_b_current", + "output_c_current", + "battery_voltage", + "battery_current", + "pv_voltage", + "pv_current", + "total_charge_energy", + "total_discharge_energy", + "time", + "timestamp" + ], + "type": "object" + }, + "ErrorDetail": { + "additionalProperties": false, + "properties": { + "location": { + "description": "Where the error occurred, e.g. 'body.items[3].tags' or 'path.thing-id'", + "type": "string" + }, + "message": { + "description": "Error message text", + "type": "string" + }, + "value": { + "description": "The value at the given location" + } + }, + "type": "object" + }, + "ErrorModel": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/ErrorModel.json" + ], + "format": "uri", + "readOnly": true, + "type": "string" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.", + "examples": [ + "Property foo is required but is missing." + ], + "type": "string" + }, + "errors": { "description": "Optional list of individual error details", "items": { "$ref": "#/components/schemas/ErrorDetail" @@ -1429,6 +1989,36 @@ ], "type": "object" }, + "InternalInvalidateAuthValidationCacheBody": { + "additionalProperties": false, + "properties": { + "cache_key": { + "pattern": "^token-auth/v2/(manager|viewer|admin)/[a-f0-9]{64}$", + "type": "string" + } + }, + "required": [ + "cache_key" + ], + "type": "object" + }, + "InternalInvalidateAuthValidationCacheResult": { + "additionalProperties": false, + "properties": { + "accepted": { + "type": "boolean" + }, + "deleted": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "accepted", + "deleted" + ], + "type": "object" + }, "InternalWarmCacheBody": { "additionalProperties": false, "properties": { @@ -1471,6 +2061,7 @@ "type": "string" }, "plant_id": { + "description": "Physical data plant ID to warm. RefPlant-backed public requests read canonical data plant cache keys, so warm targets should use the physical data plant ID.", "maxLength": 15, "minLength": 15, "type": "string" @@ -1478,7 +2069,8 @@ "source": { "enum": [ "device", - "inverter" + "inverter", + "ess" ], "type": "string" }, @@ -1490,6 +2082,7 @@ "enum": [ "panel", "inverter", + "ess", "string", "plant" ], @@ -2424,38 +3017,77 @@ "PanelData": { "additionalProperties": false, "properties": { + "avg_seqnum": { + "description": "Average sequence number indicator for the panel, or null when the source parquet does not contain this optional metric.", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "count": { + "description": "Data count for the panel interval, or null when the source parquet does not contain this optional metric.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, "cumulative_energy": { - "description": "Cumulative energy production up to this point (kWh)", + "description": "Cumulative energy production up to this point (kWh), or null when the source parquet does not contain this optional metric.", "format": "double", - "type": "number" + "type": [ + "number", + "null" + ] }, "date": { "description": "Date of the data point in YYYY-MM-DD format", "type": "string" }, "energy": { - "description": "Energy production for the time interval (kWh)", + "description": "Energy production for the time interval (kWh), or null when the source parquet does not contain this optional metric.", "format": "double", - "type": "number" + "type": [ + "number", + "null" + ] }, "i_out": { - "description": "Output current measurement (Amperes)", + "description": "Output current measurement (Amperes), or null when the source parquet does not contain this optional metric.", "format": "double", - "type": "number" + "type": [ + "number", + "null" + ] }, "id": { "description": "Unique identifier for the solar panel", "type": "string" }, - "p": { - "description": "Power output measurement (Watts)", - "format": "double", - "type": "number" - }, - "temp": { - "description": "Panel temperature measurement (Celsius)", + "min_seqnum": { + "description": "Minimum sequence number indicator for the panel, or null when the source parquet does not contain this optional metric.", "format": "double", - "type": "number" + "type": [ + "number", + "null" + ] + }, + "p": { + "description": "Power output measurement (Watts), or null when the source parquet does not contain this optional metric.", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "temp": { + "description": "Panel temperature measurement (Celsius), or null when the source parquet does not contain this optional metric.", + "format": "double", + "type": [ + "number", + "null" + ] }, "timestamp": { "description": "Unix timestamp of the measurement", @@ -2463,14 +3095,20 @@ "type": "integer" }, "v_in": { - "description": "Input voltage measurement (Volts)", + "description": "Input voltage measurement (Volts), or null when the source parquet does not contain this optional metric.", "format": "double", - "type": "number" + "type": [ + "number", + "null" + ] }, "v_out": { - "description": "Output voltage measurement (Volts)", + "description": "Output voltage measurement (Volts), or null when the source parquet does not contain this optional metric.", "format": "double", - "type": "number" + "type": [ + "number", + "null" + ] } }, "required": [ @@ -2483,7 +3121,10 @@ "p", "v_in", "v_out", - "temp" + "temp", + "avg_seqnum", + "min_seqnum", + "count" ], "type": "object" }, @@ -2791,7 +3432,10 @@ "enum": [ "device", "inverter", - "edge" + "edge", + "panel", + "panel_group", + "sensor" ], "examples": [ "device" @@ -2813,7 +3457,10 @@ "edge", "inverter", "combiner", - "panel" + "panel", + "panel_group", + "tracker", + "sensor" ], "examples": [ "panel" @@ -2869,7 +3516,10 @@ "enum": [ "device", "inverter", - "edge" + "edge", + "panel", + "panel_group", + "sensor" ], "type": "string" }, @@ -2885,7 +3535,10 @@ "edge", "inverter", "combiner", - "panel" + "panel", + "panel_group", + "tracker", + "sensor" ], "type": "string" }, @@ -3056,6 +3709,10 @@ "readOnly": true, "type": "string" }, + "all_asset_models_registered": { + "description": "Whether every active stat-covered registry record has required asset model information registered at the end of the requested day. Panels may inherit a panel_group model. Edge, sensor, tracker, combiner, string, and other non-stat records are ignored.", + "type": "boolean" + }, "device_models": { "description": "Active device model stats at the end of the requested day.", "items": { @@ -3099,6 +3756,7 @@ "required": [ "timestamp", "installed_capacity_w", + "all_asset_models_registered", "module_models", "device_models", "inverter_models" @@ -3120,7 +3778,10 @@ "enum": [ "device", "inverter", - "edge" + "edge", + "panel", + "panel_group", + "sensor" ], "examples": [ "device" @@ -3142,7 +3803,10 @@ "edge", "inverter", "combiner", - "panel" + "panel", + "panel_group", + "tracker", + "sensor" ], "examples": [ "panel" @@ -4474,10 +5138,10 @@ ] } }, - "/api/v3/plants/{plant_id}/indicator/device-state": { + "/api/v3/plants/{plant_id}/blueprints": { "get": { - "description": "Retrieves device or panel state indicator data at 5-minute interval. Use the `kind` query parameter with one of: seqnum, relay, rsd.", - "operationId": "get_device_state", + "description": "Lists blueprint records for a specific plant without including each record's data payload. Authorization header and Account-Type header are required.", + "operationId": "list_plant_blueprints", "parameters": [ { "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", @@ -4505,64 +5169,38 @@ } }, { - "description": "Succeeds when none of the supplied ETags match the current representation.", - "in": "header", - "name": "If-None-Match", - "schema": { - "description": "Succeeds when none of the supplied ETags match the current representation.", - "items": { - "type": "string" - }, - "type": [ - "array", - "null" - ] - } - }, - { - "description": "The ID of the plant.", + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation to list blueprint records for. Must be exactly 15 characters in length.", "in": "path", "name": "plant_id", "required": true, "schema": { - "description": "The ID of the plant.", - "type": "string" - } - }, - { - "description": "Target date (YYYY-MM-DD).", - "explode": false, - "in": "query", - "name": "date", - "required": true, - "schema": { - "description": "Target date (YYYY-MM-DD).", + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation to list blueprint records for. Must be exactly 15 characters in length.", "examples": [ - "2025-08-14" - ], - "format": "date", - "type": "string" - } - }, - { - "description": "Indicator kind to retrieve. One of: seqnum, relay, rsd.", - "explode": false, - "in": "query", - "name": "kind", - "required": true, - "schema": { - "description": "Indicator kind to retrieve. One of: seqnum, relay, rsd.", - "enum": [ - "seqnum", - "relay", - "rsd" + "unw4id41ud2p0wt" ], + "maxLength": 15, + "minLength": 15, + "patternDescription": "alphanum", "type": "string" } } ], "responses": { "200": { + "content": { + "application/json": { + "schema": { + "description": "Blueprint records without data payloads.", + "items": { + "$ref": "#/components/schemas/BlueprintListItem" + }, + "type": [ + "array", + "null" + ] + } + } + }, "description": "OK" }, "default": { @@ -4581,16 +5219,16 @@ "bearer": [] } ], - "summary": "Retrieve Device State (5m avg)", + "summary": "List Plant Blueprint Records", "tags": [ - "v3/plants/indicator" + "v3/plants/blueprints" ] } }, - "/api/v3/plants/{plant_id}/indicator/health-level/{unit}": { + "/api/v3/plants/{plant_id}/blueprints/{blueprint_id}": { "get": { - "description": "Calculates panel health indicators from daily energy production. The response reports the top ten panels as 'best' and reports panels outside the top ten only when they fall into 'caution' or 'faulty' thresholds.", - "operationId": "get_asset_health_level", + "description": "Retrieves a specific blueprint record on a plant, including record metadata and the data payload. Authorization header and Account-Type header are required.", + "operationId": "get_plant_blueprint_data", "parameters": [ { "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", @@ -4618,74 +5256,81 @@ } }, { - "description": "Succeeds when none of the supplied ETags match the current representation.", - "in": "header", - "name": "If-None-Match", - "schema": { - "description": "Succeeds when none of the supplied ETags match the current representation.", - "items": { - "type": "string" - }, - "type": [ - "array", - "null" - ] - } - }, - { - "description": "The ID of the plant to calculate health levels for.", + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation to fetch blueprint data for. Must be exactly 15 characters in length.", "in": "path", "name": "plant_id", "required": true, "schema": { - "description": "The ID of the plant to calculate health levels for.", + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation to fetch blueprint data for. Must be exactly 15 characters in length.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "patternDescription": "alphanum", "type": "string" } }, { - "description": "The unit to calculate health levels for (e.g., panel).", + "description": "Blueprint record ID.", "in": "path", - "name": "unit", + "name": "blueprint_id", "required": true, "schema": { - "default": "panel", - "description": "The unit to calculate health levels for (e.g., panel).", + "description": "Blueprint record ID.", "examples": [ - "panel" + "blueprint123456" ], "type": "string" } }, { - "description": "The specific date for health level calculation (YYYY-MM-DD).", - "explode": false, - "in": "query", - "name": "date", - "required": true, + "description": "Succeeds if the server's resource matches one of the passed values.", + "in": "header", + "name": "If-Match", "schema": { - "description": "The specific date for health level calculation (YYYY-MM-DD).", - "examples": [ - "2025-08-14" - ], - "format": "date", + "description": "Succeeds if the server's resource matches one of the passed values.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "in": "header", + "name": "If-None-Match", + "schema": { + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "Succeeds if the server's resource date is more recent than the passed date.", + "in": "header", + "name": "If-Modified-Since", + "schema": { + "description": "Succeeds if the server's resource date is more recent than the passed date.", + "format": "date-time-http", "type": "string" } }, { - "description": "The view type for the response (summary or detail).", - "explode": false, - "in": "query", - "name": "view", + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "in": "header", + "name": "If-Unmodified-Since", "schema": { - "default": "summary", - "description": "The view type for the response (summary or detail).", - "enum": [ - "summary", - "detail" - ], - "examples": [ - "summary" - ], + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "format": "date-time-http", "type": "string" } } @@ -4695,14 +5340,67 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/HealthLevelBody" + "description": "Blueprint record. The data field contains the stored blueprint payload, which can be an object or an array.", + "properties": { + "created": { + "description": "Blueprint record creation timestamp.", + "type": "string" + }, + "data": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "items": { + "additionalProperties": true, + "type": "object" + }, + "type": "array" + } + ], + "description": "Blueprint data payload." + }, + "date": { + "description": "Blueprint effective timestamp.", + "type": "string" + }, + "id": { + "description": "Blueprint record ID.", + "type": "string" + }, + "metadata": { + "additionalProperties": true, + "description": "Blueprint record metadata.", + "type": "object" + }, + "plant": { + "description": "Requested plant ID.", + "type": "string" + }, + "updated": { + "description": "Blueprint record update timestamp.", + "type": "string" + } + }, + "required": [ + "id", + "plant", + "date", + "updated", + "metadata", + "data" + ], + "type": "object" } } }, - "description": "OK", + "description": "Blueprint record with metadata and data payload.", "headers": { "ETag": { "schema": { + "description": "Weak entity tag for conditional requests.", "type": "string" } } @@ -4724,16 +5422,16 @@ "bearer": [] } ], - "summary": "Retrieve Panel Health Levels", + "summary": "Retrieve Plant Blueprint Data By Record ID", "tags": [ - "v3/plants/indicator" + "v3/plants/blueprints" ] } }, - "/api/v3/plants/{plant_id}/logs/inverter": { + "/api/v3/plants/{plant_id}/indicator/device-state": { "get": { - "description": "Retrieves paginated log entries for all inverters within a plant. Includes status messages, error codes, timestamps, and raw log data with Korean message translations.", - "operationId": "list_inverter_logs", + "description": "Retrieves device or panel state indicator data at 5-minute intervals. Use the kind query parameter to select the indicator (seqnum, relay, rsd, or count). Data row fields vary by kind: count rows include edge_id, id, timestamp, date, and count; seqnum rows include id, timestamp, avg_seqnum, and min_seqnum; relay rows include id, date, timestamp, is_relay, and is_forced_relay; rsd rows include id, date, timestamp, is_rsd, and is_forced_rsd.", + "operationId": "get_device_state", "parameters": [ { "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", @@ -4761,58 +5459,60 @@ } }, { - "description": "Plant ID. A unique alphanumeric identifier representing the plant to fetch data for. Must be exactly 15 characters in length.", + "description": "Succeeds when none of the supplied ETags match the current representation.", + "in": "header", + "name": "If-None-Match", + "schema": { + "description": "Succeeds when none of the supplied ETags match the current representation.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "The ID of the plant.", "in": "path", "name": "plant_id", "required": true, "schema": { - "description": "Plant ID. A unique alphanumeric identifier representing the plant to fetch data for. Must be exactly 15 characters in length.", - "examples": [ - "bsajtokt84s2byf" - ], + "description": "The ID of the plant.", "type": "string" } }, { - "description": "The page number for pagination. This allows the user to retrieve a specific subset of data from the total available records. The default value is 1, indicating the first page.", + "description": "Target date (YYYY-MM-DD).", "explode": false, "in": "query", - "name": "page", + "name": "date", + "required": true, "schema": { - "default": 1, - "description": "The page number for pagination. This allows the user to retrieve a specific subset of data from the total available records. The default value is 1, indicating the first page.", - "format": "int64", - "minimum": 1, - "type": "integer" + "description": "Target date (YYYY-MM-DD).", + "examples": [ + "2025-08-14" + ], + "format": "date", + "type": "string" } }, { - "description": "The number of records to retrieve per page. This parameter allows for pagination, enabling the user to control the amount of data returned in each request. The default value is 100.", + "description": "Indicator kind to retrieve. One of: seqnum, relay, rsd, count.", "explode": false, "in": "query", - "name": "size", - "schema": { - "default": 100, - "description": "The number of records to retrieve per page. This parameter allows for pagination, enabling the user to control the amount of data returned in each request. The default value is 100.", - "format": "int64", - "maximum": 1000, - "minimum": 1, - "type": "integer" - } - }, - { - "description": "Succeeds when none of the supplied ETags match the current representation.", - "in": "header", - "name": "If-None-Match", + "name": "kind", + "required": true, "schema": { - "description": "Succeeds when none of the supplied ETags match the current representation.", - "items": { - "type": "string" - }, - "type": [ - "array", - "null" - ] + "description": "Indicator kind to retrieve. One of: seqnum, relay, rsd, count.", + "enum": [ + "seqnum", + "relay", + "rsd", + "count" + ], + "type": "string" } } ], @@ -4821,11 +5521,46 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/InverterLogsResponse" + "description": "Device state response envelope. The data row shape depends on kind; count rows include edge_id, id, timestamp, date, and count.", + "properties": { + "data": { + "description": "Indicator rows. The structure of each item depends on the requested kind: count rows include edge_id, id, timestamp, date, and count; seqnum rows include id, timestamp, avg_seqnum, and min_seqnum; relay rows include id, date, timestamp, is_relay, and is_forced_relay; rsd rows include id, date, timestamp, is_rsd, and is_forced_rsd.", + "items": { + "additionalProperties": true, + "type": "object" + }, + "type": "array" + }, + "date": { + "description": "Requested local date.", + "type": "string" + }, + "kind": { + "description": "Indicator kind: seqnum, relay, rsd, or count.", + "enum": [ + "seqnum", + "relay", + "rsd", + "count" + ], + "type": "string" + }, + "plant_id": { + "description": "Requested plant ID.", + "type": "string" + } + }, + "required": [ + "plant_id", + "date", + "kind", + "data" + ], + "type": "object" } } }, - "description": "OK", + "description": "Gzip JSON envelope containing indicator data. The data row structure varies by kind (e.g., count rows include edge_id, id, timestamp, date, and count).", "headers": { "ETag": { "schema": { @@ -4851,16 +5586,16 @@ "bearer": [] } ], - "summary": "Retrieve Inverter Log List with Pagination", + "summary": "Retrieve Device State (5m)", "tags": [ - "v3/plants/logs" + "v3/plants/indicator" ] } }, - "/api/v3/plants/{plant_id}/logs/inverters/{inverter_id}": { + "/api/v3/plants/{plant_id}/indicator/health-level/{unit}": { "get": { - "description": "Retrieves paginated log entries for a specific inverter within a plant. Includes status messages, error codes, timestamps, and raw log data with Korean message translations.", - "operationId": "list_inverter_logs_by_id", + "description": "Calculates panel health indicators from daily energy production. The response reports the top ten panels as 'best' and reports panels outside the top ten only when they fall into 'caution' or 'faulty' thresholds.", + "operationId": "get_asset_health_level", "parameters": [ { "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", @@ -4888,68 +5623,75 @@ } }, { - "description": "Plant ID. A unique alphanumeric identifier representing the plant to fetch data for. Must be exactly 15 characters in length.", + "description": "Succeeds when none of the supplied ETags match the current representation.", + "in": "header", + "name": "If-None-Match", + "schema": { + "description": "Succeeds when none of the supplied ETags match the current representation.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "The ID of the plant to calculate health levels for.", "in": "path", "name": "plant_id", "required": true, "schema": { - "description": "Plant ID. A unique alphanumeric identifier representing the plant to fetch data for. Must be exactly 15 characters in length.", - "examples": [ - "bsajtokt84s2byf" - ], + "description": "The ID of the plant to calculate health levels for.", "type": "string" } }, { - "description": "Inverter ID.", + "description": "The unit to calculate health levels for (e.g., panel).", "in": "path", - "name": "inverter_id", + "name": "unit", "required": true, "schema": { - "description": "Inverter ID.", + "default": "panel", + "description": "The unit to calculate health levels for (e.g., panel).", + "examples": [ + "panel" + ], "type": "string" } }, { - "description": "The page number for pagination. This allows the user to retrieve a specific subset of data from the total available records. The default value is 1, indicating the first page.", + "description": "The specific date for health level calculation (YYYY-MM-DD).", "explode": false, "in": "query", - "name": "page", + "name": "date", + "required": true, "schema": { - "default": 1, - "description": "The page number for pagination. This allows the user to retrieve a specific subset of data from the total available records. The default value is 1, indicating the first page.", - "format": "int64", - "minimum": 1, - "type": "integer" + "description": "The specific date for health level calculation (YYYY-MM-DD).", + "examples": [ + "2025-08-14" + ], + "format": "date", + "type": "string" } }, { - "description": "The number of records to retrieve per page. This parameter allows for pagination, enabling the user to control the amount of data returned in each request. The default value is 100.", + "description": "The view type for the response (summary or detail).", "explode": false, "in": "query", - "name": "size", - "schema": { - "default": 100, - "description": "The number of records to retrieve per page. This parameter allows for pagination, enabling the user to control the amount of data returned in each request. The default value is 100.", - "format": "int64", - "maximum": 1000, - "minimum": 1, - "type": "integer" - } - }, - { - "description": "Succeeds when none of the supplied ETags match the current representation.", - "in": "header", - "name": "If-None-Match", + "name": "view", "schema": { - "description": "Succeeds when none of the supplied ETags match the current representation.", - "items": { - "type": "string" - }, - "type": [ - "array", - "null" - ] + "default": "summary", + "description": "The view type for the response (summary or detail).", + "enum": [ + "summary", + "detail" + ], + "examples": [ + "summary" + ], + "type": "string" } } ], @@ -4958,7 +5700,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/InverterLogsResponse" + "$ref": "#/components/schemas/HealthLevelBody" } } }, @@ -4966,7 +5708,6 @@ "headers": { "ETag": { "schema": { - "description": "Weak entity tag for conditional requests.", "type": "string" } } @@ -4988,16 +5729,16 @@ "bearer": [] } ], - "summary": "Retrieve Specific Inverter Logs", + "summary": "Retrieve Panel Health Levels", "tags": [ - "v3/plants/logs" + "v3/plants/indicator" ] } }, - "/api/v3/plants/{plant_id}/metrics/device/latest": { + "/api/v3/plants/{plant_id}/logs/inverter": { "get": { - "description": "Retrieves the most recent metrics data for all devices (panels) in the specified plant. Includes current, voltage, temperature, and status information.", - "operationId": "get_latest_device_metrics", + "description": "Retrieves paginated log entries for all inverters within a plant. Includes status messages, error codes, timestamps, and raw log data with Korean message translations.", + "operationId": "list_inverter_logs", "parameters": [ { "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", @@ -5032,61 +5773,44 @@ "schema": { "description": "Plant ID. A unique alphanumeric identifier representing the plant to fetch data for. Must be exactly 15 characters in length.", "examples": [ - "unw4id41ud2p0wt" + "bsajtokt84s2byf" ], - "maxLength": 15, - "minLength": 15, - "patternDescription": "alphanum", "type": "string" } }, { + "description": "The page number for pagination. This allows the user to retrieve a specific subset of data from the total available records. The default value is 1, indicating the first page.", "explode": false, "in": "query", - "name": "includeState", + "name": "page", "schema": { - "default": false, - "type": "boolean" + "default": 1, + "description": "The page number for pagination. This allows the user to retrieve a specific subset of data from the total available records. The default value is 1, indicating the first page.", + "format": "int64", + "minimum": 1, + "type": "integer" } }, { - "description": "The time range in minutes for filtering active devices. Only devices that have sent data within the last 'ago' minutes will be included in the response. This helps exclude inactive or unresponsive devices. The maximum allowed value is 600 minutes.", + "description": "The number of records to retrieve per page. This parameter allows for pagination, enabling the user to control the amount of data returned in each request. The default value is 100.", "explode": false, "in": "query", - "name": "ago", + "name": "size", "schema": { - "default": 15, - "description": "The time range in minutes for filtering active devices. Only devices that have sent data within the last 'ago' minutes will be included in the response. This helps exclude inactive or unresponsive devices. The maximum allowed value is 600 minutes.", - "examples": [ - 15 - ], + "default": 100, + "description": "The number of records to retrieve per page. This parameter allows for pagination, enabling the user to control the amount of data returned in each request. The default value is 100.", "format": "int64", - "maximum": 600, + "maximum": 1000, "minimum": 1, "type": "integer" } }, { - "description": "Succeeds if the server's resource matches one of the passed values.", - "in": "header", - "name": "If-Match", - "schema": { - "description": "Succeeds if the server's resource matches one of the passed values.", - "items": { - "type": "string" - }, - "type": [ - "array", - "null" - ] - } - }, - { - "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "description": "Succeeds when none of the supplied ETags match the current representation.", "in": "header", "name": "If-None-Match", "schema": { - "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "description": "Succeeds when none of the supplied ETags match the current representation.", "items": { "type": "string" }, @@ -5095,26 +5819,6 @@ "null" ] } - }, - { - "description": "Succeeds if the server's resource date is more recent than the passed date.", - "in": "header", - "name": "If-Modified-Since", - "schema": { - "description": "Succeeds if the server's resource date is more recent than the passed date.", - "format": "date-time-http", - "type": "string" - } - }, - { - "description": "Succeeds if the server's resource date is older or the same as the passed date.", - "in": "header", - "name": "If-Unmodified-Since", - "schema": { - "description": "Succeeds if the server's resource date is older or the same as the passed date.", - "format": "date-time-http", - "type": "string" - } } ], "responses": { @@ -5122,13 +5826,7 @@ "content": { "application/json": { "schema": { - "items": { - "$ref": "#/components/schemas/LatestDeviceBody" - }, - "type": [ - "array", - "null" - ] + "$ref": "#/components/schemas/InverterLogsResponse" } } }, @@ -5136,7 +5834,7 @@ "headers": { "ETag": { "schema": { - "description": "Weak entity tag for conditional requests", + "description": "Weak entity tag for conditional requests.", "type": "string" } } @@ -5158,16 +5856,16 @@ "bearer": [] } ], - "summary": "Retrieve Latest Device Metrics", + "summary": "Retrieve Inverter Log List with Pagination", "tags": [ - "v3/plants/metrics" + "v3/plants/logs" ] } }, - "/api/v3/plants/{plant_id}/metrics/inverter/latest": { + "/api/v3/plants/{plant_id}/logs/inverters/{inverter_id}": { "get": { - "description": "Retrieves the most recent metrics data for all inverters in the specified plant. Includes logs, status, daily/total energy production, and operational information.", - "operationId": "get_latest_inverter_metrics", + "description": "Retrieves paginated log entries for a specific inverter within a plant. Includes status messages, error codes, timestamps, and raw log data with Korean message translations.", + "operationId": "list_inverter_logs_by_id", "parameters": [ { "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", @@ -5208,53 +5906,55 @@ } }, { - "description": "Succeeds if the server's resource matches one of the passed values.", - "in": "header", - "name": "If-Match", + "description": "Inverter ID.", + "in": "path", + "name": "inverter_id", + "required": true, "schema": { - "description": "Succeeds if the server's resource matches one of the passed values.", - "items": { - "type": "string" - }, - "type": [ - "array", - "null" - ] - } + "description": "Inverter ID.", + "type": "string" + } }, { - "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", - "in": "header", - "name": "If-None-Match", + "description": "The page number for pagination. This allows the user to retrieve a specific subset of data from the total available records. The default value is 1, indicating the first page.", + "explode": false, + "in": "query", + "name": "page", "schema": { - "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", - "items": { - "type": "string" - }, - "type": [ - "array", - "null" - ] + "default": 1, + "description": "The page number for pagination. This allows the user to retrieve a specific subset of data from the total available records. The default value is 1, indicating the first page.", + "format": "int64", + "minimum": 1, + "type": "integer" } }, { - "description": "Succeeds if the server's resource date is more recent than the passed date.", - "in": "header", - "name": "If-Modified-Since", + "description": "The number of records to retrieve per page. This parameter allows for pagination, enabling the user to control the amount of data returned in each request. The default value is 100.", + "explode": false, + "in": "query", + "name": "size", "schema": { - "description": "Succeeds if the server's resource date is more recent than the passed date.", - "format": "date-time-http", - "type": "string" + "default": 100, + "description": "The number of records to retrieve per page. This parameter allows for pagination, enabling the user to control the amount of data returned in each request. The default value is 100.", + "format": "int64", + "maximum": 1000, + "minimum": 1, + "type": "integer" } }, { - "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "description": "Succeeds when none of the supplied ETags match the current representation.", "in": "header", - "name": "If-Unmodified-Since", + "name": "If-None-Match", "schema": { - "description": "Succeeds if the server's resource date is older or the same as the passed date.", - "format": "date-time-http", - "type": "string" + "description": "Succeeds when none of the supplied ETags match the current representation.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] } } ], @@ -5263,13 +5963,7 @@ "content": { "application/json": { "schema": { - "items": { - "$ref": "#/components/schemas/InverterDataBody" - }, - "type": [ - "array", - "null" - ] + "$ref": "#/components/schemas/InverterLogsResponse" } } }, @@ -5277,7 +5971,7 @@ "headers": { "ETag": { "schema": { - "description": "Weak entity tag for conditional requests", + "description": "Weak entity tag for conditional requests.", "type": "string" } } @@ -5299,16 +5993,16 @@ "bearer": [] } ], - "summary": "Retrieve Latest Inverter Metrics", + "summary": "Retrieve Specific Inverter Logs", "tags": [ - "v3/plants/metrics" + "v3/plants/logs" ] } }, - "/api/v3/plants/{plant_id}/metrics/{source}/{unit}-{interval}": { + "/api/v3/plants/{plant_id}/metrics/device/latest": { "get": { - "description": "Retrieves comprehensive time-series metrics data for a specific plant with configurable data source, aggregation unit, and time interval. Supports various combinations of panel, inverter, string, and plant-level data aggregation across different time intervals.", - "operationId": "get_metrics_by_date", + "description": "Retrieves the most recent metrics data for all devices (panels) in the specified plant. Includes current, voltage, temperature, and status information.", + "operationId": "get_latest_device_metrics", "parameters": [ { "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", @@ -5336,27 +6030,12 @@ } }, { - "description": "Succeeds when none of the supplied ETags match the current representation.", - "in": "header", - "name": "If-None-Match", - "schema": { - "description": "Succeeds when none of the supplied ETags match the current representation.", - "items": { - "type": "string" - }, - "type": [ - "array", - "null" - ] - } - }, - { - "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation to fetch metrics data for. Must be exactly 15 characters in length.", + "description": "Plant ID. A unique alphanumeric identifier representing the plant to fetch data for. Must be exactly 15 characters in length.", "in": "path", "name": "plant_id", "required": true, "schema": { - "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation to fetch metrics data for. Must be exactly 15 characters in length.", + "description": "Plant ID. A unique alphanumeric identifier representing the plant to fetch data for. Must be exactly 15 characters in length.", "examples": [ "unw4id41ud2p0wt" ], @@ -5367,115 +6046,37 @@ } }, { - "description": "Data source type. Indicates the origin of the data collection system. 'device' refers to panel-level monitoring devices, 'inverter' refers to inverter-level data collection, and 'sensor' refers to sensor data collection.", - "in": "path", - "name": "source", - "required": true, - "schema": { - "default": "device", - "description": "Data source type. Indicates the origin of the data collection system. 'device' refers to panel-level monitoring devices, 'inverter' refers to inverter-level data collection, and 'sensor' refers to sensor data collection.", - "enum": [ - "device", - "inverter", - "sensor" - ], - "examples": [ - "device" - ], - "type": "string" - } - }, - { - "description": "Data aggregation unit. Specifies the hierarchical level of data aggregation within the solar installation. 'panel' provides individual panel data, 'inverter' aggregates by inverter, 'string' aggregates by string configuration, 'plant' provides plant-wide aggregated data, and 'temperature'/'insolation' are sensor-specific units.", - "in": "path", - "name": "unit", - "required": true, - "schema": { - "default": "plant", - "description": "Data aggregation unit. Specifies the hierarchical level of data aggregation within the solar installation. 'panel' provides individual panel data, 'inverter' aggregates by inverter, 'string' aggregates by string configuration, 'plant' provides plant-wide aggregated data, and 'temperature'/'insolation' are sensor-specific units.", - "enum": [ - "panel", - "inverter", - "string", - "plant", - "temperature", - "insolation" - ], - "examples": [ - "plant" - ], - "type": "string" - } - }, - { - "description": "Time interval for data aggregation. Determines the temporal granularity of the returned time-series data. Supported intervals: '5m' (5 minutes), '15m' (15 minutes), '1h' (1 hour), '1d' (1 day), '1M' (1 month), '1y' (1 year).", - "in": "path", - "name": "interval", - "required": true, - "schema": { - "description": "Time interval for data aggregation. Determines the temporal granularity of the returned time-series data. Supported intervals: '5m' (5 minutes), '15m' (15 minutes), '1h' (1 hour), '1d' (1 day), '1M' (1 month), '1y' (1 year).", - "enum": [ - "5m", - "15m", - "1h", - "1d", - "1M", - "1y" - ], - "examples": [ - "5m" - ], - "type": "string" - } - }, - { - "description": "Target date for data retrieval. The specific date for which you want to retrieve solar plant metrics data. Must follow the ISO 8601 date format 'YYYY-MM-DD'.", "explode": false, "in": "query", - "name": "date", - "required": true, + "name": "includeState", "schema": { - "description": "Target date for data retrieval. The specific date for which you want to retrieve solar plant metrics data. Must follow the ISO 8601 date format 'YYYY-MM-DD'.", - "examples": [ - "2024-01-24" - ], - "format": "date", - "type": "string" + "default": false, + "type": "boolean" } }, { - "description": "Historical data range. Number of time intervals before the specified date to include in the response. This parameter allows retrieval of historical trend data. Note: Only applicable for daily and longer intervals (1d, 1M, 1y), not for intraday intervals (5m, 15m, 1h).", + "description": "The time range in minutes for filtering active devices. Only devices that have sent data within the last 'ago' minutes will be included in the response. This helps exclude inactive or unresponsive devices. The maximum allowed value is 600 minutes.", "explode": false, "in": "query", - "name": "before", + "name": "ago", "schema": { - "default": 1, - "description": "Historical data range. Number of time intervals before the specified date to include in the response. This parameter allows retrieval of historical trend data. Note: Only applicable for daily and longer intervals (1d, 1M, 1y), not for intraday intervals (5m, 15m, 1h).", + "default": 15, + "description": "The time range in minutes for filtering active devices. Only devices that have sent data within the last 'ago' minutes will be included in the response. This helps exclude inactive or unresponsive devices. The maximum allowed value is 600 minutes.", "examples": [ - 1 + 15 ], "format": "int64", - "maximum": 100, + "maximum": 600, "minimum": 1, "type": "integer" } }, { - "description": "Data fields selection. Specifies which metrics or parameters to include in the response. Use 'all' to retrieve all available measurement fields, or specify individual field names (e.g., 'i_out' for output current, 'p' for power, 'energy' for energy production).", - "explode": false, - "in": "query", - "name": "fields", + "description": "Succeeds if the server's resource matches one of the passed values.", + "in": "header", + "name": "If-Match", "schema": { - "default": [ - "all" - ], - "description": "Data fields selection. Specifies which metrics or parameters to include in the response. Use 'all' to retrieve all available measurement fields, or specify individual field names (e.g., 'i_out' for output current, 'p' for power, 'energy' for energy production).", - "examples": [ - [ - "i_out", - "p" - ] - ], + "description": "Succeeds if the server's resource matches one of the passed values.", "items": { "type": "string" }, @@ -5486,18 +6087,11 @@ } }, { - "description": "Device panel or inverter ID filters. Supported only for intraday device/panel and inverter/inverter requests (5m, 15m, 1h). Multiple id query parameters are allowed (e.g., id=pnl-001&id=pnl-002).", - "explode": false, - "in": "query", - "name": "id", + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "in": "header", + "name": "If-None-Match", "schema": { - "description": "Device panel or inverter ID filters. Supported only for intraday device/panel and inverter/inverter requests (5m, 15m, 1h). Multiple id query parameters are allowed (e.g., id=pnl-001&id=pnl-002).", - "examples": [ - [ - "pnl-001", - "pnl-002" - ] - ], + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", "items": { "type": "string" }, @@ -5506,6 +6100,26 @@ "null" ] } + }, + { + "description": "Succeeds if the server's resource date is more recent than the passed date.", + "in": "header", + "name": "If-Modified-Since", + "schema": { + "description": "Succeeds if the server's resource date is more recent than the passed date.", + "format": "date-time-http", + "type": "string" + } + }, + { + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "in": "header", + "name": "If-Unmodified-Since", + "schema": { + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "format": "date-time-http", + "type": "string" + } } ], "responses": { @@ -5513,39 +6127,534 @@ "content": { "application/json": { "schema": { - "oneOf": [ - { - "additionalProperties": false, - "description": "Time-series metrics for individual panels at 5-minute, 15-minute, and 1-hour intervals.", - "properties": { - "before": { - "description": "Number of historical intervals included in the response", - "format": "int64", - "type": "integer" - }, - "data": { - "description": "Array of time-series data points matching the specified parameters", - "items": { - "$ref": "#/components/schemas/PanelData" - }, - "type": [ - "array", - "null" - ] - }, - "date": { - "description": "Target date for the data retrieval", - "type": "string" - }, - "interval": { - "description": "Time interval used for data aggregation", - "type": "string" - }, - "plant_id": { - "description": "Plant identifier that was queried", - "type": "string" - }, - "source": { + "items": { + "$ref": "#/components/schemas/LatestDeviceBody" + }, + "type": [ + "array", + "null" + ] + } + } + }, + "description": "OK", + "headers": { + "ETag": { + "schema": { + "description": "Weak entity tag for conditional requests", + "type": "string" + } + } + } + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Retrieve Latest Device Metrics", + "tags": [ + "v3/plants/metrics" + ] + } + }, + "/api/v3/plants/{plant_id}/metrics/inverter/latest": { + "get": { + "description": "Retrieves the most recent metrics data for all inverters in the specified plant. Includes logs, status, daily/total energy production, and operational information.", + "operationId": "get_latest_inverter_metrics", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "enum": [ + "viewer", + "manager", + "admin" + ], + "type": "string" + } + }, + { + "description": "Plant ID. A unique alphanumeric identifier representing the plant to fetch data for. Must be exactly 15 characters in length.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Plant ID. A unique alphanumeric identifier representing the plant to fetch data for. Must be exactly 15 characters in length.", + "examples": [ + "bsajtokt84s2byf" + ], + "type": "string" + } + }, + { + "description": "Succeeds if the server's resource matches one of the passed values.", + "in": "header", + "name": "If-Match", + "schema": { + "description": "Succeeds if the server's resource matches one of the passed values.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "in": "header", + "name": "If-None-Match", + "schema": { + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "Succeeds if the server's resource date is more recent than the passed date.", + "in": "header", + "name": "If-Modified-Since", + "schema": { + "description": "Succeeds if the server's resource date is more recent than the passed date.", + "format": "date-time-http", + "type": "string" + } + }, + { + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "in": "header", + "name": "If-Unmodified-Since", + "schema": { + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "format": "date-time-http", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/InverterDataBody" + }, + "type": [ + "array", + "null" + ] + } + } + }, + "description": "OK", + "headers": { + "ETag": { + "schema": { + "description": "Weak entity tag for conditional requests", + "type": "string" + } + } + } + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Retrieve Latest Inverter Metrics", + "tags": [ + "v3/plants/metrics" + ] + } + }, + "/api/v3/plants/{plant_id}/metrics/{source}/{unit}-{interval}": { + "get": { + "description": "Retrieves comprehensive time-series metrics data for a specific plant with configurable data source, aggregation unit, and time interval. Supports various combinations of panel, inverter, string, ESS, and plant-level data aggregation across different time intervals. ESS supports ess and plant units at 5m, 15m, 1h, and 1d intervals only.", + "operationId": "get_metrics_by_date", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "enum": [ + "viewer", + "manager", + "admin" + ], + "type": "string" + } + }, + { + "description": "Succeeds when none of the supplied ETags match the current representation.", + "in": "header", + "name": "If-None-Match", + "schema": { + "description": "Succeeds when none of the supplied ETags match the current representation.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation to fetch metrics data for. Must be exactly 15 characters in length.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation to fetch metrics data for. Must be exactly 15 characters in length.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "patternDescription": "alphanum", + "type": "string" + } + }, + { + "description": "Data source type. Indicates the origin of the data collection system. 'device' refers to panel-level monitoring devices, 'inverter' refers to inverter-level data collection, 'ess' refers to energy storage system data collection, and 'sensor' refers to sensor data collection. For source 'ess', supported units are 'ess' and 'plant'.", + "in": "path", + "name": "source", + "required": true, + "schema": { + "default": "device", + "description": "Data source type. Indicates the origin of the data collection system. 'device' refers to panel-level monitoring devices, 'inverter' refers to inverter-level data collection, 'ess' refers to energy storage system data collection, and 'sensor' refers to sensor data collection. For source 'ess', supported units are 'ess' and 'plant'.", + "enum": [ + "device", + "inverter", + "ess", + "sensor" + ], + "examples": [ + "device" + ], + "type": "string" + } + }, + { + "description": "Data aggregation unit. Specifies the hierarchical level of data aggregation within the solar installation. 'panel' provides individual panel data, 'inverter' aggregates by inverter, 'ess' provides individual ESS data, 'string' aggregates by string configuration, 'plant' provides plant-wide aggregated data, and 'temperature'/'insolation' are sensor-specific units. Unit 'ess' is valid only with source 'ess'.", + "in": "path", + "name": "unit", + "required": true, + "schema": { + "default": "plant", + "description": "Data aggregation unit. Specifies the hierarchical level of data aggregation within the solar installation. 'panel' provides individual panel data, 'inverter' aggregates by inverter, 'ess' provides individual ESS data, 'string' aggregates by string configuration, 'plant' provides plant-wide aggregated data, and 'temperature'/'insolation' are sensor-specific units. Unit 'ess' is valid only with source 'ess'.", + "enum": [ + "panel", + "inverter", + "ess", + "string", + "plant", + "temperature", + "insolation" + ], + "examples": [ + "plant" + ], + "type": "string" + } + }, + { + "description": "Time interval for data aggregation. Determines the temporal granularity of the returned time-series data. Supported intervals: '5m' (5 minutes), '15m' (15 minutes), '1h' (1 hour), '1d' (1 day), '1M' (1 month), '1y' (1 year). For source 'ess', supported intervals are '5m', '15m', '1h', and '1d'.", + "in": "path", + "name": "interval", + "required": true, + "schema": { + "description": "Time interval for data aggregation. Determines the temporal granularity of the returned time-series data. Supported intervals: '5m' (5 minutes), '15m' (15 minutes), '1h' (1 hour), '1d' (1 day), '1M' (1 month), '1y' (1 year). For source 'ess', supported intervals are '5m', '15m', '1h', and '1d'.", + "enum": [ + "5m", + "15m", + "1h", + "1d", + "1M", + "1y" + ], + "examples": [ + "5m" + ], + "type": "string" + } + }, + { + "description": "Target date for data retrieval. The specific date for which you want to retrieve solar plant metrics data. Must follow the ISO 8601 date format 'YYYY-MM-DD'.", + "explode": false, + "in": "query", + "name": "date", + "required": true, + "schema": { + "description": "Target date for data retrieval. The specific date for which you want to retrieve solar plant metrics data. Must follow the ISO 8601 date format 'YYYY-MM-DD'.", + "examples": [ + "2024-01-24" + ], + "format": "date", + "type": "string" + } + }, + { + "description": "Historical data range. Number of time intervals before the specified date to include in the response. This parameter allows retrieval of historical trend data. Note: Only applicable for daily and longer intervals (1d, 1M, 1y), not for intraday intervals (5m, 15m, 1h). For source 'ess', before ranges are supported only for interval '1d'.", + "explode": false, + "in": "query", + "name": "before", + "schema": { + "default": 1, + "description": "Historical data range. Number of time intervals before the specified date to include in the response. This parameter allows retrieval of historical trend data. Note: Only applicable for daily and longer intervals (1d, 1M, 1y), not for intraday intervals (5m, 15m, 1h). For source 'ess', before ranges are supported only for interval '1d'.", + "examples": [ + 1 + ], + "format": "int64", + "maximum": 100, + "minimum": 1, + "type": "integer" + } + }, + { + "description": "Data fields selection. Specifies which metrics or parameters to include in the response. Use 'all' to retrieve all available measurement fields, or specify individual field names (e.g., 'i_out' for output current, 'p' for power, 'energy' for energy production).", + "explode": false, + "in": "query", + "name": "fields", + "schema": { + "default": [ + "all" + ], + "description": "Data fields selection. Specifies which metrics or parameters to include in the response. Use 'all' to retrieve all available measurement fields, or specify individual field names (e.g., 'i_out' for output current, 'p' for power, 'energy' for energy production).", + "examples": [ + [ + "i_out", + "p" + ] + ], + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "Device panel or inverter ID filters. Supported only for intraday device/panel and inverter/inverter requests (5m, 15m, 1h). Multiple id query parameters are allowed (e.g., id=pnl-001&id=pnl-002).", + "explode": false, + "in": "query", + "name": "id", + "schema": { + "description": "Device panel or inverter ID filters. Supported only for intraday device/panel and inverter/inverter requests (5m, 15m, 1h). Multiple id query parameters are allowed (e.g., id=pnl-001&id=pnl-002).", + "examples": [ + [ + "pnl-001", + "pnl-002" + ] + ], + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "additionalProperties": false, + "description": "Time-series metrics for individual panels at 5-minute, 15-minute, and 1-hour intervals.", + "properties": { + "before": { + "description": "Number of historical intervals included in the response", + "format": "int64", + "type": "integer" + }, + "data": { + "description": "Array of time-series data points matching the specified parameters", + "items": { + "$ref": "#/components/schemas/PanelData" + }, + "type": [ + "array", + "null" + ] + }, + "date": { + "description": "Target date for the data retrieval", + "type": "string" + }, + "interval": { + "description": "Time interval used for data aggregation", + "type": "string" + }, + "plant_id": { + "description": "Plant identifier that was queried", + "type": "string" + }, + "source": { + "description": "Data source type that was queried", + "type": "string" + }, + "unit": { + "description": "Data aggregation unit that was requested", + "type": "string" + } + }, + "required": [ + "plant_id", + "unit", + "source", + "date", + "interval", + "data" + ], + "title": "Panel Intraday Metrics", + "type": "object" + }, + { + "additionalProperties": false, + "description": "Daily aggregated metrics for individual panels at 1-day intervals.", + "properties": { + "before": { + "description": "Number of historical intervals included in the response", + "format": "int64", + "type": "integer" + }, + "data": { + "description": "Array of time-series data points matching the specified parameters", + "items": { + "$ref": "#/components/schemas/PanelDailyData" + }, + "type": [ + "array", + "null" + ] + }, + "date": { + "description": "Target date for the data retrieval", + "type": "string" + }, + "interval": { + "description": "Time interval used for data aggregation", + "type": "string" + }, + "plant_id": { + "description": "Plant identifier that was queried", + "type": "string" + }, + "source": { + "description": "Data source type that was queried", + "type": "string" + }, + "unit": { + "description": "Data aggregation unit that was requested", + "type": "string" + } + }, + "required": [ + "plant_id", + "unit", + "source", + "date", + "interval", + "data" + ], + "title": "Panel Daily Metrics", + "type": "object" + }, + { + "additionalProperties": false, + "description": "Time-series metrics for individual inverters at 5-minute, 15-minute, and 1-hour intervals.", + "properties": { + "before": { + "description": "Number of historical intervals included in the response", + "format": "int64", + "type": "integer" + }, + "data": { + "description": "Array of time-series data points matching the specified parameters", + "items": { + "$ref": "#/components/schemas/InverterData" + }, + "type": [ + "array", + "null" + ] + }, + "date": { + "description": "Target date for the data retrieval", + "type": "string" + }, + "interval": { + "description": "Time interval used for data aggregation", + "type": "string" + }, + "plant_id": { + "description": "Plant identifier that was queried", + "type": "string" + }, + "source": { "description": "Data source type that was queried", "type": "string" }, @@ -5562,12 +6671,12 @@ "interval", "data" ], - "title": "Panel Intraday Metrics", + "title": "Inverter Intraday Metrics", "type": "object" }, { "additionalProperties": false, - "description": "Daily aggregated metrics for individual panels at 1-day intervals.", + "description": "Daily aggregated metrics for individual inverters at 1-day intervals.", "properties": { "before": { "description": "Number of historical intervals included in the response", @@ -5577,7 +6686,7 @@ "data": { "description": "Array of time-series data points matching the specified parameters", "items": { - "$ref": "#/components/schemas/PanelDailyData" + "$ref": "#/components/schemas/InverterDailyData" }, "type": [ "array", @@ -5613,12 +6722,12 @@ "interval", "data" ], - "title": "Panel Daily Metrics", + "title": "Inverter Daily Metrics", "type": "object" }, { "additionalProperties": false, - "description": "Time-series metrics for individual inverters at 5-minute, 15-minute, and 1-hour intervals.", + "description": "Time-series metrics for entire plant at 5-minute, 15-minute, and 1-hour intervals.", "properties": { "before": { "description": "Number of historical intervals included in the response", @@ -5628,7 +6737,7 @@ "data": { "description": "Array of time-series data points matching the specified parameters", "items": { - "$ref": "#/components/schemas/InverterData" + "$ref": "#/components/schemas/PlantData" }, "type": [ "array", @@ -5664,12 +6773,12 @@ "interval", "data" ], - "title": "Inverter Intraday Metrics", + "title": "Plant Intraday Metrics", "type": "object" }, { "additionalProperties": false, - "description": "Daily aggregated metrics for individual inverters at 1-day intervals.", + "description": "Time-series summary metrics for plant sensors at 5-minute intervals.", "properties": { "before": { "description": "Number of historical intervals included in the response", @@ -5679,7 +6788,7 @@ "data": { "description": "Array of time-series data points matching the specified parameters", "items": { - "$ref": "#/components/schemas/InverterDailyData" + "$ref": "#/components/schemas/SensorData" }, "type": [ "array", @@ -5715,12 +6824,12 @@ "interval", "data" ], - "title": "Inverter Daily Metrics", + "title": "Sensor Intraday Metrics", "type": "object" }, { "additionalProperties": false, - "description": "Time-series metrics for entire plant at 5-minute, 15-minute, and 1-hour intervals.", + "description": "Energy storage system unit metrics at 5-minute, 15-minute, and 1-hour intervals.", "properties": { "before": { "description": "Number of historical intervals included in the response", @@ -5730,7 +6839,7 @@ "data": { "description": "Array of time-series data points matching the specified parameters", "items": { - "$ref": "#/components/schemas/PlantData" + "$ref": "#/components/schemas/ESSUnitIntradayData" }, "type": [ "array", @@ -5766,12 +6875,12 @@ "interval", "data" ], - "title": "Plant Intraday Metrics", + "title": "ESS Unit Intraday Metrics", "type": "object" }, { "additionalProperties": false, - "description": "Time-series summary metrics for plant sensors at 5-minute intervals.", + "description": "Energy storage system unit daily metrics at 1-day intervals.", "properties": { "before": { "description": "Number of historical intervals included in the response", @@ -5781,7 +6890,7 @@ "data": { "description": "Array of time-series data points matching the specified parameters", "items": { - "$ref": "#/components/schemas/SensorData" + "$ref": "#/components/schemas/ESSUnitDailyData" }, "type": [ "array", @@ -5817,7 +6926,109 @@ "interval", "data" ], - "title": "Sensor Intraday Metrics", + "title": "ESS Unit Daily Metrics", + "type": "object" + }, + { + "additionalProperties": false, + "description": "Plant-level energy storage system metrics at 5-minute, 15-minute, and 1-hour intervals.", + "properties": { + "before": { + "description": "Number of historical intervals included in the response", + "format": "int64", + "type": "integer" + }, + "data": { + "description": "Array of time-series data points matching the specified parameters", + "items": { + "$ref": "#/components/schemas/ESSPlantIntradayData" + }, + "type": [ + "array", + "null" + ] + }, + "date": { + "description": "Target date for the data retrieval", + "type": "string" + }, + "interval": { + "description": "Time interval used for data aggregation", + "type": "string" + }, + "plant_id": { + "description": "Plant identifier that was queried", + "type": "string" + }, + "source": { + "description": "Data source type that was queried", + "type": "string" + }, + "unit": { + "description": "Data aggregation unit that was requested", + "type": "string" + } + }, + "required": [ + "plant_id", + "unit", + "source", + "date", + "interval", + "data" + ], + "title": "ESS Plant Intraday Metrics", + "type": "object" + }, + { + "additionalProperties": false, + "description": "Plant-level energy storage system daily metrics at 1-day intervals.", + "properties": { + "before": { + "description": "Number of historical intervals included in the response", + "format": "int64", + "type": "integer" + }, + "data": { + "description": "Array of time-series data points matching the specified parameters", + "items": { + "$ref": "#/components/schemas/ESSPlantDailyData" + }, + "type": [ + "array", + "null" + ] + }, + "date": { + "description": "Target date for the data retrieval", + "type": "string" + }, + "interval": { + "description": "Time interval used for data aggregation", + "type": "string" + }, + "plant_id": { + "description": "Plant identifier that was queried", + "type": "string" + }, + "source": { + "description": "Data source type that was queried", + "type": "string" + }, + "unit": { + "description": "Data aggregation unit that was requested", + "type": "string" + } + }, + "required": [ + "plant_id", + "unit", + "source", + "date", + "interval", + "data" + ], + "title": "ESS Plant Daily Metrics", "type": "object" }, { @@ -5874,8 +7085,389 @@ ] } } - }, - "description": "Successful response. The structure varies depending on the request parameters and will be one of the following schemas." + }, + "description": "Successful response. The structure varies depending on the request parameters and will be one of the following schemas." + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Retrieve Time-Series Metrics Data", + "tags": [ + "v3/plants/metrics" + ] + } + }, + "/api/v3/plants/{plant_id}/registry": { + "get": { + "description": "Retrieves the registry timeline for a date by combining snapshots from the previous date with logs from the requested date.", + "operationId": "get_plant_registry_timeline", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "enum": [ + "viewer", + "manager", + "admin" + ], + "type": "string" + } + }, + { + "description": "Patch Plant ID. A unique alphanumeric identifier representing the plant to fetch data for. Must be exactly 15 characters in length.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Patch Plant ID. A unique alphanumeric identifier representing the plant to fetch data for. Must be exactly 15 characters in length.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "patternDescription": "alphanum", + "type": "string" + } + }, + { + "description": "Target date for registry timeline data. Must follow the format 'YYYY-MM-DD'.", + "explode": false, + "in": "query", + "name": "date", + "required": true, + "schema": { + "description": "Target date for registry timeline data. Must follow the format 'YYYY-MM-DD'.", + "examples": [ + "2024-01-24" + ], + "format": "date", + "type": "string" + } + }, + { + "description": "Succeeds if the server's resource matches one of the passed values.", + "in": "header", + "name": "If-Match", + "schema": { + "description": "Succeeds if the server's resource matches one of the passed values.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "in": "header", + "name": "If-None-Match", + "schema": { + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "Succeeds if the server's resource date is more recent than the passed date.", + "in": "header", + "name": "If-Modified-Since", + "schema": { + "description": "Succeeds if the server's resource date is more recent than the passed date.", + "format": "date-time-http", + "type": "string" + } + }, + { + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "in": "header", + "name": "If-Unmodified-Since", + "schema": { + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "format": "date-time-http", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Array of asset registration records for the specified plant and date", + "items": { + "$ref": "#/components/schemas/RegistryOutputBody" + }, + "type": [ + "array", + "null" + ] + } + } + }, + "description": "OK", + "headers": { + "ETag": { + "schema": { + "description": "Weak entity tag for conditional requests.", + "type": "string" + } + } + } + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Retrieve Plant Registry Timeline", + "tags": [ + "v3/plants/registry" + ] + } + }, + "/api/v3/plants/{plant_id}/registry/logs": { + "get": { + "description": "Retrieves registry log records for the specified plant and date using the explicit patch-registry logs path shape.", + "operationId": "get_plant_registry_logs", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "enum": [ + "viewer", + "manager", + "admin" + ], + "type": "string" + } + }, + { + "description": "Patch Plant ID. A unique alphanumeric identifier representing the plant to fetch data for. Must be exactly 15 characters in length.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Patch Plant ID. A unique alphanumeric identifier representing the plant to fetch data for. Must be exactly 15 characters in length.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "patternDescription": "alphanum", + "type": "string" + } + }, + { + "description": "Target date of data. Must follow the format 'YYYY-MM-DD'.", + "explode": false, + "in": "query", + "name": "date", + "required": true, + "schema": { + "description": "Target date of data. Must follow the format 'YYYY-MM-DD'.", + "examples": [ + "2024-01-24" + ], + "format": "date", + "type": "string" + } + }, + { + "description": "Optional asset ID filter.", + "explode": false, + "in": "query", + "name": "asset_id", + "schema": { + "description": "Optional asset ID filter.", + "pattern": "^[a-zA-Z0-9.\\-_ /:@+]*$", + "type": "string" + } + }, + { + "description": "Optional map ID filter.", + "explode": false, + "in": "query", + "name": "map_id", + "schema": { + "description": "Optional map ID filter.", + "pattern": "^[a-zA-Z0-9.\\-_ /:@+]*$", + "type": "string" + } + }, + { + "description": "Optional asset type filter.", + "explode": false, + "in": "query", + "name": "asset_type", + "schema": { + "description": "Optional asset type filter.", + "enum": [ + "device", + "inverter", + "edge", + "panel", + "panel_group", + "sensor" + ], + "type": "string" + } + }, + { + "description": "Optional map type filter.", + "explode": false, + "in": "query", + "name": "map_type", + "schema": { + "description": "Optional map type filter.", + "enum": [ + "device", + "string", + "edge", + "inverter", + "combiner", + "panel", + "panel_group", + "tracker", + "sensor" + ], + "type": "string" + } + }, + { + "description": "Succeeds if the server's resource matches one of the passed values.", + "in": "header", + "name": "If-Match", + "schema": { + "description": "Succeeds if the server's resource matches one of the passed values.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "in": "header", + "name": "If-None-Match", + "schema": { + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "Succeeds if the server's resource date is more recent than the passed date.", + "in": "header", + "name": "If-Modified-Since", + "schema": { + "description": "Succeeds if the server's resource date is more recent than the passed date.", + "format": "date-time-http", + "type": "string" + } + }, + { + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "in": "header", + "name": "If-Unmodified-Since", + "schema": { + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "format": "date-time-http", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Array of asset registration records for the specified plant and date", + "items": { + "$ref": "#/components/schemas/RegistryOutputBody" + }, + "type": [ + "array", + "null" + ] + } + } + }, + "description": "OK", + "headers": { + "ETag": { + "schema": { + "description": "Weak entity tag for conditional requests.", + "type": "string" + } + } + } }, "default": { "content": { @@ -5893,16 +7485,16 @@ "bearer": [] } ], - "summary": "Retrieve Time-Series Metrics Data", + "summary": "Retrieve Plant Registry Logs", "tags": [ - "v3/plants/metrics" + "v3/plants/registry" ] } }, - "/api/v3/plants/{plant_id}/registry/stat": { + "/api/v3/plants/{plant_id}/registry/logs/filter": { "get": { - "description": "Retrieves the end-of-day installed capacity, module model counts, and device model stats for the specified plant and date from the registry origin, while computing the response ETag within patch-api.", - "operationId": "get_plant_registry_stat", + "description": "Filters registry log records for the specified plant and date by asset_id, map_id, asset_type, and map_type. At least one filter parameter is required.", + "operationId": "filter_plant_registry_logs", "parameters": [ { "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", @@ -5960,6 +7552,67 @@ "type": "string" } }, + { + "description": "Optional asset ID filter.", + "explode": false, + "in": "query", + "name": "asset_id", + "schema": { + "description": "Optional asset ID filter.", + "pattern": "^[a-zA-Z0-9.\\-_ /:@+]*$", + "type": "string" + } + }, + { + "description": "Optional map ID filter.", + "explode": false, + "in": "query", + "name": "map_id", + "schema": { + "description": "Optional map ID filter.", + "pattern": "^[a-zA-Z0-9.\\-_ /:@+]*$", + "type": "string" + } + }, + { + "description": "Optional asset type filter.", + "explode": false, + "in": "query", + "name": "asset_type", + "schema": { + "description": "Optional asset type filter.", + "enum": [ + "device", + "inverter", + "edge", + "panel", + "panel_group", + "sensor" + ], + "type": "string" + } + }, + { + "description": "Optional map type filter.", + "explode": false, + "in": "query", + "name": "map_type", + "schema": { + "description": "Optional map type filter.", + "enum": [ + "device", + "string", + "edge", + "inverter", + "combiner", + "panel", + "panel_group", + "tracker", + "sensor" + ], + "type": "string" + } + }, { "description": "Succeeds if the server's resource matches one of the passed values.", "in": "header", @@ -6016,8 +7669,14 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/StatPoint", - "description": "Installed panel capacity, module model counts, device model stats, and inverter model stats at the end of the requested day." + "description": "Array of asset registration records for the specified plant and date", + "items": { + "$ref": "#/components/schemas/RegistryOutputBody" + }, + "type": [ + "array", + "null" + ] } } }, @@ -6047,16 +7706,16 @@ "bearer": [] } ], - "summary": "Retrieve Plant Registry Stat", + "summary": "Filter Plant Registry Logs", "tags": [ "v3/plants/registry" ] } }, - "/api/v3/plants/{plant_id}/registry/{record_type}": { + "/api/v3/plants/{plant_id}/registry/snapshots": { "get": { - "description": "Retrieves asset registry information for a specific plant filtered by record type. Includes registration status, mapping information, and historical data for the specified asset type. Authorization header and Account-Type header are required.", - "operationId": "get_asset_registration_on_plant", + "description": "Retrieves registry snapshot records for the specified plant and date, with optional asset_id, map_id, asset_type, and map_type filters.", + "operationId": "get_plant_registry_snapshots", "parameters": [ { "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", @@ -6099,23 +7758,6 @@ "type": "string" } }, - { - "description": "The type of data to retrieve. Possible values:'logs': Returns all records that have changed on the specified date., 'snapshots': Returns all records that can be evaluated as 'registered' on the specified date.", - "in": "path", - "name": "record_type", - "required": true, - "schema": { - "description": "The type of data to retrieve. Possible values:'logs': Returns all records that have changed on the specified date., 'snapshots': Returns all records that can be evaluated as 'registered' on the specified date.", - "enum": [ - "logs", - "snapshots" - ], - "examples": [ - "logs" - ], - "type": "string" - } - }, { "description": "Target date of data. Must follow the format 'YYYY-MM-DD'.", "explode": false, @@ -6132,22 +7774,63 @@ } }, { - "description": "The unique identifier for the asset.", + "description": "Optional asset ID filter.", "explode": false, "in": "query", "name": "asset_id", "schema": { - "description": "The unique identifier for the asset.", + "description": "Optional asset ID filter.", + "pattern": "^[a-zA-Z0-9.\\-_ /:@+]*$", "type": "string" } }, { - "description": "The unique identifier for the map.", + "description": "Optional map ID filter.", "explode": false, "in": "query", "name": "map_id", "schema": { - "description": "The unique identifier for the map.", + "description": "Optional map ID filter.", + "pattern": "^[a-zA-Z0-9.\\-_ /:@+]*$", + "type": "string" + } + }, + { + "description": "Optional asset type filter.", + "explode": false, + "in": "query", + "name": "asset_type", + "schema": { + "description": "Optional asset type filter.", + "enum": [ + "device", + "inverter", + "edge", + "panel", + "panel_group", + "sensor" + ], + "type": "string" + } + }, + { + "description": "Optional map type filter.", + "explode": false, + "in": "query", + "name": "map_type", + "schema": { + "description": "Optional map type filter.", + "enum": [ + "device", + "string", + "edge", + "inverter", + "combiner", + "panel", + "panel_group", + "tracker", + "sensor" + ], "type": "string" } }, @@ -6244,7 +7927,161 @@ "bearer": [] } ], - "summary": "Retrieve Plant Registry by Record Type", + "summary": "Retrieve Plant Registry Snapshots", + "tags": [ + "v3/plants/registry" + ] + } + }, + "/api/v3/plants/{plant_id}/registry/stat": { + "get": { + "description": "Retrieves the end-of-day installed capacity, module model counts, and device model stats for the specified plant and date from the registry origin, while computing the response ETag within patch-api.", + "operationId": "get_plant_registry_stat", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "enum": [ + "viewer", + "manager", + "admin" + ], + "type": "string" + } + }, + { + "description": "Patch Plant ID. A unique alphanumeric identifier representing the plant to fetch data for. Must be exactly 15 characters in length.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Patch Plant ID. A unique alphanumeric identifier representing the plant to fetch data for. Must be exactly 15 characters in length.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "patternDescription": "alphanum", + "type": "string" + } + }, + { + "description": "Target date of data. Must follow the format 'YYYY-MM-DD'.", + "explode": false, + "in": "query", + "name": "date", + "required": true, + "schema": { + "description": "Target date of data. Must follow the format 'YYYY-MM-DD'.", + "examples": [ + "2024-01-24" + ], + "format": "date", + "type": "string" + } + }, + { + "description": "Succeeds if the server's resource matches one of the passed values.", + "in": "header", + "name": "If-Match", + "schema": { + "description": "Succeeds if the server's resource matches one of the passed values.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "in": "header", + "name": "If-None-Match", + "schema": { + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "Succeeds if the server's resource date is more recent than the passed date.", + "in": "header", + "name": "If-Modified-Since", + "schema": { + "description": "Succeeds if the server's resource date is more recent than the passed date.", + "format": "date-time-http", + "type": "string" + } + }, + { + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "in": "header", + "name": "If-Unmodified-Since", + "schema": { + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "format": "date-time-http", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StatPoint", + "description": "Installed panel capacity, module model counts, device model stats, and inverter model stats at the end of the requested day." + } + } + }, + "description": "OK", + "headers": { + "ETag": { + "schema": { + "description": "Weak entity tag for conditional requests.", + "type": "string" + } + } + } + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Retrieve Plant Registry Stat", "tags": [ "v3/plants/registry" ] From 21cd86585e45bf986792c1a5fd8f9a75b9106cbb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 25 May 2026 01:08:03 +0000 Subject: [PATCH 06/11] chore: sync openapi v3 snapshot --- openapi/openapi-v3.json | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/openapi/openapi-v3.json b/openapi/openapi-v3.json index 7718258..ebf8d5c 100644 --- a/openapi/openapi-v3.json +++ b/openapi/openapi-v3.json @@ -3499,6 +3499,20 @@ ], "type": "object" }, + "RegistryMeta": { + "additionalProperties": false, + "properties": { + "fielder_name": { + "description": "Name of the field worker who performed the registry event.", + "type": "string" + }, + "fielder_org": { + "description": "Organization of the field worker who performed the registry event.", + "type": "string" + } + }, + "type": "object" + }, "RegistryOutputBody": { "additionalProperties": false, "properties": { @@ -3546,6 +3560,10 @@ "description": "Timestamp when the asset was registered in RFC3339 format", "type": "string" }, + "registered_meta": { + "$ref": "#/components/schemas/RegistryMeta", + "description": "Sanitized registration actor metadata. Only fielder_name and fielder_org are exposed." + }, "tag": { "additionalProperties": {}, "description": "Additional metadata and tags associated with the asset registration", @@ -3554,6 +3572,10 @@ "unregistered": { "description": "Timestamp when the asset was unregistered in RFC3339 format (empty if still registered)", "type": "string" + }, + "unregistered_meta": { + "$ref": "#/components/schemas/RegistryMeta", + "description": "Sanitized unregistration actor metadata. Only fielder_name and fielder_org are exposed." } }, "required": [ From ce68a75a857c33ab4ad54e836c37e64adf7fde2a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 1 Jun 2026 01:14:06 +0000 Subject: [PATCH 07/11] chore: sync openapi v3 snapshot --- openapi/openapi-v3.json | 1748 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 1666 insertions(+), 82 deletions(-) diff --git a/openapi/openapi-v3.json b/openapi/openapi-v3.json index ebf8d5c..dca40c7 100644 --- a/openapi/openapi-v3.json +++ b/openapi/openapi-v3.json @@ -1204,6 +1204,205 @@ ], "type": "object" }, + "CommentActionBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/CommentActionBody.json" + ], + "format": "uri", + "readOnly": true, + "type": "string" + }, + "images": { + "description": "Image file IDs attached to the comment.", + "items": { + "type": "string" + }, + "type": "array" + }, + "is_private": { + "description": "Private flag.", + "type": "boolean" + }, + "map_ids": { + "description": "Plant map object IDs attached to the comment.", + "items": { + "minLength": 1, + "pattern": "^[^\\s\\p{Z}](?:[^\\r\\n\\x85\\p{Zl}\\p{Zp}]*[^\\s\\p{Z}])?$", + "patternDescription": "non-blank with no leading or trailing whitespace", + "type": "string" + }, + "type": "array" + }, + "related": { + "description": "Related plant-data timestamp.", + "examples": [ + "2025-04-11 00:05:00.000Z" + ], + "type": "string" + }, + "text": { + "description": "Comment text.", + "examples": [ + "입력전압 없음" + ], + "minLength": 1, + "type": "string" + } + }, + "required": [ + "text" + ], + "type": "object" + }, + "CommentEditBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/CommentEditBody.json" + ], + "format": "uri", + "readOnly": true, + "type": "string" + }, + "images": { + "description": "Image file IDs attached to the comment.", + "items": { + "type": "string" + }, + "type": "array" + }, + "is_private": { + "description": "Private flag.", + "type": "boolean" + }, + "map_ids": { + "description": "Plant map object IDs attached to the comment.", + "items": { + "minLength": 1, + "pattern": "^[^\\s\\p{Z}](?:[^\\r\\n\\x85\\p{Zl}\\p{Zp}]*[^\\s\\p{Z}])?$", + "patternDescription": "non-blank with no leading or trailing whitespace", + "type": "string" + }, + "type": "array" + }, + "related": { + "description": "Related plant-data timestamp.", + "examples": [ + "2025-04-11 00:05:00.000Z" + ], + "type": "string" + }, + "text": { + "description": "Comment text.", + "examples": [ + "입력전압 없음" + ], + "minLength": 1, + "type": "string" + } + }, + "type": "object" + }, + "CommentOutput": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/CommentOutput.json" + ], + "format": "uri", + "readOnly": true, + "type": "string" + }, + "created": { + "type": "string" + }, + "id": { + "type": "string" + }, + "images": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "is_private": { + "type": "boolean" + }, + "map_ids": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "parent": { + "type": "string" + }, + "related": { + "type": "string" + }, + "resolved": { + "type": "string" + }, + "text": { + "type": "string" + }, + "updated": { + "type": "string" + } + }, + "required": [ + "id", + "text", + "created", + "updated" + ], + "type": "object" + }, + "CommentStateBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/CommentStateBody.json" + ], + "format": "uri", + "readOnly": true, + "type": "string" + }, + "transition": { + "description": "State transition to apply to the comment.", + "enum": [ + "resolve", + "reopen", + "archive", + "restore" + ], + "examples": [ + "resolve" + ], + "type": "string" + } + }, + "required": [ + "transition" + ], + "type": "object" + }, "CreateAccountOutputBody": { "additionalProperties": false, "properties": { @@ -1275,6 +1474,46 @@ ], "type": "object" }, + "CreateFilterBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/CreateFilterBody.json" + ], + "format": "uri", + "readOnly": true, + "type": "string" + }, + "map_ids": { + "description": "Plant map object IDs included in this filter.", + "items": { + "minLength": 1, + "pattern": "^[^\\s\\p{Z}](?:[^\\r\\n\\x85\\p{Zl}\\p{Zp}]*[^\\s\\p{Z}])?$", + "patternDescription": "non-blank with no leading or trailing whitespace", + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "name": { + "description": "Filter name.", + "examples": [ + "Inverter A" + ], + "minLength": 1, + "pattern": "^[^\\s\\p{Z}](?:[^\\r\\n\\x85\\p{Zl}\\p{Zp}]*[^\\s\\p{Z}])?$", + "patternDescription": "non-blank with no leading or trailing whitespace", + "type": "string" + } + }, + "required": [ + "name", + "map_ids" + ], + "type": "object" + }, "CreateOrganizationMemberRequestBody": { "additionalProperties": false, "properties": { @@ -1941,6 +2180,90 @@ ], "type": "object" }, + "Filter": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/Filter.json" + ], + "format": "uri", + "readOnly": true, + "type": "string" + }, + "conditions": { + "$ref": "#/components/schemas/FilterConditions", + "description": "Filter conditions." + }, + "created": { + "description": "Filter record creation timestamp.", + "type": "string" + }, + "id": { + "description": "Filter record ID.", + "type": "string" + }, + "name": { + "description": "Filter name.", + "type": "string" + }, + "updated": { + "description": "Filter record update timestamp.", + "type": "string" + } + }, + "required": [ + "id", + "name", + "conditions", + "updated" + ], + "type": "object" + }, + "FilterConditions": { + "additionalProperties": false, + "properties": { + "merge": { + "description": "Map object IDs merged by this filter.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + "type": "object" + }, + "FilterListItem": { + "additionalProperties": false, + "properties": { + "created": { + "description": "Filter record creation timestamp.", + "type": "string" + }, + "id": { + "description": "Filter record ID.", + "type": "string" + }, + "name": { + "description": "Filter name.", + "type": "string" + }, + "updated": { + "description": "Filter record update timestamp.", + "type": "string" + } + }, + "required": [ + "id", + "name", + "updated" + ], + "type": "object" + }, "HealthLevelBody": { "additionalProperties": false, "properties": { @@ -3042,7 +3365,7 @@ ] }, "date": { - "description": "Date of the data point in YYYY-MM-DD format", + "description": "Date/time label from the panel-all parquet row.", "type": "string" }, "energy": { @@ -3112,11 +3435,6 @@ } }, "required": [ - "id", - "date", - "timestamp", - "energy", - "cumulative_energy", "i_out", "p", "v_in", @@ -3124,7 +3442,12 @@ "temp", "avg_seqnum", "min_seqnum", - "count" + "count", + "energy", + "cumulative_energy", + "id", + "date", + "timestamp" ], "type": "object" }, @@ -3590,6 +3913,34 @@ ], "type": "object" }, + "RenameFilterBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/RenameFilterBody.json" + ], + "format": "uri", + "readOnly": true, + "type": "string" + }, + "name": { + "description": "Filter name.", + "examples": [ + "Inverter A" + ], + "minLength": 1, + "pattern": "^[^\\s\\p{Z}](?:[^\\r\\n\\x85\\p{Zl}\\p{Zp}]*[^\\s\\p{Z}])?$", + "patternDescription": "non-blank with no leading or trailing whitespace", + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, "Report": { "additionalProperties": false, "properties": { @@ -5450,10 +5801,10 @@ ] } }, - "/api/v3/plants/{plant_id}/indicator/device-state": { + "/api/v3/plants/{plant_id}/comments": { "get": { - "description": "Retrieves device or panel state indicator data at 5-minute intervals. Use the kind query parameter to select the indicator (seqnum, relay, rsd, or count). Data row fields vary by kind: count rows include edge_id, id, timestamp, date, and count; seqnum rows include id, timestamp, avg_seqnum, and min_seqnum; relay rows include id, date, timestamp, is_relay, and is_forced_relay; rsd rows include id, date, timestamp, is_rsd, and is_forced_rsd.", - "operationId": "get_device_state", + "description": "Lists comments for a specific plant.", + "operationId": "list_plant_comments", "parameters": [ { "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", @@ -5481,109 +5832,1342 @@ } }, { - "description": "Succeeds when none of the supplied ETags match the current representation.", - "in": "header", - "name": "If-None-Match", + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "in": "path", + "name": "plant_id", + "required": true, "schema": { - "description": "Succeeds when none of the supplied ETags match the current representation.", - "items": { - "type": "string" - }, - "type": [ - "array", - "null" - ] + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "pattern": "^[a-zA-Z0-9]{15}$", + "patternDescription": "alphanum", + "type": "string" } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/CommentOutput" + }, + "type": [ + "array", + "null" + ] + } + } + }, + "description": "OK" }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ { - "description": "The ID of the plant.", - "in": "path", - "name": "plant_id", + "bearer": [] + } + ], + "summary": "List Plant Comments", + "tags": [ + "v3/plants/comments" + ] + } + }, + "/api/v3/plants/{plant_id}/comments/start_thread": { + "post": { + "description": "Starts a comment thread for a specific plant.", + "operationId": "start_plant_comment_thread", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", "required": true, "schema": { - "description": "The ID of the plant.", + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", "type": "string" } }, { - "description": "Target date (YYYY-MM-DD).", - "explode": false, - "in": "query", - "name": "date", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "in": "header", + "name": "Account-Type", "required": true, "schema": { - "description": "Target date (YYYY-MM-DD).", - "examples": [ - "2025-08-14" + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "enum": [ + "viewer", + "manager", + "admin" ], - "format": "date", "type": "string" } }, { - "description": "Indicator kind to retrieve. One of: seqnum, relay, rsd, count.", - "explode": false, - "in": "query", - "name": "kind", + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "in": "path", + "name": "plant_id", "required": true, "schema": { - "description": "Indicator kind to retrieve. One of: seqnum, relay, rsd, count.", - "enum": [ - "seqnum", - "relay", - "rsd", - "count" + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "examples": [ + "unw4id41ud2p0wt" ], + "maxLength": 15, + "minLength": 15, + "pattern": "^[a-zA-Z0-9]{15}$", + "patternDescription": "alphanum", "type": "string" } } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommentActionBody" + } + } + }, + "required": true + }, "responses": { - "200": { + "201": { "content": { "application/json": { "schema": { - "description": "Device state response envelope. The data row shape depends on kind; count rows include edge_id, id, timestamp, date, and count.", - "properties": { - "data": { - "description": "Indicator rows. The structure of each item depends on the requested kind: count rows include edge_id, id, timestamp, date, and count; seqnum rows include id, timestamp, avg_seqnum, and min_seqnum; relay rows include id, date, timestamp, is_relay, and is_forced_relay; rsd rows include id, date, timestamp, is_rsd, and is_forced_rsd.", - "items": { - "additionalProperties": true, - "type": "object" - }, - "type": "array" - }, - "date": { - "description": "Requested local date.", - "type": "string" - }, - "kind": { - "description": "Indicator kind: seqnum, relay, rsd, or count.", - "enum": [ - "seqnum", - "relay", - "rsd", - "count" - ], - "type": "string" - }, - "plant_id": { - "description": "Requested plant ID.", - "type": "string" - } - }, - "required": [ - "plant_id", - "date", - "kind", - "data" - ], - "type": "object" + "$ref": "#/components/schemas/CommentOutput" } } }, - "description": "Gzip JSON envelope containing indicator data. The data row structure varies by kind (e.g., count rows include edge_id, id, timestamp, date, and count).", - "headers": { + "description": "Created" + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Start Plant Comment Thread", + "tags": [ + "v3/plants/comments" + ] + } + }, + "/api/v3/plants/{plant_id}/comments/{comment_id}": { + "get": { + "description": "Retrieves a specific comment for a plant.", + "operationId": "get_plant_comment", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "enum": [ + "viewer", + "manager", + "admin" + ], + "type": "string" + } + }, + { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "pattern": "^[a-zA-Z0-9]{15}$", + "patternDescription": "alphanum", + "type": "string" + } + }, + { + "description": "Comment ID. A unique alphanumeric identifier representing the comment. Must be exactly 15 characters in length.", + "in": "path", + "name": "comment_id", + "required": true, + "schema": { + "description": "Comment ID. A unique alphanumeric identifier representing the comment. Must be exactly 15 characters in length.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "pattern": "^[a-zA-Z0-9]{15}$", + "patternDescription": "alphanum", + "type": "string" + } + }, + { + "description": "Succeeds if the server's resource matches one of the passed values.", + "in": "header", + "name": "If-Match", + "schema": { + "description": "Succeeds if the server's resource matches one of the passed values.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "in": "header", + "name": "If-None-Match", + "schema": { + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "Succeeds if the server's resource date is more recent than the passed date.", + "in": "header", + "name": "If-Modified-Since", + "schema": { + "description": "Succeeds if the server's resource date is more recent than the passed date.", + "format": "date-time-http", + "type": "string" + } + }, + { + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "in": "header", + "name": "If-Unmodified-Since", + "schema": { + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "format": "date-time-http", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommentOutput", + "description": "Plant comment detail." + } + } + }, + "description": "OK", + "headers": { + "ETag": { + "schema": { + "description": "Weak entity tag for conditional requests.", + "type": "string" + } + } + } + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Get Plant Comment", + "tags": [ + "v3/plants/comments" + ] + } + }, + "/api/v3/plants/{plant_id}/comments/{comment_id}/edit": { + "post": { + "description": "Edits a specific plant comment.", + "operationId": "edit_plant_comment", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "enum": [ + "viewer", + "manager", + "admin" + ], + "type": "string" + } + }, + { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "pattern": "^[a-zA-Z0-9]{15}$", + "patternDescription": "alphanum", + "type": "string" + } + }, + { + "description": "Comment ID. A unique alphanumeric identifier representing the comment. Must be exactly 15 characters in length.", + "in": "path", + "name": "comment_id", + "required": true, + "schema": { + "description": "Comment ID. A unique alphanumeric identifier representing the comment. Must be exactly 15 characters in length.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "pattern": "^[a-zA-Z0-9]{15}$", + "patternDescription": "alphanum", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommentEditBody" + } + } + } + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommentOutput" + } + } + }, + "description": "OK" + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Edit Plant Comment", + "tags": [ + "v3/plants/comments" + ] + } + }, + "/api/v3/plants/{plant_id}/comments/{comment_id}/reply": { + "post": { + "description": "Creates a reply under a specific plant comment.", + "operationId": "reply_plant_comment", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "enum": [ + "viewer", + "manager", + "admin" + ], + "type": "string" + } + }, + { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "pattern": "^[a-zA-Z0-9]{15}$", + "patternDescription": "alphanum", + "type": "string" + } + }, + { + "description": "Comment ID. A unique alphanumeric identifier representing the comment. Must be exactly 15 characters in length.", + "in": "path", + "name": "comment_id", + "required": true, + "schema": { + "description": "Comment ID. A unique alphanumeric identifier representing the comment. Must be exactly 15 characters in length.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "pattern": "^[a-zA-Z0-9]{15}$", + "patternDescription": "alphanum", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommentActionBody" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommentOutput" + } + } + }, + "description": "Created" + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Reply To Plant Comment", + "tags": [ + "v3/plants/comments" + ] + } + }, + "/api/v3/plants/{plant_id}/comments/{comment_id}/state": { + "post": { + "description": "Applies a state transition to a specific plant comment.", + "operationId": "change_plant_comment_state", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "enum": [ + "viewer", + "manager", + "admin" + ], + "type": "string" + } + }, + { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "pattern": "^[a-zA-Z0-9]{15}$", + "patternDescription": "alphanum", + "type": "string" + } + }, + { + "description": "Comment ID. A unique alphanumeric identifier representing the comment. Must be exactly 15 characters in length.", + "in": "path", + "name": "comment_id", + "required": true, + "schema": { + "description": "Comment ID. A unique alphanumeric identifier representing the comment. Must be exactly 15 characters in length.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "pattern": "^[a-zA-Z0-9]{15}$", + "patternDescription": "alphanum", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommentStateBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommentOutput" + } + } + }, + "description": "OK" + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Change Plant Comment State", + "tags": [ + "v3/plants/comments" + ] + } + }, + "/api/v3/plants/{plant_id}/filters": { + "get": { + "description": "Lists reusable map object filters for a specific plant without including each filter's condition payload.", + "operationId": "list_plant_filters", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "enum": [ + "viewer", + "manager", + "admin" + ], + "type": "string" + } + }, + { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "pattern": "^[a-zA-Z0-9]{15}$", + "patternDescription": "alphanum", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Plant filters without condition payloads.", + "items": { + "$ref": "#/components/schemas/FilterListItem" + }, + "type": [ + "array", + "null" + ] + } + } + }, + "description": "OK" + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "List Plant Filters", + "tags": [ + "v3/plants/filters" + ] + } + }, + "/api/v3/plants/{plant_id}/filters/create": { + "post": { + "description": "Creates a reusable map object filter for a specific plant. The request map IDs are stored internally as merge conditions.", + "operationId": "create_plant_filter", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "enum": [ + "viewer", + "manager", + "admin" + ], + "type": "string" + } + }, + { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "pattern": "^[a-zA-Z0-9]{15}$", + "patternDescription": "alphanum", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateFilterBody" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Filter", + "description": "Created plant filter." + } + } + }, + "description": "Created" + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Create Plant Filter", + "tags": [ + "v3/plants/filters" + ] + } + }, + "/api/v3/plants/{plant_id}/filters/{filter_id}": { + "delete": { + "description": "Deletes a reusable map object filter for a specific plant.", + "operationId": "delete_plant_filter", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "enum": [ + "viewer", + "manager", + "admin" + ], + "type": "string" + } + }, + { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "pattern": "^[a-zA-Z0-9]{15}$", + "patternDescription": "alphanum", + "type": "string" + } + }, + { + "description": "Filter record ID.", + "in": "path", + "name": "filter_id", + "required": true, + "schema": { + "description": "Filter record ID.", + "examples": [ + "filter123456789" + ], + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Delete Plant Filter", + "tags": [ + "v3/plants/filters" + ] + }, + "get": { + "description": "Retrieves a reusable map object filter for a specific plant, including its condition payload.", + "operationId": "get_plant_filter", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "enum": [ + "viewer", + "manager", + "admin" + ], + "type": "string" + } + }, + { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "pattern": "^[a-zA-Z0-9]{15}$", + "patternDescription": "alphanum", + "type": "string" + } + }, + { + "description": "Filter record ID.", + "in": "path", + "name": "filter_id", + "required": true, + "schema": { + "description": "Filter record ID.", + "examples": [ + "filter123456789" + ], + "type": "string" + } + }, + { + "description": "Succeeds if the server's resource matches one of the passed values.", + "in": "header", + "name": "If-Match", + "schema": { + "description": "Succeeds if the server's resource matches one of the passed values.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "in": "header", + "name": "If-None-Match", + "schema": { + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "Succeeds if the server's resource date is more recent than the passed date.", + "in": "header", + "name": "If-Modified-Since", + "schema": { + "description": "Succeeds if the server's resource date is more recent than the passed date.", + "format": "date-time-http", + "type": "string" + } + }, + { + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "in": "header", + "name": "If-Unmodified-Since", + "schema": { + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "format": "date-time-http", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Filter", + "description": "Plant filter detail." + } + } + }, + "description": "OK", + "headers": { + "ETag": { + "schema": { + "description": "Weak entity tag for conditional requests.", + "type": "string" + } + } + } + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Get Plant Filter", + "tags": [ + "v3/plants/filters" + ] + } + }, + "/api/v3/plants/{plant_id}/filters/{filter_id}/rename": { + "post": { + "description": "Renames a reusable map object filter for a specific plant.", + "operationId": "rename_plant_filter", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "enum": [ + "viewer", + "manager", + "admin" + ], + "type": "string" + } + }, + { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "pattern": "^[a-zA-Z0-9]{15}$", + "patternDescription": "alphanum", + "type": "string" + } + }, + { + "description": "Filter record ID.", + "in": "path", + "name": "filter_id", + "required": true, + "schema": { + "description": "Filter record ID.", + "examples": [ + "filter123456789" + ], + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RenameFilterBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Filter", + "description": "Renamed plant filter." + } + } + }, + "description": "OK" + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Rename Plant Filter", + "tags": [ + "v3/plants/filters" + ] + } + }, + "/api/v3/plants/{plant_id}/indicator/device-state": { + "get": { + "description": "Retrieves device-state data at 5-minute intervals. The fields query parameter is accepted for API compatibility but currently all device-state columns are returned. Rows include id, timestamp, date, is_forced_rapid_shutdown, is_forced_ref, is_forced_relay, is_rapid_shutdown, and is_relay.", + "operationId": "get_device_state", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "enum": [ + "viewer", + "manager", + "admin" + ], + "type": "string" + } + }, + { + "description": "Succeeds when none of the supplied ETags match the current representation.", + "in": "header", + "name": "If-None-Match", + "schema": { + "description": "Succeeds when none of the supplied ETags match the current representation.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "The ID of the plant.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "The ID of the plant.", + "type": "string" + } + }, + { + "description": "Target date (YYYY-MM-DD).", + "explode": false, + "in": "query", + "name": "date", + "required": true, + "schema": { + "description": "Target date (YYYY-MM-DD).", + "examples": [ + "2025-08-14" + ], + "format": "date", + "type": "string" + } + }, + { + "description": "Device-state fields to include. Selection is reserved for future use; the endpoint currently returns all device-state columns.", + "explode": false, + "in": "query", + "name": "fields", + "schema": { + "default": [ + "all" + ], + "description": "Device-state fields to include. Selection is reserved for future use; the endpoint currently returns all device-state columns.", + "examples": [ + [ + "is_relay", + "is_rapid_shutdown" + ] + ], + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Device state response envelope. Rows include id, timestamp, date, is_forced_rapid_shutdown, is_forced_ref, is_forced_relay, is_rapid_shutdown, and is_relay.", + "properties": { + "data": { + "description": "Device-state rows. Rows include id, timestamp, date, is_forced_rapid_shutdown, is_forced_ref, is_forced_relay, is_rapid_shutdown, and is_relay.", + "items": { + "additionalProperties": false, + "description": "Rows include id, timestamp, date, is_forced_rapid_shutdown, is_forced_ref, is_forced_relay, is_rapid_shutdown, and is_relay.", + "properties": { + "date": { + "description": "Time label from the device-state parquet row.", + "type": "string" + }, + "id": { + "description": "Device-state row identifier.", + "type": "string" + }, + "is_forced_rapid_shutdown": { + "description": "Forced rapid shutdown state.", + "type": "boolean" + }, + "is_forced_ref": { + "description": "Forced reference state.", + "type": "boolean" + }, + "is_forced_relay": { + "description": "Forced relay state.", + "type": "boolean" + }, + "is_rapid_shutdown": { + "description": "Rapid shutdown state.", + "type": "boolean" + }, + "is_relay": { + "description": "Relay state.", + "type": "boolean" + }, + "timestamp": { + "description": "Unix timestamp of the device-state row.", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "id", + "timestamp", + "date", + "is_forced_rapid_shutdown", + "is_forced_ref", + "is_forced_relay", + "is_rapid_shutdown", + "is_relay" + ], + "type": "object" + }, + "type": "array" + }, + "date": { + "description": "Requested local date.", + "type": "string" + }, + "plant_id": { + "description": "Requested plant ID.", + "type": "string" + } + }, + "required": [ + "plant_id", + "date", + "data" + ], + "type": "object" + } + } + }, + "description": "Gzip JSON envelope containing device-state rows. Rows include id, timestamp, date, is_forced_rapid_shutdown, is_forced_ref, is_forced_relay, is_rapid_shutdown, and is_relay.", + "headers": { + "Content-Encoding": { + "description": "Response body content encoding. Device-state streams are gzip encoded.", + "schema": { + "enum": [ + "gzip" + ], + "type": "string" + } + }, "ETag": { "schema": { "description": "Weak entity tag for conditional requests.", From ca7515c4257b514e65c98c31472d2c1217b4d750 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 8 Jun 2026 01:13:29 +0000 Subject: [PATCH 08/11] chore: sync openapi v3 snapshot --- openapi/openapi-v3.json | 1623 ++++++++++++++++++++++----------------- 1 file changed, 903 insertions(+), 720 deletions(-) diff --git a/openapi/openapi-v3.json b/openapi/openapi-v3.json index dca40c7..0531327 100644 --- a/openapi/openapi-v3.json +++ b/openapi/openapi-v3.json @@ -14,7 +14,7 @@ "type": "string" }, "email": { - "description": "The email address of the user. Only available for 'manager' and 'admin' account types.", + "description": "The email address of the user. Only available for 'manager' account types.", "examples": [ "manager@example.com" ], @@ -45,12 +45,12 @@ "enum": [ "manager", "viewer", - "admin" + "temporary" ], "type": "string" }, "username": { - "description": "The username of the user. Only available for 'viewer' account types.", + "description": "The username of the user. Only available for 'viewer' and 'temporary' account types.", "examples": [ "viewer_user" ], @@ -64,6 +64,60 @@ ], "type": "object" }, + "AssignOrganizationPermissionRequestBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/AssignOrganizationPermissionRequestBody.json" + ], + "format": "uri", + "readOnly": true, + "type": "string" + }, + "email": { + "description": "User email to grant access for. Used when Role is manager", + "examples": [ + "usr123456789012@conalog.com" + ], + "type": "string" + }, + "plantId": { + "description": "Target plant ID to grant access to.", + "examples": [ + "pln123456789012" + ], + "maxLength": 15, + "minLength": 15, + "type": "string" + }, + "type": { + "description": "Account type of user.", + "enum": [ + "viewer", + "manager", + "temporary" + ], + "examples": [ + "viewer" + ], + "type": "string" + }, + "username": { + "description": "User username to grant access for. Used when Role is viewer or temporary", + "examples": [ + "usr123456789012" + ], + "type": "string" + } + }, + "required": [ + "plantId", + "type" + ], + "type": "object" + }, "AuthAccountBody": { "additionalProperties": false, "properties": { @@ -202,7 +256,7 @@ "type": "string" }, "email": { - "description": "The email address of the user. Only available for 'manager' and 'admin' account types.", + "description": "The email address of the user. Only available for 'manager' account types.", "examples": [ "manager@example.com" ], @@ -237,12 +291,12 @@ "enum": [ "manager", "viewer", - "admin" + "temporary" ], "type": "string" }, "username": { - "description": "The username of the user. Only available for 'viewer' account types.", + "description": "The username of the user. Only available for 'viewer' and 'temporary' account types.", "examples": [ "viewer_user" ], @@ -349,12 +403,13 @@ "description": "The type of account to authenticate. Determines the authentication method and access level.", "enum": [ "manager", - "viewer" + "viewer", + "temporary" ], "type": "string" }, "username": { - "description": "The user's username. Required when authenticating as a 'viewer' account type.", + "description": "The user's username. Required when authenticating as a 'viewer' or 'temporary' account type.", "examples": [ "viewer_user" ], @@ -394,6 +449,78 @@ ], "type": "object" }, + "BlueprintRecordPayload": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/BlueprintRecordPayload.json" + ], + "format": "uri", + "readOnly": true, + "type": "string" + }, + "created": { + "type": "string" + }, + "data": {}, + "date": { + "type": "string" + }, + "id": { + "type": "string" + }, + "metadata": {}, + "plant": { + "type": "string" + }, + "updated": { + "type": "string" + } + }, + "required": [ + "id", + "plant", + "date", + "updated", + "metadata", + "data" + ], + "type": "object" + }, + "BlueprintWriteBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/BlueprintWriteBody.json" + ], + "format": "uri", + "readOnly": true, + "type": "string" + }, + "data": { + "description": "Blueprint data payload." + }, + "date": { + "description": "Blueprint effective timestamp.", + "examples": [ + "2026-06-04 00:00:00.000Z" + ], + "type": "string" + }, + "metadata": { + "description": "Blueprint metadata." + } + }, + "required": [ + "date", + "data" + ], + "type": "object" + }, "BodyESSPlantDailyData": { "additionalProperties": false, "description": "Plant-level energy storage system daily metrics at 1-day intervals.", @@ -1117,93 +1244,6 @@ ], "type": "object" }, - "Comment": { - "additionalProperties": false, - "properties": { - "created": { - "type": "string" - }, - "expand": { - "additionalProperties": {}, - "type": "object" - }, - "id": { - "type": "string" - }, - "images": { - "items": { - "type": "string" - }, - "type": [ - "array", - "null" - ] - }, - "isArchive": { - "type": [ - "boolean", - "null" - ] - }, - "isPrivate": { - "type": [ - "boolean", - "null" - ] - }, - "parent": { - "type": [ - "string", - "null" - ] - }, - "plant": { - "type": "string" - }, - "related": { - "type": [ - "string", - "null" - ] - }, - "resolved": { - "type": [ - "string", - "null" - ] - }, - "tag": {}, - "text": { - "type": "string" - }, - "title": { - "type": "string" - }, - "updated": { - "type": "string" - }, - "user": { - "type": "string" - } - }, - "required": [ - "id", - "plant", - "user", - "title", - "text", - "images", - "tag", - "parent", - "resolved", - "related", - "isPrivate", - "isArchive", - "created", - "updated" - ], - "type": "object" - }, "CommentActionBody": { "additionalProperties": false, "properties": { @@ -1324,10 +1364,20 @@ "created": { "type": "string" }, + "expand": { + "additionalProperties": {}, + "type": "object" + }, "id": { "type": "string" }, "images": { + "description": "Array of image file URLs attached to the comment.", + "examples": [ + [ + "https://example.org/api/files/w8l3o9jedinck7g/img123/blob.jpg" + ] + ], "items": { "type": "string" }, @@ -1362,78 +1412,178 @@ }, "updated": { "type": "string" + }, + "user": { + "$ref": "#/components/schemas/CommentUserOutput" } }, "required": [ "id", "text", + "user", "created", "updated" ], "type": "object" }, - "CommentStateBody": { + "CommentReadOutput": { "additionalProperties": false, "properties": { - "$schema": { - "description": "A URL to the JSON Schema for this object.", - "examples": [ - "https://patch-api.conalog.com/schemas/CommentStateBody.json" - ], - "format": "uri", - "readOnly": true, + "created": { "type": "string" }, - "transition": { - "description": "State transition to apply to the comment.", - "enum": [ - "resolve", - "reopen", - "archive", - "restore" - ], - "examples": [ - "resolve" - ], - "type": "string" - } - }, - "required": [ - "transition" - ], - "type": "object" - }, - "CreateAccountOutputBody": { - "additionalProperties": false, - "properties": { - "$schema": { - "description": "A URL to the JSON Schema for this object.", - "examples": [ - "https://patch-api.conalog.com/schemas/CreateAccountOutputBody.json" - ], - "format": "uri", - "readOnly": true, + "id": { "type": "string" }, - "email": { - "description": "The email address of the user. Only available for 'manager' and 'admin' account types.", + "images": { + "description": "Array of image file URLs attached to the comment.", "examples": [ - "manager@example.com" + [ + "https://example.org/api/files/w8l3o9jedinck7g/img123/blob.jpg" + ] ], - "type": "string" + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] }, - "id": { - "description": "Unique identifier for the user within the system.", + "is_private": { + "type": "boolean" + }, + "map_ids": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "parent": { + "type": "string" + }, + "related": { + "type": "string" + }, + "resolved": { + "type": "string" + }, + "text": { + "type": "string" + }, + "updated": { + "type": "string" + }, + "user": { + "$ref": "#/components/schemas/CommentUserOutput" + } + }, + "required": [ + "id", + "text", + "user", + "created", + "updated" + ], + "type": "object" + }, + "CommentStateBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/CommentStateBody.json" + ], + "format": "uri", + "readOnly": true, + "type": "string" + }, + "transition": { + "description": "State transition to apply to the comment.", + "enum": [ + "resolve", + "reopen", + "archive", + "restore" + ], + "examples": [ + "resolve" + ], + "type": "string" + } + }, + "required": [ + "transition" + ], + "type": "object" + }, + "CommentUserOutput": { + "additionalProperties": false, + "properties": { + "email": { + "type": "string" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "username": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "username", + "email" + ], + "type": "object" + }, + "CreateAccountOutputBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/CreateAccountOutputBody.json" + ], + "format": "uri", + "readOnly": true, + "type": "string" + }, + "email": { + "description": "The email address of the user. Only available for 'manager' account types.", + "examples": [ + "manager@example.com" + ], + "type": "string" + }, + "expired": { + "description": "Expiration timestamp for temporary accounts.", + "type": "string" + }, + "id": { + "description": "Unique identifier for the user within the system.", "examples": [ "user123" ], "type": "string" }, + "link": { + "description": "Generated onsite link for temporary accounts.", + "type": "string" + }, "metadata": { "description": "Additional metadata associated with the user account. May include custom fields, preferences, or configuration data. Not available for viewer accounts." }, "name": { - "description": "The display name of the user.", + "description": "The display name of the created manager or viewer account.", "examples": [ "John Doe" ], @@ -1454,12 +1604,12 @@ "enum": [ "manager", "viewer", - "admin" + "temporary" ], "type": "string" }, "username": { - "description": "The username of the user. Only available for 'viewer' account types.", + "description": "The username of the user. Only available for 'viewer' and 'temporary' account types.", "examples": [ "viewer_user" ], @@ -1469,7 +1619,6 @@ "required": [ "id", "type", - "name", "organizations" ], "type": "object" @@ -1646,7 +1795,7 @@ "additionalProperties": false, "properties": { "email": { - "description": "The email address of the user. Only available for 'manager' and 'admin' account types.", + "description": "The email address of the user. Only available for 'manager' account types.", "examples": [ "manager@example.com" ], @@ -1656,14 +1805,14 @@ "description": "Additional metadata associated with the user account. May include custom fields, preferences, or configuration data. Not available for viewer accounts." }, "name": { - "description": "The display name of the user.", + "description": "The display name of the user. Only used for 'manager' and 'viewer' account types.", "examples": [ "John Doe" ], "type": "string" }, "password": { - "description": "The user's password for authentication", + "description": "The user's password for authentication. Temporary account passwords are generated by the server and returned in the create response.", "examples": [ "securepassword123" ], @@ -1673,12 +1822,13 @@ "description": "The type of account indicating the user's access level and permissions. Determines available operations and data access.", "enum": [ "manager", - "viewer" + "viewer", + "temporary" ], "type": "string" }, "username": { - "description": "The username of the user. Only available for 'viewer' account types.", + "description": "The username of the user. Only used for 'viewer' account types. Temporary account usernames are generated by the server.", "examples": [ "viewer_user" ], @@ -1686,9 +1836,7 @@ } }, "required": [ - "type", - "password", - "name" + "type" ], "type": "object" }, @@ -2180,22 +2328,9 @@ ], "type": "object" }, - "Filter": { + "FilterListItem": { "additionalProperties": false, "properties": { - "$schema": { - "description": "A URL to the JSON Schema for this object.", - "examples": [ - "https://patch-api.conalog.com/schemas/Filter.json" - ], - "format": "uri", - "readOnly": true, - "type": "string" - }, - "conditions": { - "$ref": "#/components/schemas/FilterConditions", - "description": "Filter conditions." - }, "created": { "description": "Filter record creation timestamp.", "type": "string" @@ -2204,6 +2339,16 @@ "description": "Filter record ID.", "type": "string" }, + "map_ids": { + "description": "Plant map object IDs included in this filter.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, "name": { "description": "Filter name.", "type": "string" @@ -2216,30 +2361,23 @@ "required": [ "id", "name", - "conditions", + "map_ids", "updated" ], "type": "object" }, - "FilterConditions": { - "additionalProperties": false, - "properties": { - "merge": { - "description": "Map object IDs merged by this filter.", - "items": { - "type": "string" - }, - "type": [ - "array", - "null" - ] - } - }, - "type": "object" - }, - "FilterListItem": { + "FilterOutput": { "additionalProperties": false, "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/FilterOutput.json" + ], + "format": "uri", + "readOnly": true, + "type": "string" + }, "created": { "description": "Filter record creation timestamp.", "type": "string" @@ -2248,6 +2386,16 @@ "description": "Filter record ID.", "type": "string" }, + "map_ids": { + "description": "Plant map object IDs included in this filter.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, "name": { "description": "Filter name.", "type": "string" @@ -2260,6 +2408,7 @@ "required": [ "id", "name", + "map_ids", "updated" ], "type": "object" @@ -2312,11 +2461,50 @@ ], "type": "object" }, + "ImageUploadResponse": { + "additionalProperties": false, + "properties": { + "created": { + "description": "Timestamp when the image record was created", + "type": "string" + }, + "filename": { + "description": "Original filename of the uploaded image", + "type": "string" + }, + "id": { + "description": "Image record ID. Use this value in comment image attachment requests.", + "type": "string" + }, + "plant_id": { + "description": "Plant ID from the upload route path", + "type": "string" + }, + "size": { + "description": "Image file size in bytes", + "format": "int64", + "type": "integer" + }, + "updated": { + "description": "Timestamp when the image record was last updated", + "type": "string" + } + }, + "required": [ + "id", + "plant_id", + "filename", + "size", + "created", + "updated" + ], + "type": "object" + }, "InternalInvalidateAuthValidationCacheBody": { "additionalProperties": false, "properties": { "cache_key": { - "pattern": "^token-auth/v2/(manager|viewer|admin)/[a-f0-9]{64}$", + "pattern": "^token-auth/v2/(manager|viewer|temporary)/[a-f0-9]{64}$", "type": "string" } }, @@ -3155,13 +3343,13 @@ ], "type": "object" }, - "OrgAddPermissionInputBody": { + "OrgAddPermissionOutputBody": { "additionalProperties": false, "properties": { "$schema": { "description": "A URL to the JSON Schema for this object.", "examples": [ - "https://patch-api.conalog.com/schemas/OrgAddPermissionInputBody.json" + "https://patch-api.conalog.com/schemas/OrgAddPermissionOutputBody.json" ], "format": "uri", "readOnly": true, @@ -3174,28 +3362,20 @@ ], "type": "string" }, - "plantId": { - "description": "Target plant ID to grant access to.", - "examples": [ - "pln123456789012" - ], - "maxLength": 15, - "minLength": 15, + "plant_id": { "type": "string" }, "type": { - "description": "Account type of user.", + "description": "The type of account indicating the user's access level and permissions. Determines available operations and data access.", "enum": [ + "manager", "viewer", - "manager" - ], - "examples": [ - "viewer" + "temporary" ], "type": "string" }, "username": { - "description": "User username to grant access for. Used when Role is viewer", + "description": "User username to grant access for. Used when Role is viewer or temporary", "examples": [ "usr123456789012" ], @@ -3203,68 +3383,24 @@ } }, "required": [ - "plantId", + "plant_id", "type" ], "type": "object" }, - "OrgAddPermissionOutputBody": { + "OrgInfo": { "additionalProperties": false, "properties": { - "$schema": { - "description": "A URL to the JSON Schema for this object.", - "examples": [ - "https://patch-api.conalog.com/schemas/OrgAddPermissionOutputBody.json" - ], - "format": "uri", - "readOnly": true, + "icon": { "type": "string" }, - "email": { - "description": "User email to grant access for. Used when Role is manager", - "examples": [ - "usr123456789012@conalog.com" - ], + "id": { "type": "string" }, - "plant_id": { + "logo": { "type": "string" }, - "type": { - "description": "The type of account indicating the user's access level and permissions. Determines available operations and data access.", - "enum": [ - "manager", - "viewer" - ], - "type": "string" - }, - "username": { - "description": "User username to grant access for. Used when Role is viewer", - "examples": [ - "usr123456789012" - ], - "type": "string" - } - }, - "required": [ - "plant_id", - "type" - ], - "type": "object" - }, - "OrgInfo": { - "additionalProperties": false, - "properties": { - "icon": { - "type": "string" - }, - "id": { - "type": "string" - }, - "logo": { - "type": "string" - }, - "name": { + "name": { "type": "string" }, "owner": { @@ -3743,6 +3879,15 @@ "RegisterBody": { "additionalProperties": false, "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/RegisterBody.json" + ], + "format": "uri", + "readOnly": true, + "type": "string" + }, "asset_id": { "description": "Unique identifier for the physical asset to be registered (e.g., device serial number, inverter ID)", "examples": [ @@ -3799,18 +3944,35 @@ "type": "string" }, "registered_meta": { - "description": "Additional metadata associated with the registration event (JSON string or custom format)", - "examples": [ - "{\"installer\": \"John Doe\", \"warranty\": \"2029-01-24\"}" - ], - "type": "string" + "description": "Registration action metadata. Structured form accepts an object with JSON values; legacy string is still accepted.", + "oneOf": [ + { + "additionalProperties": true, + "description": "Registration action metadata as a flat object with JSON values. Limited to 4096 bytes, 32 keys, key length 64, and value JSON size 1024 bytes.", + "maxProperties": 32, + "type": "object" + }, + { + "deprecated": true, + "description": "Deprecated compatibility form. Use structured actor metadata instead. The full meta JSON value is limited to 4096 bytes.", + "maxLength": 4094, + "type": "string" + } + ] }, "tag": { - "description": "Optional descriptive tag or label for the asset (e.g., location, purpose, or custom identifier)", - "examples": [ - "North Array Panel 5" - ], - "type": "string" + "description": "Optional tag metadata for the asset.", + "oneOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "deprecated": true, + "description": "Deprecated compatibility form. Use an object instead.", + "type": "string" + } + ] } }, "required": [ @@ -4051,6 +4213,48 @@ ], "type": "object" }, + "SetTemporaryExpiredBody": { + "additionalProperties": false, + "properties": { + "expired": { + "description": "Expiration timestamp to set on the temporary account.", + "examples": [ + "2026-06-11 00:00:00.000Z" + ], + "type": "string" + }, + "id": { + "description": "Temporary account record ID.", + "examples": [ + "temporary123456" + ], + "type": "string" + } + }, + "required": [ + "id", + "expired" + ], + "type": "object" + }, + "SetTemporaryExpiredOutputBody": { + "additionalProperties": false, + "properties": { + "expired": { + "description": "Updated expiration timestamp.", + "type": "string" + }, + "id": { + "description": "Temporary account record ID.", + "type": "string" + } + }, + "required": [ + "id", + "expired" + ], + "type": "object" + }, "StatModelCount": { "additionalProperties": false, "properties": { @@ -4139,6 +4343,15 @@ "UnregisterBody": { "additionalProperties": false, "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/UnregisterBody.json" + ], + "format": "uri", + "readOnly": true, + "type": "string" + }, "asset_id": { "description": "Unique identifier for the physical asset to be unregistered (must match the originally registered asset ID)", "examples": [ @@ -4187,11 +4400,18 @@ "type": "string" }, "tag": { - "description": "Optional descriptive tag or label for the asset (should match the originally registered tag if applicable)", - "examples": [ - "North Array Panel 5" - ], - "type": "string" + "description": "Optional tag metadata for the asset.", + "oneOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "deprecated": true, + "description": "Deprecated compatibility form. Use an object instead.", + "type": "string" + } + ] }, "unregistered": { "description": "Timestamp when the asset should be considered unregistered. Must be in RFC3339 format and should be after the original registration date.", @@ -4202,11 +4422,21 @@ "type": "string" }, "unregistered_meta": { - "description": "Additional metadata associated with the unregistration event (JSON string or custom format)", - "examples": [ - "{\"reason\": \"Equipment replacement\", \"technician\": \"Jane Smith\"}" - ], - "type": "string" + "description": "Unregistration action metadata. Structured form accepts an object with JSON values; legacy string is still accepted.", + "oneOf": [ + { + "additionalProperties": true, + "description": "Registration action metadata as a flat object with JSON values. Limited to 4096 bytes, 32 keys, key length 64, and value JSON size 1024 bytes.", + "maxProperties": 32, + "type": "object" + }, + { + "deprecated": true, + "description": "Deprecated compatibility form. Use structured actor metadata instead. The full meta JSON value is limited to 4096 bytes.", + "maxLength": 4094, + "type": "string" + } + ] } }, "required": [ @@ -4286,16 +4516,16 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "enum": [ "viewer", "manager", - "admin" + "temporary" ], "type": "string" } @@ -4456,7 +4686,7 @@ }, "/api/v3/account/auth-with-password": { "post": { - "description": "Authenticates users using either email (for managers) or username (for viewers) with password. The response includes an authentication token for subsequent API calls. This endpoint does not require the Authorization header.", + "description": "Authenticates users using either email (for managers) or username (for viewers and temporary accounts) with password. The response includes an authentication token for subsequent API calls. This endpoint does not require the Authorization header.", "operationId": "authenticate_user", "requestBody": { "content": { @@ -4578,16 +4808,16 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "enum": [ "viewer", "manager", - "admin" + "temporary" ], "type": "string" } @@ -4643,16 +4873,16 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "enum": [ "viewer", "manager", - "admin" + "temporary" ], "type": "string" } @@ -4707,16 +4937,16 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "enum": [ "viewer", "manager", - "admin" + "temporary" ], "type": "string" } @@ -4771,16 +5001,16 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "enum": [ "viewer", "manager", - "admin" + "temporary" ], "type": "string" } @@ -4835,16 +5065,15 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Organization routes are available to manager and viewer accounts only.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Organization routes are available to manager and viewer accounts only.", "enum": [ "viewer", - "manager", - "admin" + "manager" ], "type": "string" } @@ -4911,29 +5140,29 @@ }, "/api/v3/organizations/{organization_id}/permissions": { "post": { - "description": "Grants a user a specific role-based permission (viewer, user, temporary) to access a plant under the given organization.", + "description": "Grants a user a specific role-based permission (viewer, manager, temporary) to access a plant under the given organization.", "operationId": "assign_plant_permission", "parameters": [ { "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", "in": "header", "name": "Authorization", + "required": true, "schema": { "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", "type": "string" } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Organization routes are available to manager and viewer accounts only.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Organization routes are available to manager and viewer accounts only.", "enum": [ "viewer", - "manager", - "admin" + "manager" ], "type": "string" } @@ -4958,7 +5187,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/OrgAddPermissionInputBody", + "$ref": "#/components/schemas/AssignOrganizationPermissionRequestBody", "description": "Request body for assigning plant permission to a user" } } @@ -5015,16 +5244,15 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Plant collection routes are available to manager and viewer accounts only.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Plant collection routes are available to manager and viewer accounts only.", "enum": [ "viewer", - "manager", - "admin" + "manager" ], "type": "string" } @@ -5174,16 +5402,15 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Plant collection routes are available to manager and viewer accounts only.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Plant collection routes are available to manager and viewer accounts only.", "enum": [ "viewer", - "manager", - "admin" + "manager" ], "type": "string" } @@ -5250,16 +5477,16 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "enum": [ "viewer", "manager", - "admin" + "temporary" ], "type": "string" } @@ -5389,16 +5616,16 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the blueprint account type making the request. Supported values map to public blueprint collections: 'manager', 'viewer', and 'temporary'.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the blueprint account type making the request. Supported values map to public blueprint collections: 'manager', 'viewer', and 'temporary'.", "enum": [ - "viewer", "manager", - "admin" + "viewer", + "temporary" ], "type": "string" } @@ -5527,16 +5754,16 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the blueprint account type making the request. Supported values map to public blueprint collections: 'manager', 'viewer', and 'temporary'.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the blueprint account type making the request. Supported values map to public blueprint collections: 'manager', 'viewer', and 'temporary'.", "enum": [ - "viewer", "manager", - "admin" + "viewer", + "temporary" ], "type": "string" } @@ -5598,6 +5825,95 @@ ] } }, + "/api/v3/plants/{plant_id}/blueprints/record": { + "post": { + "description": "Records a new immutable blueprint snapshot for a plant. This endpoint never mutates an existing blueprint record. On success, it invalidates the plant blueprint timeline/list cache.", + "operationId": "record_plant_blueprint", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the blueprint account type making the request. Blueprint record writes are available to manager accounts only.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the blueprint account type making the request. Blueprint record writes are available to manager accounts only.", + "enum": [ + "manager" + ], + "type": "string" + } + }, + { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation to record blueprint data for. Must be exactly 15 characters in length.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation to record blueprint data for. Must be exactly 15 characters in length.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "patternDescription": "alphanum", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BlueprintWriteBody" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BlueprintRecordPayload", + "description": "Recorded immutable blueprint snapshot." + } + } + }, + "description": "Created" + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Record Plant Blueprint Snapshot", + "tags": [ + "v3/plants/blueprints" + ] + } + }, "/api/v3/plants/{plant_id}/blueprints/{blueprint_id}": { "get": { "description": "Retrieves a specific blueprint record on a plant, including record metadata and the data payload. Authorization header and Account-Type header are required.", @@ -5614,16 +5930,16 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the blueprint account type making the request. Supported values map to public blueprint collections: 'manager', 'viewer', and 'temporary'.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the blueprint account type making the request. Supported values map to public blueprint collections: 'manager', 'viewer', and 'temporary'.", "enum": [ - "viewer", "manager", - "admin" + "viewer", + "temporary" ], "type": "string" } @@ -5817,16 +6133,16 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "enum": [ "viewer", "manager", - "admin" + "temporary" ], "type": "string" } @@ -5855,7 +6171,7 @@ "application/json": { "schema": { "items": { - "$ref": "#/components/schemas/CommentOutput" + "$ref": "#/components/schemas/CommentReadOutput" }, "type": [ "array", @@ -5904,16 +6220,15 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Plant comment mutation routes are available to manager and viewer accounts only.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Plant comment mutation routes are available to manager and viewer accounts only.", "enum": [ "viewer", - "manager", - "admin" + "manager" ], "type": "string" } @@ -5979,163 +6294,6 @@ ] } }, - "/api/v3/plants/{plant_id}/comments/{comment_id}": { - "get": { - "description": "Retrieves a specific comment for a plant.", - "operationId": "get_plant_comment", - "parameters": [ - { - "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", - "in": "header", - "name": "Authorization", - "required": true, - "schema": { - "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", - "type": "string" - } - }, - { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", - "in": "header", - "name": "Account-Type", - "required": true, - "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", - "enum": [ - "viewer", - "manager", - "admin" - ], - "type": "string" - } - }, - { - "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", - "in": "path", - "name": "plant_id", - "required": true, - "schema": { - "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", - "examples": [ - "unw4id41ud2p0wt" - ], - "maxLength": 15, - "minLength": 15, - "pattern": "^[a-zA-Z0-9]{15}$", - "patternDescription": "alphanum", - "type": "string" - } - }, - { - "description": "Comment ID. A unique alphanumeric identifier representing the comment. Must be exactly 15 characters in length.", - "in": "path", - "name": "comment_id", - "required": true, - "schema": { - "description": "Comment ID. A unique alphanumeric identifier representing the comment. Must be exactly 15 characters in length.", - "examples": [ - "unw4id41ud2p0wt" - ], - "maxLength": 15, - "minLength": 15, - "pattern": "^[a-zA-Z0-9]{15}$", - "patternDescription": "alphanum", - "type": "string" - } - }, - { - "description": "Succeeds if the server's resource matches one of the passed values.", - "in": "header", - "name": "If-Match", - "schema": { - "description": "Succeeds if the server's resource matches one of the passed values.", - "items": { - "type": "string" - }, - "type": [ - "array", - "null" - ] - } - }, - { - "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", - "in": "header", - "name": "If-None-Match", - "schema": { - "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", - "items": { - "type": "string" - }, - "type": [ - "array", - "null" - ] - } - }, - { - "description": "Succeeds if the server's resource date is more recent than the passed date.", - "in": "header", - "name": "If-Modified-Since", - "schema": { - "description": "Succeeds if the server's resource date is more recent than the passed date.", - "format": "date-time-http", - "type": "string" - } - }, - { - "description": "Succeeds if the server's resource date is older or the same as the passed date.", - "in": "header", - "name": "If-Unmodified-Since", - "schema": { - "description": "Succeeds if the server's resource date is older or the same as the passed date.", - "format": "date-time-http", - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CommentOutput", - "description": "Plant comment detail." - } - } - }, - "description": "OK", - "headers": { - "ETag": { - "schema": { - "description": "Weak entity tag for conditional requests.", - "type": "string" - } - } - } - }, - "default": { - "content": { - "application/problem+json": { - "schema": { - "$ref": "#/components/schemas/ErrorModel" - } - } - }, - "description": "Error" - } - }, - "security": [ - { - "bearer": [] - } - ], - "summary": "Get Plant Comment", - "tags": [ - "v3/plants/comments" - ] - } - }, "/api/v3/plants/{plant_id}/comments/{comment_id}/edit": { "post": { "description": "Edits a specific plant comment.", @@ -6152,16 +6310,15 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Plant comment mutation routes are available to manager and viewer accounts only.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Plant comment mutation routes are available to manager and viewer accounts only.", "enum": [ "viewer", - "manager", - "admin" + "manager" ], "type": "string" } @@ -6259,16 +6416,15 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Plant comment mutation routes are available to manager and viewer accounts only.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Plant comment mutation routes are available to manager and viewer accounts only.", "enum": [ "viewer", - "manager", - "admin" + "manager" ], "type": "string" } @@ -6367,16 +6523,15 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Plant comment mutation routes are available to manager and viewer accounts only.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Plant comment mutation routes are available to manager and viewer accounts only.", "enum": [ "viewer", - "manager", - "admin" + "manager" ], "type": "string" } @@ -6461,7 +6616,7 @@ }, "/api/v3/plants/{plant_id}/filters": { "get": { - "description": "Lists reusable map object filters for a specific plant without including each filter's condition payload.", + "description": "Lists reusable map object filters for a specific plant, including each filter's map object IDs.", "operationId": "list_plant_filters", "parameters": [ { @@ -6475,16 +6630,16 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "enum": [ "viewer", "manager", - "admin" + "temporary" ], "type": "string" } @@ -6512,7 +6667,7 @@ "content": { "application/json": { "schema": { - "description": "Plant filters without condition payloads.", + "description": "Plant filters with map object IDs.", "items": { "$ref": "#/components/schemas/FilterListItem" }, @@ -6549,7 +6704,7 @@ }, "/api/v3/plants/{plant_id}/filters/create": { "post": { - "description": "Creates a reusable map object filter for a specific plant. The request map IDs are stored internally as merge conditions.", + "description": "Creates a reusable map object filter for a specific plant from the provided map IDs.", "operationId": "create_plant_filter", "parameters": [ { @@ -6563,16 +6718,15 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Plant filter mutation routes are available to manager and viewer accounts only.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Plant filter mutation routes are available to manager and viewer accounts only.", "enum": [ "viewer", - "manager", - "admin" + "manager" ], "type": "string" } @@ -6606,103 +6760,16 @@ "required": true }, "responses": { - "201": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Filter", - "description": "Created plant filter." - } - } - }, - "description": "Created" - }, - "default": { - "content": { - "application/problem+json": { - "schema": { - "$ref": "#/components/schemas/ErrorModel" - } - } - }, - "description": "Error" - } - }, - "security": [ - { - "bearer": [] - } - ], - "summary": "Create Plant Filter", - "tags": [ - "v3/plants/filters" - ] - } - }, - "/api/v3/plants/{plant_id}/filters/{filter_id}": { - "delete": { - "description": "Deletes a reusable map object filter for a specific plant.", - "operationId": "delete_plant_filter", - "parameters": [ - { - "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", - "in": "header", - "name": "Authorization", - "required": true, - "schema": { - "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", - "type": "string" - } - }, - { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", - "in": "header", - "name": "Account-Type", - "required": true, - "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", - "enum": [ - "viewer", - "manager", - "admin" - ], - "type": "string" - } - }, - { - "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", - "in": "path", - "name": "plant_id", - "required": true, - "schema": { - "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", - "examples": [ - "unw4id41ud2p0wt" - ], - "maxLength": 15, - "minLength": 15, - "pattern": "^[a-zA-Z0-9]{15}$", - "patternDescription": "alphanum", - "type": "string" - } - }, - { - "description": "Filter record ID.", - "in": "path", - "name": "filter_id", - "required": true, - "schema": { - "description": "Filter record ID.", - "examples": [ - "filter123456789" - ], - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "No Content" + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FilterOutput", + "description": "Created plant filter." + } + } + }, + "description": "Created" }, "default": { "content": { @@ -6720,14 +6787,16 @@ "bearer": [] } ], - "summary": "Delete Plant Filter", + "summary": "Create Plant Filter", "tags": [ "v3/plants/filters" ] - }, - "get": { - "description": "Retrieves a reusable map object filter for a specific plant, including its condition payload.", - "operationId": "get_plant_filter", + } + }, + "/api/v3/plants/{plant_id}/filters/{filter_id}": { + "delete": { + "description": "Deletes a reusable map object filter for a specific plant.", + "operationId": "delete_plant_filter", "parameters": [ { "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", @@ -6740,16 +6809,15 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Plant filter mutation routes are available to manager and viewer accounts only.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Plant filter mutation routes are available to manager and viewer accounts only.", "enum": [ "viewer", - "manager", - "admin" + "manager" ], "type": "string" } @@ -6783,77 +6851,11 @@ ], "type": "string" } - }, - { - "description": "Succeeds if the server's resource matches one of the passed values.", - "in": "header", - "name": "If-Match", - "schema": { - "description": "Succeeds if the server's resource matches one of the passed values.", - "items": { - "type": "string" - }, - "type": [ - "array", - "null" - ] - } - }, - { - "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", - "in": "header", - "name": "If-None-Match", - "schema": { - "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", - "items": { - "type": "string" - }, - "type": [ - "array", - "null" - ] - } - }, - { - "description": "Succeeds if the server's resource date is more recent than the passed date.", - "in": "header", - "name": "If-Modified-Since", - "schema": { - "description": "Succeeds if the server's resource date is more recent than the passed date.", - "format": "date-time-http", - "type": "string" - } - }, - { - "description": "Succeeds if the server's resource date is older or the same as the passed date.", - "in": "header", - "name": "If-Unmodified-Since", - "schema": { - "description": "Succeeds if the server's resource date is older or the same as the passed date.", - "format": "date-time-http", - "type": "string" - } } ], "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Filter", - "description": "Plant filter detail." - } - } - }, - "description": "OK", - "headers": { - "ETag": { - "schema": { - "description": "Weak entity tag for conditional requests.", - "type": "string" - } - } - } + "204": { + "description": "No Content" }, "default": { "content": { @@ -6871,7 +6873,7 @@ "bearer": [] } ], - "summary": "Get Plant Filter", + "summary": "Delete Plant Filter", "tags": [ "v3/plants/filters" ] @@ -6893,16 +6895,15 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Plant filter mutation routes are available to manager and viewer accounts only.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Plant filter mutation routes are available to manager and viewer accounts only.", "enum": [ "viewer", - "manager", - "admin" + "manager" ], "type": "string" } @@ -6953,7 +6954,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Filter", + "$ref": "#/components/schemas/FilterOutput", "description": "Renamed plant filter." } } @@ -6998,16 +6999,16 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "enum": [ "viewer", "manager", - "admin" + "temporary" ], "type": "string" } @@ -7214,16 +7215,16 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "enum": [ "viewer", "manager", - "admin" + "temporary" ], "type": "string" } @@ -7357,16 +7358,16 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "enum": [ "viewer", "manager", - "admin" + "temporary" ], "type": "string" } @@ -7484,16 +7485,16 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "enum": [ "viewer", "manager", - "admin" + "temporary" ], "type": "string" } @@ -7621,16 +7622,16 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "enum": [ "viewer", "manager", - "admin" + "temporary" ], "type": "string" } @@ -7791,16 +7792,16 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "enum": [ "viewer", "manager", - "admin" + "temporary" ], "type": "string" } @@ -7932,16 +7933,16 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "enum": [ "viewer", "manager", - "admin" + "temporary" ], "type": "string" } @@ -8732,16 +8733,16 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "enum": [ "viewer", "manager", - "admin" + "temporary" ], "type": "string" } @@ -8892,16 +8893,16 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "enum": [ "viewer", "manager", - "admin" + "temporary" ], "type": "string" } @@ -9113,16 +9114,16 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "enum": [ "viewer", "manager", - "admin" + "temporary" ], "type": "string" } @@ -9318,6 +9319,97 @@ ] } }, + "/api/v3/plants/{plant_id}/registry/register": { + "post": { + "description": "Registers a new asset (device, inverter, etc.) to the specified plant with mapping and metadata information.", + "operationId": "register_asset_to_plant", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", + "enum": [ + "viewer", + "manager", + "temporary" + ], + "type": "string" + } + }, + { + "description": "Patch Plant ID. A unique alphanumeric identifier representing the plant to fetch data for. Must be exactly 15 characters in length.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Patch Plant ID. A unique alphanumeric identifier representing the plant to fetch data for. Must be exactly 15 characters in length.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "patternDescription": "alphanum", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegisterBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Confirmation message indicating successful asset registration or operation details", + "type": "string" + } + } + }, + "description": "OK" + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Register Asset to Plant", + "tags": [ + "v3/plants/registry" + ] + } + }, "/api/v3/plants/{plant_id}/registry/snapshots": { "get": { "description": "Retrieves registry snapshot records for the specified plant and date, with optional asset_id, map_id, asset_type, and map_type filters.", @@ -9334,16 +9426,16 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "enum": [ "viewer", "manager", - "admin" + "temporary" ], "type": "string" } @@ -9555,16 +9647,16 @@ } }, { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'admin' grants full system access.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "enum": [ "viewer", "manager", - "admin" + "temporary" ], "type": "string" } @@ -9692,6 +9784,97 @@ "v3/plants/registry" ] } + }, + "/api/v3/plants/{plant_id}/registry/unregister": { + "post": { + "description": "Unregisters an existing asset (device, inverter, etc.) from the specified plant when equipment is replaced or removed.", + "operationId": "unregister_asset_from_plant", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", + "enum": [ + "viewer", + "manager", + "temporary" + ], + "type": "string" + } + }, + { + "description": "Patch Plant ID. A unique alphanumeric identifier representing the plant to fetch data for. Must be exactly 15 characters in length.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Patch Plant ID. A unique alphanumeric identifier representing the plant to fetch data for. Must be exactly 15 characters in length.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "patternDescription": "alphanum", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnregisterBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Confirmation message indicating successful asset unregistration or operation details", + "type": "string" + } + } + }, + "description": "OK" + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Unregister Asset from Plant", + "tags": [ + "v3/plants/registry" + ] + } } }, "servers": [ From c6024633fc806e3a09fcaf8198cbe1f2e13d7191 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 15 Jun 2026 01:17:32 +0000 Subject: [PATCH 09/11] chore: sync openapi v3 snapshot --- openapi/openapi-v3.json | 436 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 420 insertions(+), 16 deletions(-) diff --git a/openapi/openapi-v3.json b/openapi/openapi-v3.json index 0531327..10be54d 100644 --- a/openapi/openapi-v3.json +++ b/openapi/openapi-v3.json @@ -2331,6 +2331,9 @@ "FilterListItem": { "additionalProperties": false, "properties": { + "condition": { + "description": "JSONLogic condition body for non-merge filters." + }, "created": { "description": "Filter record creation timestamp.", "type": "string" @@ -2378,6 +2381,9 @@ "readOnly": true, "type": "string" }, + "condition": { + "description": "JSONLogic condition body for non-merge filters." + }, "created": { "description": "Filter record creation timestamp.", "type": "string" @@ -3457,6 +3463,10 @@ "PanelDailyData": { "additionalProperties": false, "properties": { + "date": { + "description": "Date of the data point in YYYY-MM-DD format", + "type": "string" + }, "energy": { "description": "Total daily energy production (kWh)", "format": "double", @@ -3469,6 +3479,7 @@ }, "required": [ "id", + "date", "energy" ], "type": "object" @@ -3895,6 +3906,11 @@ ], "type": "string" }, + "asset_model": { + "additionalProperties": {}, + "description": "Optional asset model information to store with the registry record.", + "type": "object" + }, "asset_type": { "description": "Classification of the physical asset being registered", "enum": [ @@ -4050,9 +4066,18 @@ "description": "Sanitized registration actor metadata. Only fielder_name and fielder_org are exposed." }, "tag": { - "additionalProperties": {}, "description": "Additional metadata and tags associated with the asset registration", - "type": "object" + "oneOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "deprecated": true, + "description": "Deprecated compatibility form. Use an object instead.", + "type": "string" + } + ] }, "unregistered": { "description": "Timestamp when the asset was unregistered in RFC3339 format (empty if still registered)", @@ -4399,20 +4424,6 @@ ], "type": "string" }, - "tag": { - "description": "Optional tag metadata for the asset.", - "oneOf": [ - { - "additionalProperties": true, - "type": "object" - }, - { - "deprecated": true, - "description": "Deprecated compatibility form. Use an object instead.", - "type": "string" - } - ] - }, "unregistered": { "description": "Timestamp when the asset should be considered unregistered. Must be in RFC3339 format and should be after the original registration date.", "examples": [ @@ -4484,6 +4495,184 @@ } }, "type": "object" + }, + "WeatherForecastDaily": { + "additionalProperties": false, + "properties": { + "img_1x": { + "type": "string" + }, + "img_2x": { + "type": "string" + }, + "img_4x": { + "type": "string" + }, + "precip_prob": { + "format": "double", + "type": "number" + }, + "temp_max_c": { + "format": "double", + "type": "number" + }, + "temp_min_c": { + "format": "double", + "type": "number" + }, + "wmo_code": { + "format": "int64", + "type": "integer" + } + }, + "type": "object" + }, + "WeatherForecastHour": { + "additionalProperties": false, + "properties": { + "img_1x": { + "type": "string" + }, + "img_2x": { + "type": "string" + }, + "img_4x": { + "type": "string" + }, + "precip_prob": { + "format": "double", + "type": "number" + }, + "temp_c": { + "format": "double", + "type": "number" + }, + "time": { + "type": "string" + }, + "wmo_code": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "time" + ], + "type": "object" + }, + "WeatherForecastRow": { + "additionalProperties": false, + "properties": { + "daily": { + "$ref": "#/components/schemas/WeatherForecastDaily" + }, + "hourly": { + "items": { + "$ref": "#/components/schemas/WeatherForecastHour" + }, + "type": [ + "array", + "null" + ] + }, + "local_date": { + "type": "string" + } + }, + "required": [ + "local_date", + "daily" + ], + "type": "object" + }, + "WeatherObservedDaily": { + "additionalProperties": false, + "properties": { + "img_1x": { + "type": "string" + }, + "img_2x": { + "type": "string" + }, + "img_4x": { + "type": "string" + }, + "precip_prob": { + "format": "double", + "type": "number" + }, + "temp_max_c": { + "format": "double", + "type": "number" + }, + "temp_min_c": { + "format": "double", + "type": "number" + }, + "wmo_code": { + "format": "int64", + "type": "integer" + } + }, + "type": "object" + }, + "WeatherObservedHour": { + "additionalProperties": false, + "properties": { + "img_1x": { + "type": "string" + }, + "img_2x": { + "type": "string" + }, + "img_4x": { + "type": "string" + }, + "precip_prob": { + "format": "double", + "type": "number" + }, + "temp_c": { + "format": "double", + "type": "number" + }, + "time": { + "type": "string" + }, + "wmo_code": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "time" + ], + "type": "object" + }, + "WeatherObservedRow": { + "additionalProperties": false, + "properties": { + "daily": { + "$ref": "#/components/schemas/WeatherObservedDaily" + }, + "hourly": { + "items": { + "$ref": "#/components/schemas/WeatherObservedHour" + }, + "type": [ + "array", + "null" + ] + }, + "local_date": { + "type": "string" + } + }, + "required": [ + "local_date", + "daily" + ], + "type": "object" } }, "securitySchemes": { @@ -9875,6 +10064,221 @@ "v3/plants/registry" ] } + }, + "/api/v3/plants/{plant_id}/weather/forecast": { + "get": { + "description": "Retrieves weather forecast rows for the specified plant by using the plant metadata address and forwarding to weather-api.", + "operationId": "get_plant_weather_forecast", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", + "enum": [ + "viewer", + "manager", + "temporary" + ], + "type": "string" + } + }, + { + "description": "Plant ID. A unique alphanumeric identifier representing the plant to fetch weather forecast data for.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Plant ID. A unique alphanumeric identifier representing the plant to fetch weather forecast data for.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "patternDescription": "alphanum", + "type": "string" + } + }, + { + "description": "Number of forecast days to request from weather-api, including the current day.", + "explode": false, + "in": "query", + "name": "days", + "schema": { + "default": 7, + "description": "Number of forecast days to request from weather-api, including the current day.", + "format": "int64", + "maximum": 7, + "minimum": 1, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/WeatherForecastRow" + }, + "type": [ + "array", + "null" + ] + } + } + }, + "description": "OK" + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Retrieve Plant Weather Forecast", + "tags": [ + "v3/plants/weather" + ] + } + }, + "/api/v3/plants/{plant_id}/weather/observed": { + "get": { + "description": "Retrieves observed weather rows for the specified plant and date by using the plant metadata address and forwarding to weather-api.", + "operationId": "get_plant_weather_observed", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", + "enum": [ + "viewer", + "manager", + "temporary" + ], + "type": "string" + } + }, + { + "description": "Plant ID. A unique alphanumeric identifier representing the plant to fetch observed weather data for.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Plant ID. A unique alphanumeric identifier representing the plant to fetch observed weather data for.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "patternDescription": "alphanum", + "type": "string" + } + }, + { + "description": "Local date to fetch observed weather for, formatted as YYYY-MM-DD.", + "explode": false, + "in": "query", + "name": "date", + "required": true, + "schema": { + "description": "Local date to fetch observed weather for, formatted as YYYY-MM-DD.", + "examples": [ + "2026-04-13" + ], + "format": "date", + "type": "string" + } + }, + { + "description": "Number of observed days to include up to and including date.", + "explode": false, + "in": "query", + "name": "before", + "schema": { + "default": 1, + "description": "Number of observed days to include up to and including date.", + "format": "int64", + "maximum": 31, + "minimum": 1, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/WeatherObservedRow" + }, + "type": [ + "array", + "null" + ] + } + } + }, + "description": "OK" + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Retrieve Plant Observed Weather", + "tags": [ + "v3/plants/weather" + ] + } } }, "servers": [ From e3879a597b1fda198a5d5c6a2223f52362469c07 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 22 Jun 2026 01:17:14 +0000 Subject: [PATCH 10/11] chore: sync openapi v3 snapshot --- openapi/openapi-v3.json | 1490 ++++++++++++++++++++++++++++++++------- 1 file changed, 1227 insertions(+), 263 deletions(-) diff --git a/openapi/openapi-v3.json b/openapi/openapi-v3.json index 10be54d..d0044ab 100644 --- a/openapi/openapi-v3.json +++ b/openapi/openapi-v3.json @@ -83,15 +83,6 @@ ], "type": "string" }, - "plantId": { - "description": "Target plant ID to grant access to.", - "examples": [ - "pln123456789012" - ], - "maxLength": 15, - "minLength": 15, - "type": "string" - }, "type": { "description": "Account type of user.", "enum": [ @@ -113,43 +104,10 @@ } }, "required": [ - "plantId", "type" ], "type": "object" }, - "AuthAccountBody": { - "additionalProperties": false, - "properties": { - "$schema": { - "description": "A URL to the JSON Schema for this object.", - "examples": [ - "https://patch-api.conalog.com/schemas/AuthAccountBody.json" - ], - "format": "uri", - "readOnly": true, - "type": "string" - }, - "account": { - "description": "The user's account name or username used for authentication", - "examples": [ - "viewer_user" - ], - "type": "string" - }, - "password": { - "description": "The user's password for authentication", - "examples": [ - "securepassword123" - ], - "type": "string" - } - }, - "required": [ - "account" - ], - "type": "object" - }, "AuthBody": { "additionalProperties": false, "properties": { @@ -183,38 +141,6 @@ ], "type": "object" }, - "AuthEmailBody": { - "additionalProperties": false, - "properties": { - "$schema": { - "description": "A URL to the JSON Schema for this object.", - "examples": [ - "https://patch-api.conalog.com/schemas/AuthEmailBody.json" - ], - "format": "uri", - "readOnly": true, - "type": "string" - }, - "email": { - "description": "The user's email address used for authentication", - "examples": [ - "manager@example.com" - ], - "type": "string" - }, - "password": { - "description": "The user's password for authentication", - "examples": [ - "securepassword123" - ], - "type": "string" - } - }, - "required": [ - "email" - ], - "type": "object" - }, "AuthMethodsBody": { "additionalProperties": false, "properties": { @@ -385,7 +311,7 @@ "type": "string" }, "email": { - "description": "The user's email address. Required when authenticating as a 'manager' account type.", + "description": "The user's email address. Accepted when authenticating as a 'manager' account type.", "examples": [ "manager@example.com" ], @@ -409,7 +335,7 @@ "type": "string" }, "username": { - "description": "The user's username. Required when authenticating as a 'viewer' or 'temporary' account type.", + "description": "The user's username. Accepted for 'manager' accounts and required when authenticating as a 'viewer' or 'temporary' account type.", "examples": [ "viewer_user" ], @@ -1263,10 +1189,6 @@ }, "type": "array" }, - "is_private": { - "description": "Private flag.", - "type": "boolean" - }, "map_ids": { "description": "Plant map object IDs attached to the comment.", "items": { @@ -1317,10 +1239,6 @@ }, "type": "array" }, - "is_private": { - "description": "Private flag.", - "type": "boolean" - }, "map_ids": { "description": "Plant map object IDs attached to the comment.", "items": { @@ -1386,9 +1304,6 @@ "null" ] }, - "is_private": { - "type": "boolean" - }, "map_ids": { "items": { "type": "string" @@ -1450,9 +1365,6 @@ "null" ] }, - "is_private": { - "type": "boolean" - }, "map_ids": { "items": { "type": "string" @@ -1769,9 +1681,6 @@ "isArchive": { "type": "boolean" }, - "isPrivate": { - "type": "boolean" - }, "parent": { "type": "string" }, @@ -2536,6 +2445,34 @@ ], "type": "object" }, + "InternalInvalidatePlantListCacheInputBody": { + "additionalProperties": false, + "properties": { + "account_id": { + "type": "string" + }, + "account_type": { + "type": "string" + } + }, + "required": [ + "account_type", + "account_id" + ], + "type": "object" + }, + "InternalInvalidatePlantListCacheOutputBody": { + "additionalProperties": false, + "properties": { + "accepted": { + "type": "boolean" + } + }, + "required": [ + "accepted" + ], + "type": "object" + }, "InternalWarmCacheBody": { "additionalProperties": false, "properties": { @@ -3422,6 +3359,51 @@ ], "type": "object" }, + "OrgRemovePermissionOutputBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/OrgRemovePermissionOutputBody.json" + ], + "format": "uri", + "readOnly": true, + "type": "string" + }, + "email": { + "description": "User email revoked. Used when Role is manager", + "examples": [ + "usr123456789012@conalog.com" + ], + "type": "string" + }, + "plant_id": { + "type": "string" + }, + "type": { + "description": "The type of account whose plant access was removed.", + "enum": [ + "manager", + "viewer", + "temporary" + ], + "type": "string" + }, + "username": { + "description": "User username revoked. Used when Role is viewer or temporary", + "examples": [ + "usr123456789012" + ], + "type": "string" + } + }, + "required": [ + "plant_id", + "type" + ], + "type": "object" + }, "OrganizationBody": { "additionalProperties": false, "properties": { @@ -3559,6 +3541,10 @@ "null" ] }, + "time": { + "description": "Same time label as date for device panel intraday rows.", + "type": "string" + }, "timestamp": { "description": "Unix timestamp of the measurement", "format": "int64", @@ -3594,6 +3580,7 @@ "cumulative_energy", "id", "date", + "time", "timestamp" ], "type": "object" @@ -3887,6 +3874,46 @@ ], "type": "object" }, + "Record": { + "additionalProperties": false, + "properties": { + "detected": { + "type": "string" + }, + "id": { + "type": "string" + }, + "map_id": { + "type": "string" + }, + "map_type": { + "type": "string" + }, + "plant_id": { + "type": "string" + }, + "resolved": { + "type": "string" + }, + "severity": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "id", + "plant_id", + "map_type", + "map_id", + "type", + "severity", + "detected", + "resolved" + ], + "type": "object" + }, "RegisterBody": { "additionalProperties": false, "properties": { @@ -4100,6 +4127,50 @@ ], "type": "object" }, + "RemoveOrganizationPermissionRequestBody": { + "additionalProperties": false, + "properties": { + "$schema": { + "description": "A URL to the JSON Schema for this object.", + "examples": [ + "https://patch-api.conalog.com/schemas/RemoveOrganizationPermissionRequestBody.json" + ], + "format": "uri", + "readOnly": true, + "type": "string" + }, + "email": { + "description": "User email to revoke access from. Used when Role is manager", + "examples": [ + "usr123456789012@conalog.com" + ], + "type": "string" + }, + "type": { + "description": "Account type of user.", + "enum": [ + "viewer", + "manager", + "temporary" + ], + "examples": [ + "viewer" + ], + "type": "string" + }, + "username": { + "description": "User username to revoke access from. Used when Role is viewer or temporary", + "examples": [ + "usr123456789012" + ], + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, "RenameFilterBody": { "additionalProperties": false, "properties": { @@ -4474,9 +4545,6 @@ "isArchive": { "type": "boolean" }, - "isPrivate": { - "type": "boolean" - }, "parent": { "type": "string" }, @@ -4875,7 +4943,7 @@ }, "/api/v3/account/auth-with-password": { "post": { - "description": "Authenticates users using either email (for managers) or username (for viewers and temporary accounts) with password. The response includes an authentication token for subsequent API calls. This endpoint does not require the Authorization header.", + "description": "Authenticates users using email or username for managers, and username for viewers and temporary accounts, with password. The response includes an authentication token for subsequent API calls. This endpoint does not require the Authorization header.", "operationId": "authenticate_user", "requestBody": { "content": { @@ -5240,7 +5308,7 @@ }, "/api/v3/organizations/{organization_id}/members": { "post": { - "description": "Creates a new user under the specified organization. Alias of POST /api/v3/account.", + "description": "Creates a new user under the specified organization. Only the organization owner may create organization members. Alias of POST /api/v3/account.", "operationId": "create_org_member", "parameters": [ { @@ -5254,14 +5322,13 @@ } }, { - "description": "Specifies the type of user account making the request. Organization routes are available to manager and viewer accounts only.", + "description": "Specifies the type of user account making the request. Every v3/org route requires a manager account that owns the organization.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Organization routes are available to manager and viewer accounts only.", + "description": "Specifies the type of user account making the request. Every v3/org route requires a manager account that owns the organization.", "enum": [ - "viewer", "manager" ], "type": "string" @@ -5327,9 +5394,9 @@ ] } }, - "/api/v3/organizations/{organization_id}/permissions": { + "/api/v3/organizations/{organization_id}/plants/{plant_id}/permissions/grant": { "post": { - "description": "Grants a user a specific role-based permission (viewer, manager, temporary) to access a plant under the given organization.", + "description": "Grants a user a specific role-based permission (viewer, manager, temporary) to access a plant under the given organization. Only the organization owner may add plant permissions.", "operationId": "assign_plant_permission", "parameters": [ { @@ -5343,14 +5410,13 @@ } }, { - "description": "Specifies the type of user account making the request. Organization routes are available to manager and viewer accounts only.", + "description": "Specifies the type of user account making the request. Every v3/org route requires a manager account that owns the organization.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Organization routes are available to manager and viewer accounts only.", + "description": "Specifies the type of user account making the request. Every v3/org route requires a manager account that owns the organization.", "enum": [ - "viewer", "manager" ], "type": "string" @@ -5370,6 +5436,21 @@ "minLength": 15, "type": "string" } + }, + { + "description": "Target plant ID to grant access to.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Target plant ID to grant access to.", + "examples": [ + "pln123456789012" + ], + "maxLength": 15, + "minLength": 15, + "type": "string" + } } ], "requestBody": { @@ -5417,10 +5498,10 @@ ] } }, - "/api/v3/plants": { - "get": { - "description": "Retrieves a paginated list of all solar plants associated with the user's account. Includes plant ID, name, location, organization information, and other relevant details with pagination support.", - "operationId": "get_plant_list", + "/api/v3/organizations/{organization_id}/plants/{plant_id}/permissions/revoke": { + "post": { + "description": "Removes a user's role-based permission (viewer, manager, temporary) to access a plant under the given organization. Only the organization owner may remove plant permissions.", + "operationId": "remove_plant_permission", "parameters": [ { "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", @@ -5433,34 +5514,138 @@ } }, { - "description": "Specifies the type of user account making the request. Plant collection routes are available to manager and viewer accounts only.", + "description": "Specifies the type of user account making the request. Every v3/org route requires a manager account that owns the organization.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Plant collection routes are available to manager and viewer accounts only.", + "description": "Specifies the type of user account making the request. Every v3/org route requires a manager account that owns the organization.", "enum": [ - "viewer", "manager" ], "type": "string" } }, { - "description": "Page number for pagination (1-based indexing). Determines which subset of results to return. Results from (page-1)*size to page*size will be returned.", - "explode": false, - "in": "query", - "name": "page", + "description": "Organization ID that owns the target plant.", + "in": "path", + "name": "organization_id", + "required": true, "schema": { - "default": 1, - "description": "Page number for pagination (1-based indexing). Determines which subset of results to return. Results from (page-1)*size to page*size will be returned.", - "format": "int64", - "minimum": 1, - "type": "integer" - } - }, - { - "description": "Number of items per page for pagination. Controls how many plant installations are returned in a single request. Maximum recommended value is 100.", + "description": "Organization ID that owns the target plant.", + "examples": [ + "org123456789012" + ], + "maxLength": 15, + "minLength": 15, + "type": "string" + } + }, + { + "description": "Target plant ID to revoke access from.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Target plant ID to revoke access from.", + "examples": [ + "pln123456789012" + ], + "maxLength": 15, + "minLength": 15, + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RemoveOrganizationPermissionRequestBody", + "description": "Request body for removing plant permission from a user" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrgRemovePermissionOutputBody", + "description": "Response body with removal result info" + } + } + }, + "description": "OK" + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Remove plant permission from a user", + "tags": [ + "v3/org" + ] + } + }, + "/api/v3/plants": { + "get": { + "description": "Retrieves a paginated list of all solar plants associated with the user's account. Includes plant ID, name, location, organization information, and other relevant details with pagination support.", + "operationId": "get_plant_list", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Plant collection routes are available to manager and viewer accounts only.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Plant collection routes are available to manager and viewer accounts only.", + "enum": [ + "viewer", + "manager" + ], + "type": "string" + } + }, + { + "description": "Page number for pagination (1-based indexing). Determines which subset of results to return. Results from (page-1)*size to page*size will be returned.", + "explode": false, + "in": "query", + "name": "page", + "schema": { + "default": 1, + "description": "Page number for pagination (1-based indexing). Determines which subset of results to return. Results from (page-1)*size to page*size will be returned.", + "format": "int64", + "minimum": 1, + "type": "integer" + } + }, + { + "description": "Number of items per page for pagination. Controls how many plant installations are returned in a single request. Maximum recommended value is 100.", "explode": false, "in": "query", "name": "size", @@ -5591,14 +5776,13 @@ } }, { - "description": "Specifies the type of user account making the request. Plant collection routes are available to manager and viewer accounts only.", + "description": "Specifies the type of user account making the request. Plant creation is available to manager accounts only.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Plant collection routes are available to manager and viewer accounts only.", + "description": "Specifies the type of user account making the request. Plant creation is available to manager accounts only.", "enum": [ - "viewer", "manager" ], "type": "string" @@ -6907,58 +7091,821 @@ } }, { - "description": "Specifies the type of user account making the request. Plant filter mutation routes are available to manager and viewer accounts only.", + "description": "Specifies the type of user account making the request. Plant filter mutation routes are available to manager and viewer accounts only.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Plant filter mutation routes are available to manager and viewer accounts only.", + "enum": [ + "viewer", + "manager" + ], + "type": "string" + } + }, + { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "pattern": "^[a-zA-Z0-9]{15}$", + "patternDescription": "alphanum", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateFilterBody" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FilterOutput", + "description": "Created plant filter." + } + } + }, + "description": "Created" + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Create Plant Filter", + "tags": [ + "v3/plants/filters" + ] + } + }, + "/api/v3/plants/{plant_id}/filters/{filter_id}": { + "delete": { + "description": "Deletes a reusable map object filter for a specific plant.", + "operationId": "delete_plant_filter", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Plant filter mutation routes are available to manager and viewer accounts only.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Plant filter mutation routes are available to manager and viewer accounts only.", + "enum": [ + "viewer", + "manager" + ], + "type": "string" + } + }, + { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "pattern": "^[a-zA-Z0-9]{15}$", + "patternDescription": "alphanum", + "type": "string" + } + }, + { + "description": "Filter record ID.", + "in": "path", + "name": "filter_id", + "required": true, + "schema": { + "description": "Filter record ID.", + "examples": [ + "filter123456789" + ], + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Delete Plant Filter", + "tags": [ + "v3/plants/filters" + ] + } + }, + "/api/v3/plants/{plant_id}/filters/{filter_id}/rename": { + "post": { + "description": "Renames a reusable map object filter for a specific plant.", + "operationId": "rename_plant_filter", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Plant filter mutation routes are available to manager and viewer accounts only.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Plant filter mutation routes are available to manager and viewer accounts only.", + "enum": [ + "viewer", + "manager" + ], + "type": "string" + } + }, + { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "pattern": "^[a-zA-Z0-9]{15}$", + "patternDescription": "alphanum", + "type": "string" + } + }, + { + "description": "Filter record ID.", + "in": "path", + "name": "filter_id", + "required": true, + "schema": { + "description": "Filter record ID.", + "examples": [ + "filter123456789" + ], + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RenameFilterBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FilterOutput", + "description": "Renamed plant filter." + } + } + }, + "description": "OK" + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Rename Plant Filter", + "tags": [ + "v3/plants/filters" + ] + } + }, + "/api/v3/plants/{plant_id}/indicator/anomaly": { + "get": { + "description": "Retrieves active anomaly snapshots from the previous date plus anomaly logs from the requested date.", + "operationId": "get_plant_anomaly_timeline", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", + "enum": [ + "viewer", + "manager", + "temporary" + ], + "type": "string" + } + }, + { + "description": "Patch Plant ID.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Patch Plant ID.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "type": "string" + } + }, + { + "explode": false, + "in": "query", + "name": "date", + "required": true, + "schema": { + "examples": [ + "2026-06-15" + ], + "format": "date", + "type": "string" + } + }, + { + "description": "Succeeds if the server's resource matches one of the passed values.", + "in": "header", + "name": "If-Match", + "schema": { + "description": "Succeeds if the server's resource matches one of the passed values.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "in": "header", + "name": "If-None-Match", + "schema": { + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "Succeeds if the server's resource date is more recent than the passed date.", + "in": "header", + "name": "If-Modified-Since", + "schema": { + "description": "Succeeds if the server's resource date is more recent than the passed date.", + "format": "date-time-http", + "type": "string" + } + }, + { + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "in": "header", + "name": "If-Unmodified-Since", + "schema": { + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "format": "date-time-http", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Array of anomaly records for the specified plant and date.", + "items": { + "$ref": "#/components/schemas/Record" + }, + "type": [ + "array", + "null" + ] + } + } + }, + "description": "OK", + "headers": { + "ETag": { + "schema": { + "description": "Weak entity tag for conditional requests.", + "type": "string" + } + } + } + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Retrieve Plant Anomaly Timeline", + "tags": [ + "v3/plants/indicator" + ] + } + }, + "/api/v3/plants/{plant_id}/indicator/anomaly/logs": { + "get": { + "description": "Retrieves anomaly records detected or resolved on the requested date.", + "operationId": "get_plant_anomaly_logs", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", + "enum": [ + "viewer", + "manager", + "temporary" + ], + "type": "string" + } + }, + { + "description": "Patch Plant ID.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Patch Plant ID.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "type": "string" + } + }, + { + "explode": false, + "in": "query", + "name": "date", + "required": true, + "schema": { + "examples": [ + "2026-06-15" + ], + "format": "date", + "type": "string" + } + }, + { + "description": "Optional anomaly map ID filter.", + "explode": false, + "in": "query", + "name": "map_id", + "schema": { + "description": "Optional anomaly map ID filter.", + "type": "string" + } + }, + { + "description": "Optional anomaly map type filter.", + "explode": false, + "in": "query", + "name": "map_type", + "schema": { + "description": "Optional anomaly map type filter.", + "enum": [ + "plant", + "inverter", + "string", + "panel" + ], + "type": "string" + } + }, + { + "description": "Optional anomaly type filter.", + "explode": false, + "in": "query", + "name": "type", + "schema": { + "description": "Optional anomaly type filter.", + "type": "string" + } + }, + { + "description": "Optional severity filter.", + "explode": false, + "in": "query", + "name": "severity", + "schema": { + "description": "Optional severity filter.", + "enum": [ + "low", + "medium", + "high" + ], + "type": "string" + } + }, + { + "description": "Succeeds if the server's resource matches one of the passed values.", + "in": "header", + "name": "If-Match", + "schema": { + "description": "Succeeds if the server's resource matches one of the passed values.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "in": "header", + "name": "If-None-Match", + "schema": { + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "Succeeds if the server's resource date is more recent than the passed date.", + "in": "header", + "name": "If-Modified-Since", + "schema": { + "description": "Succeeds if the server's resource date is more recent than the passed date.", + "format": "date-time-http", + "type": "string" + } + }, + { + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "in": "header", + "name": "If-Unmodified-Since", + "schema": { + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "format": "date-time-http", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "description": "Array of anomaly records for the specified plant and date.", + "items": { + "$ref": "#/components/schemas/Record" + }, + "type": [ + "array", + "null" + ] + } + } + }, + "description": "OK", + "headers": { + "ETag": { + "schema": { + "description": "Weak entity tag for conditional requests.", + "type": "string" + } + } + } + }, + "default": { + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + }, + "description": "Error" + } + }, + "security": [ + { + "bearer": [] + } + ], + "summary": "Retrieve Plant Anomaly Logs", + "tags": [ + "v3/plants/indicator" + ] + } + }, + "/api/v3/plants/{plant_id}/indicator/anomaly/logs/filter": { + "get": { + "description": "Filters anomaly records by date, map_id, map_type, type, and severity. At least one query parameter is required.", + "operationId": "filter_plant_anomaly_logs", + "parameters": [ + { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "in": "header", + "name": "Authorization", + "required": true, + "schema": { + "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "type": "string" + } + }, + { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", + "in": "header", + "name": "Account-Type", + "required": true, + "schema": { + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", + "enum": [ + "viewer", + "manager", + "temporary" + ], + "type": "string" + } + }, + { + "description": "Patch Plant ID.", + "in": "path", + "name": "plant_id", + "required": true, + "schema": { + "description": "Patch Plant ID.", + "examples": [ + "unw4id41ud2p0wt" + ], + "maxLength": 15, + "minLength": 15, + "type": "string" + } + }, + { + "explode": false, + "in": "query", + "name": "date", + "required": true, + "schema": { + "examples": [ + "2026-06-15" + ], + "format": "date", + "type": "string" + } + }, + { + "description": "Optional anomaly map ID filter.", + "explode": false, + "in": "query", + "name": "map_id", + "schema": { + "description": "Optional anomaly map ID filter.", + "type": "string" + } + }, + { + "description": "Optional anomaly map type filter.", + "explode": false, + "in": "query", + "name": "map_type", + "schema": { + "description": "Optional anomaly map type filter.", + "enum": [ + "plant", + "inverter", + "string", + "panel" + ], + "type": "string" + } + }, + { + "description": "Optional anomaly type filter.", + "explode": false, + "in": "query", + "name": "type", + "schema": { + "description": "Optional anomaly type filter.", + "type": "string" + } + }, + { + "description": "Optional severity filter.", + "explode": false, + "in": "query", + "name": "severity", + "schema": { + "description": "Optional severity filter.", + "enum": [ + "low", + "medium", + "high" + ], + "type": "string" + } + }, + { + "description": "Succeeds if the server's resource matches one of the passed values.", + "in": "header", + "name": "If-Match", + "schema": { + "description": "Succeeds if the server's resource matches one of the passed values.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "in": "header", + "name": "If-None-Match", + "schema": { + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "Succeeds if the server's resource date is more recent than the passed date.", "in": "header", - "name": "Account-Type", - "required": true, + "name": "If-Modified-Since", "schema": { - "description": "Specifies the type of user account making the request. Plant filter mutation routes are available to manager and viewer accounts only.", - "enum": [ - "viewer", - "manager" - ], + "description": "Succeeds if the server's resource date is more recent than the passed date.", + "format": "date-time-http", "type": "string" } }, { - "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", - "in": "path", - "name": "plant_id", - "required": true, + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "in": "header", + "name": "If-Unmodified-Since", "schema": { - "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", - "examples": [ - "unw4id41ud2p0wt" - ], - "maxLength": 15, - "minLength": 15, - "pattern": "^[a-zA-Z0-9]{15}$", - "patternDescription": "alphanum", + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "format": "date-time-http", "type": "string" } } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateFilterBody" - } - } - }, - "required": true - }, "responses": { - "201": { + "200": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/FilterOutput", - "description": "Created plant filter." + "description": "Array of anomaly records for the specified plant and date.", + "items": { + "$ref": "#/components/schemas/Record" + }, + "type": [ + "array", + "null" + ] } } }, - "description": "Created" + "description": "OK", + "headers": { + "ETag": { + "schema": { + "description": "Weak entity tag for conditional requests.", + "type": "string" + } + } + } }, "default": { "content": { @@ -6976,16 +7923,16 @@ "bearer": [] } ], - "summary": "Create Plant Filter", + "summary": "Filter Plant Anomaly Logs", "tags": [ - "v3/plants/filters" + "v3/plants/indicator" ] } }, - "/api/v3/plants/{plant_id}/filters/{filter_id}": { - "delete": { - "description": "Deletes a reusable map object filter for a specific plant.", - "operationId": "delete_plant_filter", + "/api/v3/plants/{plant_id}/indicator/anomaly/snapshots": { + "get": { + "description": "Retrieves anomalies detected before the end of the requested date that had not resolved by that time.", + "operationId": "get_plant_anomaly_snapshots", "parameters": [ { "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", @@ -6998,157 +7945,175 @@ } }, { - "description": "Specifies the type of user account making the request. Plant filter mutation routes are available to manager and viewer accounts only.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "in": "header", "name": "Account-Type", "required": true, "schema": { - "description": "Specifies the type of user account making the request. Plant filter mutation routes are available to manager and viewer accounts only.", + "description": "Specifies the type of user account making the request. Determines the access level and available operations. 'viewer' provides read-only access, 'manager' allows administrative operations, and 'temporary' provides scoped plant access.", "enum": [ "viewer", - "manager" + "manager", + "temporary" ], "type": "string" } }, { - "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "description": "Patch Plant ID.", "in": "path", "name": "plant_id", "required": true, "schema": { - "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", + "description": "Patch Plant ID.", "examples": [ "unw4id41ud2p0wt" ], "maxLength": 15, "minLength": 15, - "pattern": "^[a-zA-Z0-9]{15}$", - "patternDescription": "alphanum", "type": "string" } }, { - "description": "Filter record ID.", - "in": "path", - "name": "filter_id", + "explode": false, + "in": "query", + "name": "date", "required": true, "schema": { - "description": "Filter record ID.", "examples": [ - "filter123456789" + "2026-06-15" ], + "format": "date", "type": "string" } - } - ], - "responses": { - "204": { - "description": "No Content" }, - "default": { - "content": { - "application/problem+json": { - "schema": { - "$ref": "#/components/schemas/ErrorModel" - } - } - }, - "description": "Error" - } - }, - "security": [ - { - "bearer": [] - } - ], - "summary": "Delete Plant Filter", - "tags": [ - "v3/plants/filters" - ] - } - }, - "/api/v3/plants/{plant_id}/filters/{filter_id}/rename": { - "post": { - "description": "Renames a reusable map object filter for a specific plant.", - "operationId": "rename_plant_filter", - "parameters": [ { - "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", - "in": "header", - "name": "Authorization", - "required": true, + "description": "Optional anomaly map ID filter.", + "explode": false, + "in": "query", + "name": "map_id", "schema": { - "description": "Authorization header containing the Bearer token used for user authentication and access control. Format: 'Bearer '", + "description": "Optional anomaly map ID filter.", "type": "string" } }, { - "description": "Specifies the type of user account making the request. Plant filter mutation routes are available to manager and viewer accounts only.", - "in": "header", - "name": "Account-Type", - "required": true, + "description": "Optional anomaly map type filter.", + "explode": false, + "in": "query", + "name": "map_type", "schema": { - "description": "Specifies the type of user account making the request. Plant filter mutation routes are available to manager and viewer accounts only.", + "description": "Optional anomaly map type filter.", "enum": [ - "viewer", - "manager" + "plant", + "inverter", + "string", + "panel" ], "type": "string" } }, { - "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", - "in": "path", - "name": "plant_id", - "required": true, + "description": "Optional anomaly type filter.", + "explode": false, + "in": "query", + "name": "type", "schema": { - "description": "Plant ID. A unique alphanumeric identifier representing the solar plant installation. Must be exactly 15 characters in length.", - "examples": [ - "unw4id41ud2p0wt" - ], - "maxLength": 15, - "minLength": 15, - "pattern": "^[a-zA-Z0-9]{15}$", - "patternDescription": "alphanum", + "description": "Optional anomaly type filter.", "type": "string" } }, { - "description": "Filter record ID.", - "in": "path", - "name": "filter_id", - "required": true, + "description": "Optional severity filter.", + "explode": false, + "in": "query", + "name": "severity", "schema": { - "description": "Filter record ID.", - "examples": [ - "filter123456789" + "description": "Optional severity filter.", + "enum": [ + "low", + "medium", + "high" ], "type": "string" } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RenameFilterBody" - } + }, + { + "description": "Succeeds if the server's resource matches one of the passed values.", + "in": "header", + "name": "If-Match", + "schema": { + "description": "Succeeds if the server's resource matches one of the passed values.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] } }, - "required": true - }, + { + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "in": "header", + "name": "If-None-Match", + "schema": { + "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + { + "description": "Succeeds if the server's resource date is more recent than the passed date.", + "in": "header", + "name": "If-Modified-Since", + "schema": { + "description": "Succeeds if the server's resource date is more recent than the passed date.", + "format": "date-time-http", + "type": "string" + } + }, + { + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "in": "header", + "name": "If-Unmodified-Since", + "schema": { + "description": "Succeeds if the server's resource date is older or the same as the passed date.", + "format": "date-time-http", + "type": "string" + } + } + ], "responses": { "200": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/FilterOutput", - "description": "Renamed plant filter." + "description": "Array of anomaly records for the specified plant and date.", + "items": { + "$ref": "#/components/schemas/Record" + }, + "type": [ + "array", + "null" + ] } } }, - "description": "OK" + "description": "OK", + "headers": { + "ETag": { + "schema": { + "description": "Weak entity tag for conditional requests.", + "type": "string" + } + } + } }, "default": { "content": { @@ -7166,9 +8131,9 @@ "bearer": [] } ], - "summary": "Rename Plant Filter", + "summary": "Retrieve Plant Anomaly Snapshots", "tags": [ - "v3/plants/filters" + "v3/plants/indicator" ] } }, @@ -9289,7 +10254,7 @@ }, "/api/v3/plants/{plant_id}/registry/logs/filter": { "get": { - "description": "Filters registry log records for the specified plant and date by asset_id, map_id, asset_type, and map_type. At least one filter parameter is required.", + "description": "Filters registry log records for the specified plant by date, asset_id, map_id, asset_type, and map_type. At least one query parameter is required.", "operationId": "filter_plant_registry_logs", "parameters": [ { @@ -9334,13 +10299,12 @@ } }, { - "description": "Target date of data. Must follow the format 'YYYY-MM-DD'.", + "description": "Optional target date of data. Must follow the format 'YYYY-MM-DD'.", "explode": false, "in": "query", "name": "date", - "required": true, "schema": { - "description": "Target date of data. Must follow the format 'YYYY-MM-DD'.", + "description": "Optional target date of data. Must follow the format 'YYYY-MM-DD'.", "examples": [ "2024-01-24" ], From 16e6b81eb8b69b643bda46ee3b11eceb7665fcc1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 29 Jun 2026 01:10:43 +0000 Subject: [PATCH 11/11] chore: sync openapi v3 snapshot --- openapi/openapi-v3.json | 125 +++------------------------------------- 1 file changed, 7 insertions(+), 118 deletions(-) diff --git a/openapi/openapi-v3.json b/openapi/openapi-v3.json index d0044ab..ab6a84e 100644 --- a/openapi/openapi-v3.json +++ b/openapi/openapi-v3.json @@ -8802,6 +8802,7 @@ ], "maxLength": 15, "minLength": 15, + "pattern": "^[a-zA-Z0-9]{15}$", "patternDescription": "alphanum", "type": "string" } @@ -8831,56 +8832,6 @@ "minimum": 1, "type": "integer" } - }, - { - "description": "Succeeds if the server's resource matches one of the passed values.", - "in": "header", - "name": "If-Match", - "schema": { - "description": "Succeeds if the server's resource matches one of the passed values.", - "items": { - "type": "string" - }, - "type": [ - "array", - "null" - ] - } - }, - { - "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", - "in": "header", - "name": "If-None-Match", - "schema": { - "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", - "items": { - "type": "string" - }, - "type": [ - "array", - "null" - ] - } - }, - { - "description": "Succeeds if the server's resource date is more recent than the passed date.", - "in": "header", - "name": "If-Modified-Since", - "schema": { - "description": "Succeeds if the server's resource date is more recent than the passed date.", - "format": "date-time-http", - "type": "string" - } - }, - { - "description": "Succeeds if the server's resource date is older or the same as the passed date.", - "in": "header", - "name": "If-Unmodified-Since", - "schema": { - "description": "Succeeds if the server's resource date is older or the same as the passed date.", - "format": "date-time-http", - "type": "string" - } } ], "responses": { @@ -8898,15 +8849,7 @@ } } }, - "description": "OK", - "headers": { - "ETag": { - "schema": { - "description": "Weak entity tag for conditional requests", - "type": "string" - } - } - } + "description": "OK" }, "default": { "content": { @@ -8970,56 +8913,10 @@ "examples": [ "bsajtokt84s2byf" ], - "type": "string" - } - }, - { - "description": "Succeeds if the server's resource matches one of the passed values.", - "in": "header", - "name": "If-Match", - "schema": { - "description": "Succeeds if the server's resource matches one of the passed values.", - "items": { - "type": "string" - }, - "type": [ - "array", - "null" - ] - } - }, - { - "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", - "in": "header", - "name": "If-None-Match", - "schema": { - "description": "Succeeds if the server's resource matches none of the passed values. On writes, the special value * may be used to match any existing value.", - "items": { - "type": "string" - }, - "type": [ - "array", - "null" - ] - } - }, - { - "description": "Succeeds if the server's resource date is more recent than the passed date.", - "in": "header", - "name": "If-Modified-Since", - "schema": { - "description": "Succeeds if the server's resource date is more recent than the passed date.", - "format": "date-time-http", - "type": "string" - } - }, - { - "description": "Succeeds if the server's resource date is older or the same as the passed date.", - "in": "header", - "name": "If-Unmodified-Since", - "schema": { - "description": "Succeeds if the server's resource date is older or the same as the passed date.", - "format": "date-time-http", + "maxLength": 15, + "minLength": 15, + "pattern": "^[a-zA-Z0-9]{15}$", + "patternDescription": "alphanum", "type": "string" } } @@ -9039,15 +8936,7 @@ } } }, - "description": "OK", - "headers": { - "ETag": { - "schema": { - "description": "Weak entity tag for conditional requests", - "type": "string" - } - } - } + "description": "OK" }, "default": { "content": {