> ## Documentation Index
> Fetch the complete documentation index at: /docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Optimizations

> Find the best times to run a device: price windows by duration or price limit, and with VPP, power profiles by state of charge or strategy.

An optimization ranks the connected tariff for one device and returns the best times to consume or export energy. Use the result as an input to your own scheduling.

| You want | Call |
| :- | :- |
| The best times to run a device for a set number of minutes | [Optimize by duration](/docs/energy-api/reference/optimizations/duration.md) |
| Every interval below or above a price | [Optimize by price limit](/docs/energy-api/reference/optimizations/limit.md) |
| With VPP: a charging profile that reaches a charge target | [Optimize by state of charge](/docs/energy-api/reference/optimizations/soc.md) |
| With VPP: a battery power profile under its strategy | [Optimize by strategy](/docs/energy-api/reference/optimizations/strategy.md) |

Every optimization needs a connected tariff with prices. Without them the request fails with `no_tariff_connected` or `no_price_data`. See [Errors](/docs/energy-api/guides/platform/errors.md).

## Price windows

Optimizing by duration or by price limit returns price windows: the intervals of the tariff that match your request, in time order.

Both take a window of at most 3 days, set by `start_time` and `end_time`. Ask for `import`, `export` or both. In each, `segment` picks the side of the tariff: `LOW` for the cheapest intervals, `HIGH` for the most expensive.

| Method | Input | Returns |
| :- | :- | :- |
| By duration | `duration`: the minutes the device must run. `rank_by` `SOLAR` ranks by forecast generation instead of price | The cheapest, most valuable or sunniest intervals that add up to the duration. They may be non-contiguous |
| By price limit | A threshold: `ABSOLUTE` in currency, or `RELATIVE` between 0.01 (lowest tariff) and 1 (highest tariff) | Every interval below or above the threshold |

Each window carries the tariff `price`: the average price per kWh for the interval, with a `confidence`. Where the location has PV, it also carries the `solar` forecast for the same interval.

This request finds the cheapest 45 minutes to import in the next day.

```bash Request example theme={"system"}
curl --request POST \
  --url https://energy-api.flatpeak.com/devices/dev_9c1f70a4e2b6485db3f0c8a1/optimizations/duration \
  --header 'Authorization: Bearer <bearer_token>' \
  --header 'Content-Type: application/json' \
  --data '{
    "start_time": "2026-06-15T09:00:00Z",
    "end_time": "2026-06-16T09:00:00Z",
    "import": {
      "segment": "LOW",
      "duration": 45
    }
  }'
```

```json Response example theme={"system"}
{
  "id": "opt_65e42cdd73e9f861edda35d7",
  "object": "optimization_duration",
  "live_mode": false,
  "device_id": "dev_9c1f70a4e2b6485db3f0c8a1",
  "location_id": "loc_65e42ce4d3b813479b252160",
  "timezone": "Europe/London",
  "currency_code": "GBP",
  "data": [
    {
      "start_time": "2026-06-16T01:00:00Z",
      "end_time": "2026-06-16T01:45:00Z",
      "price": {
        "value": 0.032,
        "confidence": 1
      },
      "solar": null
    }
  ],
  "account_id": "acc_661677911f2197045e6cf1b1",
  "time_created": "2026-06-15T09:00:04Z"
}
```

### Solar forecasts

Solar forecasts come only inside price windows. To get them:

1. Give the PV device a `pv` capability block with `peak_power_kw`. `azimuth`, `tilt` and `terrain_shading` improve accuracy.
2. Set `forecasts_enabled` to `true` in `capabilities.pv`. The location must have an address.

Within an hour, every window at the location carries `solar`: `energy_kwh`, `power_kw` and a `confidence`. Forecasts come from [Solcast](https://solcast.com/), run 7 days ahead and refresh hourly.

`solar` is `null` when the device has no `pv` block or forecasts are off. `rank_by` `SOLAR` needs forecasts on the device or its location.

## Power profiles

With [VPP](/docs/energy-api/guides/vpp/how-it-works.md), two more optimizations return a power profile instead of price windows. Each row has a `start_time`, an `end_time`, the tariff `price` and a `power_kw`. Power is signed: positive imports, negative exports.

| Method | For | Returns |
| :- | :- | :- |
| By state of charge | A battery or a vehicle | The charging profile that reaches the charge target in the latest [device state](/docs/energy-api/guides/vpp/telemetry.md): `battery.target_state_of_charge_percent`, or `vehicle.charge_limit_percent` by `vehicle.time_departure` |
| By strategy | A battery | The power profile under the battery's `strategy`. `SAVINGS` charges in cheap periods and discharges in expensive ones. `SELF_POWER` holds charge for local load |

Optimizing by strategy takes an `end_time`; the window starts now and extends at most 48 hours.

Both accept `storm_mode_enabled`, which overrides the device's storm mode setting for that request only. Omit it to use the setting from the latest device state. A row with `storm_mode_active` `true` is shaped by storm mode: the profile holds or builds charge ahead of forecast severe weather.

## Keep results current

An optimization is a snapshot of its inputs at `time_created`, so run it again when an input changes.

| Input | Changes when |
| :- | :- |
| Prices or the solar forecast | `price.update` fires |
| Device settings, such as `strategy` and storm mode | `device.settings.update` fires |
| Device state, such as the charge target | You submit new device state |
| VPP enrollment | `vpp_enrollment.update` fires |

See [Events](/docs/energy-api/guides/platform/events.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.