Volume Control
Volume control lets you bias the flex shape away from its default. The default is the output of a two-step optimization: the optimizer first finds the schedules that minimize cost for the end customer given the zone's tariffs, then — among the schedules that are still end-customer-optimal — picks the one that minimizes your own cost given the zone's price signal. The shape you read by default is therefore the cheapest schedule for you that doesn't leave the end customer worse off.
Apply a relative setpoint to a chunk and the optimizer will push that chunk's scheduled load up or down by the requested delta, taking the minimum-cost combination of changes to surrounding chunks that still honors your constraint. You steer the chunk you care about; the optimizer distributes the cheapest possible response across the rest of the shape.
Use volume control when you've committed capacity into another market — a forward contract, ancillary services, intra-day imbalance — and you need the underlying assets to be available at specific times, regardless of what the default cost-optimal plan would prefer.
Copy linkThe Cost Floor
The end customer's electricity cost is computed from the tariffs configured for their location — see the Tariffs guide and API referenceAPI for how those are modeled.
By default, volume control operates within a strict cost-preservation envelope: Enode will not apply a bias that makes the end customer pay more than they would have in the no-trading baseline. The bounds in forecast.minimumKw and forecast.maximumKw already reflect this — they are not raw physical bounds, they are the bounds of the schedule space that both respects asset feasibility and keeps the end customer's cost at or below their no-trading baseline.
This has three consequences you should design around:
- Envelopes shrink for economic reasons, not just physical ones. If your proposed shift would move load from an off-peak window into a peak window for the end customer, the optimizer will rearrange to avoid that, or will partially honor your constraint and stop at the point where the cost floor is hit. Constraints accumulate in the economic dimension as much as the physical one.
- The cost floor is configurable per deployment. If your commercial arrangement covers end-customer cost deltas through another channel, we can loosen the default and let volume control shift load into more expensive slots. Coordinate this with Enode — it's a deployment setting, not an API flag.
- Preview shows the shape impact. Previewing a constraint set returns the reshaped forecast, so you can see how the fleet would absorb your setpoints before committing. A per-preview end-customer cost breakdown is not yet available; the cost-preservation envelope described above is enforced server-side.
Copy linkThe Iterative Workflow
Volume control is a conversation with the optimizer, not a one-shot command. The first constraint you apply changes the entire shape non-locally: chunks you didn't touch will move, the feasibility envelope will tighten, and the trade-offs the optimizer is making will shift. The intended workflow is iterative:
- Read the current shape.
- Identify the chunk you care most about steering. Apply one constraint.
- Send it to the preview endpoint and read the result.
- Look at what else changed. Which chunks moved? How much did the feasibility envelope tighten? If anything shifted in a way you don't like, decide whether to counter it with an additional constraint.
- Add the counter-constraint and preview again.
- Repeat until the shape reflects all the positions you need it to, then commit the set via
PATCH.
Non-locality is not a bug — it's the optimizer telling you what happens when you ask it to do something other than the cost-minimizing schedule. The preview endpoint is where you have that conversation without commitment.
Copy linkPreviewing a Constraint
Preview a proposed constraint set without persisting it. The response is a full flex shape — same structure as GET /flex/shape/{zoneId} — recomputed as if the setpoints were in place.
POST /flex/shape/{zoneId}/preview
Content-Type: application/json
{
"chunks": [
{
"timestamp": "2026-03-17T10:00:00Z",
"relativeSetpoint": 40000
},
{
"timestamp": "2026-03-17T10:15:00Z",
"relativeSetpoint": 40000
}
]
}
Each chunk's forecast reflects the proposed constraints, including the non-local shifts the optimizer had to make to honor them.
Copy linkApplying Constraints
When you've converged on a constraint set you're happy with, commit it via PATCH:
PATCH /flex/shape/{zoneId}
Content-Type: application/json
{
"chunks": [
{
"timestamp": "2026-03-17T10:00:00Z",
"relativeSetpoint": 40000
}
]
}
Applied constraints take effect on the next shape computation and appear in subsequent shape reads as chunks[i].relativeSetpoint.
Copy linkClearing Constraints
Set relativeSetpoint to null to clear a previously-applied constraint for a given chunk:
PATCH /flex/shape/{zoneId}
Content-Type: application/json
{
"chunks": [
{ "timestamp": "2026-03-17T10:00:00Z", "relativeSetpoint": null }
]
}
Only chunks listed in the payload are touched. Constraints on other chunks remain in place.