Skip to main content

Energy Model Runs

POST /energymodels accepts an EnergyModelInput payload and executes a run either synchronously or asynchronously. Saved energy-model rows can then be edited and rerun in place with GET /energymodels/{id}?include=inputs, PUT /energymodels/{id}, and POST /energymodels/{id}/run.

Endpoint behavior

  • Sync is the default when async is omitted.
  • ?async=false runs sync and returns 200 when results complete in request scope.
  • ?async=true queues background processing and returns a queued 200 response.
  • Multi-block sync fan-out can also return a queued 200 response if worker blocks do not finish within the sync wait window.
  • Queued async and fan-out responses do not expose per-block task IDs in the public payload.

Saved-input edit/rerun workflow

The saved-row workflow is:
  1. Fetch the currently saved input JSON with GET /energymodels/{id}?include=inputs
  2. Edit the returned inputs JSON
  3. Save the updated JSON back to the same row with PUT /energymodels/{id}
  4. Rerun that same saved row with POST /energymodels/{id}/run
Important contract notes:
  • PUT /energymodels/{id} updates the saved input JSON on the existing energy-model row.
  • POST /energymodels/{id}/run runs the currently saved JSON in place on that same row.
  • Rerun does not create a new energy-model row.
  • Imported project variants created by POST /projects/import are intended entry points for this flow.
  • Active rows with status pending, queued, or running reject update/rerun with 409 Conflict.

Request contract

Minimum required structure:
  • exactly one of projectId, locationId, or inline location
  • blocks with at least one block
Each block requires:
  • inverterId
  • shading, losses, acSystem, albedo
  • at least one of array or dcInputs
  • at least one of layout or layoutRef

Request compatibility and deprecation behavior

Current behavior:
  • top-level name
    • backward-compatible alias for output.name
  • output.blockIndex
    • canonical zero-based selected-block response filter
    • valid only when block-level results are effectively requested
  • output.blockResults
    • canonical block-level time-series visibility flag for blockTimeSeries
    • mutually exclusive with output.fullTimeSeries
  • output.lossBreakdownTimestamps
    • top-level boolean request flag
    • implies block-level results are surfaced
    • the older object wrapper form is rejected on the public API
  • output.irradianceLossDetail
    • additive annual-detail flag that can surface losses.irradianceLossDetail even when output.fullOutput is false
  • query params:
    • blockresults
  • body fields:
    • blockQuery
    • blockQueryIndex
    • these are compatibility-only selected-block aliases and remain deprecated
  • legacy-only blockQuery + blockQueryIndex still map to canonical output.blockIndex behavior and emit deprecation warnings
  • if canonical output.blockIndex and legacy block selectors are both present and semantically consistent, the request is accepted and legacy warnings still apply
  • if canonical output.blockIndex and legacy block selectors conflict, the API returns 422
  • output.query is no longer supported and returns 422
  • object-shaped output.lossBreakdownTimestamps values are no longer supported and return 422
Route-specific note:
  • POST /energymodels?debug_block=... is no longer supported and returns 422 with guidance to use output.blockIndex.
  • POST /energymodels/{id}/run?debug_block=... is also no longer supported and returns 422 with the same guidance.
Rejected legacy query params:
  • summary
  • fullresults
Those return 422 with endpoint-specific guidance.

Example request

Output-shape behavior

  • Sync POST shape is controlled by request-body output flags.
  • Detail GET shape is controlled by include=....
  • List GET does not expand shape; include=summary is only a compatibility token.
  • output.timeSeries=true exposes plant-level timeSeries in sync completed responses.
  • output.blockResults controls blockTimeSeries visibility and does not rewrite runtime execution scope.
  • output.blockIndex filters the returned blockTimeSeries section only; it does not convert the request into single-block execution.
  • output.lossBreakdownTimestamps=true can surface blockTimeSeries even when output.blockResults is omitted or false.
  • blockTimeSeries keys preserve original zero-based block numbering, including filtered single-block responses.
  • timestamped loss details live under blockTimeSeries[<blockIndex>].lossBreakdown when output.lossBreakdownTimestamps=true.
  • losses.irradianceLossDetail is additive and may appear even when output.fullOutput is false if output.irradianceLossDetail=true is set.
Important compatibility note:
  • output.fullTimeSeries=true can still cause richer stored outputs, but the immediate sync POST response filters timeSeries back to the six legacy base keys.
Async note:
  • Async energy-model responses expose only the parent taskId in taskDetails.
  • Fan-out child block tasks and their IDs are internal orchestration details and are not returned on the public API.

Import -> edit -> rerun example

This example shows the intended workflow for an imported external project template. The same energy_model_id is reused across the GET, PUT, and POST /run steps.
The final rerun response still points at the same saved row:

Response contract

Canonical response envelopes and include behavior are documented here:

Follow-up calls

  • Poll task: GET /tasks/{taskId} where taskId = taskDetails.taskId
  • Fetch run resource: GET /energymodels/{energyModelId}