Skip to main content

Energy Model Response Contracts

This page documents the current public response contract for /energymodels, including the saved-input update/rerun flow on existing rows.

POST /energymodels

Execution modes:
  • Default (async omitted or ?async=false): synchronous attempt
  • ?async=true: queued async execution
  • sync fan-out can also return a queued 200 response when block work is queued before completion
Request-shaping notes:
  • output.query is rejected with 422.
  • output.blockIndex is the canonical selected-block filter and preserves zero-based original block numbering in public responses.
  • output.blockResults controls blockTimeSeries visibility and is mutually exclusive with output.fullTimeSeries.
  • output.lossBreakdownTimestamps is a top-level boolean again and implies block-level results are surfaced.
  • object-shaped output.lossBreakdownTimestamps values are rejected with 422.
  • output.irradianceLossDetail is an additive annual-detail flag that may surface losses.irradianceLossDetail even when output.fullOutput is false.
  • Deprecated top-level blockQuery + blockQueryIndex remain compatibility aliases to top-level output.blockIndex; conflicting canonical and legacy block selectors return 422.

200 OK

Sync-completed responses keep legacy-compatible top-level flattened result sections.
{
  "result": "success",
  "message": "Energy model completed",
  "energyModelId": 56,
  "globalEnergyModelId": "111222333",
  "projectId": 7,
  "globalProjectId": "901234567",
  "revision": "v0003",
  "taskDetails": {
    "message": "Energy model completed",
    "taskId": 1234,
    "schemaMode": "legacy",
    "executionMode": "sync_in_process",
    "calculationTime": 12.5,
    "createdAtUtc": "2026-03-03T16:21:11Z",
    "warnings": [
      "Block 0: Using legacy single-array format. Migrate to 'dcInputs' for per-MPPT control. Legacy format will be removed in schema v4.0."
    ],
    "normalizationWarnings": []
  },
  "energyYieldSummary": {
    "MWh": 1234.56,
    "kWh/kWdc": 1875.4
  }
}
Declared top-level result sections:
  • title
  • energyYieldSummary
  • locationSummary
  • plantSummary
  • losses
  • blockSummary
  • settings
  • monthlySummary
  • timeSeries
  • blockTimeSeries
blockTimeSeries notes:
  • surfaced when block-level results are effectively requested by output.blockResults=true, output.lossBreakdownTimestamps=true, or deprecated ?blockresults=true
  • returns all available blocks when output.blockIndex is omitted
  • returns only the selected block when output.blockIndex is provided
  • preserves original zero-based block numbering in public keys
  • timestamped loss breakdowns live under blockTimeSeries[<blockIndex>].lossBreakdown
Legacy compatibility note:
  • If the request uses output.fullTimeSeries=true, the immediate sync POST response filters timeSeries back to: date, arraySTCDCPower, arrayDCPower, inverterOutACPower, gridACPower, poiACPower
Additive irradiance-loss detail:
  • When output.irradianceLossDetail=true, public responses may include losses.irradianceLossDetail without requiring output.fullOutput=true.
  • The detail payload reports annual fractions on the same stage basis as the scalar losses.irradianceLosses entries.
  • Stage keys include transpositionOnPoaLoss, farShadingLoss, nearShadingLoss, aoiIrradianceLoss, soilingIrradianceLoss, and groundReflectedOnFront.
  • The component fields are direct, circumsolar, diffuse, and albedo.

200 OK (Queued)

{
  "result": "success",
  "message": "Energy model queued for processing",
  "energyModelId": 57,
  "globalEnergyModelId": "111222334",
  "projectId": 7,
  "globalProjectId": "901234567",
  "revision": "v0004",
  "taskDetails": {
    "message": "Energy model queued for processing",
    "taskId": 1235,
    "schemaMode": "legacy",
    "executionMode": "async_fanout",
    "calculationTime": null,
    "createdAtUtc": "2026-03-03T16:22:03Z",
    "warnings": [
      "Deprecated query parameter 'blockresults' was used."
    ],
    "normalizationWarnings": [
      "defaulted output to {}"
    ]
  }
}
Queued async and fan-out responses do not expose per-block task IDs in the public payload.

Canonical taskDetails fields

FieldTypeDescription
messagestring | nullRun/task status message.
taskIdinteger | nullWorkspace-scoped task index for /tasks/{task_id}.
schemaMode"legacy" | "multi_mppt" | "hybrid" | nullDetected input schema mode.
executionMode"sync_in_process" | "sync_fanout" | "async_fanout" | nullRun execution path.
calculationTimenumber | nullRuntime in seconds for completed runs.
createdAtUtcstring | nullResource creation timestamp (UTC ISO-8601).
warningsstring[] | nullHuman-readable warning messages.
normalizationWarningsstring[] | nullInput-normalization warnings.
Notes:
  • Warnings are always exposed as strings.
  • If runtime code generates structured warnings, the API surfaces only their message text.
  • GET/list/detail task details are backed by persisted summary metadata for the run.
  • output.query and debug_block are not supported on the public request surface; the API returns 422 and directs callers to output.blockIndex.

GET /energymodels

List responses remain a light flattened summary shape.
[
  {
    "energyModelId": 57,
    "globalEnergyModelId": "111222333",
    "workspaceId": 1,
    "name": "North Project Run",
    "projectId": 7,
    "globalProjectId": "901234567",
    "revision": "v0004",
    "dateCreated": "2026-03-03T16:22:03Z",
    "status": "queued",
    "annualACEnergy": 111.1,
    "taskDetails": {
      "message": "Energy model queued for processing",
      "taskId": 1235,
      "schemaMode": "legacy",
      "executionMode": "async_fanout",
      "calculationTime": null,
      "createdAtUtc": "2026-03-03T16:22:03Z",
      "warnings": ["gate warning"],
      "normalizationWarnings": []
    }
  }
]
Compatibility note:
  • include=summary is accepted as a no-op compatibility token on this endpoint.

GET /energymodels/{energy_model_id}

Default detail responses omit optional result sections unless requested with include. With include=summary,inputs,fulltimeseries,blocktimeseries, detail responses can additionally expose:
  • title
  • energyYieldSummary
  • locationSummary
  • plantSummary
  • losses
  • blockSummary
  • settings
  • monthlySummary
  • inputs
  • normalizedInputs
  • timeSeries
  • blockTimeSeries
With include=inputs, detail responses also expose the persisted saved input JSON needed for edit/rerun workflows.

PUT /energymodels/{energy_model_id}

PUT /energymodels/{energy_model_id} accepts a full EnergyModelInput body, replaces the saved input JSON on that same row, clears stale outputs, and returns an EnergyModelDetailResponse. Typical update response:
{
  "energyModelId": 56,
  "projectId": 7,
  "revision": "v0003",
  "status": "draft",
  "inputs": {
    "projectId": 7,
    "blocks": []
  },
  "taskDetails": {
    "message": "Energy model saved",
    "taskId": null,
    "schemaMode": "legacy",
    "executionMode": null,
    "createdAtUtc": "2026-03-03T16:22:03Z"
  }
}
Notes:
  • This updates the existing energy-model row instead of creating a new one.
  • The returned inputs payload is the saved JSON after hydration/validation.
  • Rows in pending, queued, or running state return 409 Conflict.

POST /energymodels/{energy_model_id}/run

POST /energymodels/{energy_model_id}/run executes the currently saved input JSON on the same energy-model row in place. Behavior:
  • ?async=false or omitted attempts sync execution first.
  • ?async=true queues background execution and returns a queued 200.
  • Multi-block reruns can still return queued 200 fan-out responses from the sync path.
  • The response envelopes match POST /energymodels, but energyModelId remains the existing row instead of a newly created row.
Queued rerun example:
{
  "result": "success",
  "message": "Energy model queued for processing",
  "energyModelId": 56,
  "revision": "v0003",
  "taskDetails": {
    "message": "Energy model queued for processing",
    "taskId": 1235,
    "schemaMode": "legacy",
    "executionMode": "async_queued",
    "calculationTime": null,
    "createdAtUtc": "2026-03-03T16:22:03Z",
    "warnings": [],
    "normalizationWarnings": []
  }
}
Async notes:
  • Poll GET /tasks/{task_id} using taskDetails.taskId.
  • Fetch final results from GET /energymodels/{energy_model_id}.
  • The rerun updates the same saved row; it does not create a second model row.

Include token behavior

EndpointAllowed tokensCurrent behavior
GET /energymodelssummaryAccepted no-op compatibility token
GET /energymodels/{energy_model_id}summary, inputs, fulltimeseries, blocktimeseriesGates optional detail sections
PUT /energymodels/{energy_model_id}noneRequest body is the full saved input JSON
POST /energymodels/{energy_model_id}/runnoneRuns the currently saved JSON in place
POST /energymodelsnoneQuery-based include control is unsupported
Legacy query parameters such as summary and fullresults are rejected with endpoint-specific 422 guidance.