Curtailment
Curtailment endpoints of the DynVolt Open API.
Active and scheduled curtailment windows, a forecast-based limit suggester, relay/fan command history, and the control writes that schedule, apply immediately, or release curtailment. See the Curtailment guide — curtailment can only ever reduce output, never raise it above the grid permit.
GET /v1/sites/{site_id}/curtailment
Active + scheduled curtailment windows (rows carry group_id, applied, is_active).
Scope: curtailment:read · Module: basic_scada
curl "https://api.owner.dynvolt.com/v1/sites/pv-ljubas/curtailment" \
-H "Authorization: Bearer $DYNVOLT_API_KEY"GET /v1/sites/{site_id}/curtailment/suggest
Suggest a power limit from forecast (?logger_id&date&start_hour&end_hour).
Scope: curtailment:read · Module: basic_scada
| Query parameter | Type | Required | Description |
|---|---|---|---|
logger_id | integer | yes | Logger (plant) to suggest a limit for. |
date | string | yes | Target day, YYYY-MM-DD (UTC). |
start_hour | integer | yes | Window start hour, 0–23 (local plant hour). |
end_hour | integer | yes | Window end hour, 1–24. Must be greater than start_hour. |
curl "https://api.owner.dynvolt.com/v1/sites/pv-ljubas/curtailment/suggest" \
-H "Authorization: Bearer $DYNVOLT_API_KEY"GET /v1/sites/{site_id}/commands/relay-history
Relay/fan command history (?node_id&limit).
Scope: curtailment:read · Module: basic_scada
| Query parameter | Type | Required | Description |
|---|---|---|---|
node_id | string | no | Restrict to one sensor/relay node. |
limit | integer | no | Maximum rows to return (capped at 500). |
curl "https://api.owner.dynvolt.com/v1/sites/pv-ljubas/commands/relay-history" \
-H "Authorization: Bearer $DYNVOLT_API_KEY"POST /v1/sites/{site_id}/curtailment/window
Schedule a curtailment window (site or single plant).
Scope: curtailment:write · Module: basic_scada · Control write — commands the plant
| Path parameter | Type | Description |
|---|---|---|
site_id | string | Site identifier from GET /v1/sites. |
Request body (application/json):
| Field | Type | Required | Description |
|---|---|---|---|
scope | string | yes | "site" (whole site) or "logger" (one plant). |
logger_id | integer | when scope="logger" | Target logger. Required only for logger scope; ignored for site scope. |
start_at | string | yes | Window start — RFC3339 datetime. |
end_at | string | yes | Window end — RFC3339 datetime. Must be after start_at. |
limit_mode | string | yes | "percent" (% of rated power) or "kw" (absolute ceiling). For scope="site" + "kw", limit_value is the total site kW, split across plants proportional to their rated power. |
limit_value | number | yes | The limit, > 0. Interpreted per limit_mode. |
- Response:
201—{ group_id, schedules: [ { id, logger_id, start_at, end_at, max_power_kw, ... } ] }. Keepgroup_idto release the window later. - Control write — reduces plant output. It can never raise output above the grid-connection permit; every apply and restore is clamped to that permit by the edge. See the Curtailment guide.
- Supports the
Idempotency-Keyheader for safe retries (24-hour replay). Returns409 conflict_safe_modewhile the site is in commissioning safe mode.
curl -X POST "https://api.owner.dynvolt.com/v1/sites/pv-ljubas/curtailment/window" \
-H "Authorization: Bearer $DYNVOLT_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"scope": "logger",
"logger_id": 4,
"start_at": "2026-08-12T10:00:00Z",
"end_at": "2026-08-12T14:00:00Z",
"limit_mode": "percent",
"limit_value": 60
}'POST /v1/sites/{site_id}/curtailment/immediate
Curtail now (applied within ~10s).
Scope: curtailment:write · Module: basic_scada · Control write — commands the plant
| Path parameter | Type | Description |
|---|---|---|
site_id | string | Site identifier from GET /v1/sites. |
Request body (application/json):
| Field | Type | Required | Description |
|---|---|---|---|
scope | string | yes | "site" or "logger" — same semantics as the window endpoint. |
logger_id | integer | when scope="logger" | Target logger. Required only for logger scope. |
limit_mode | string | yes | "percent" or "kw" — same semantics as the window endpoint. |
limit_value | number | yes | The limit, > 0. |
duration_minutes | integer | no | How long to hold, > 0 and ≤ 10080 (7 days). Omit or null = hold until released (still bounded to 7 days). |
- Response:
201— same shape as the window endpoint. Applied within ~10 s. - Control write — reduces plant output. It can never raise output above the grid-connection permit; every apply and restore is clamped to that permit by the edge. See the Curtailment guide.
- Supports the
Idempotency-Keyheader for safe retries (24-hour replay). Returns409 conflict_safe_modewhile the site is in commissioning safe mode.
curl -X POST "https://api.owner.dynvolt.com/v1/sites/pv-ljubas/curtailment/immediate" \
-H "Authorization: Bearer $DYNVOLT_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"scope": "site",
"limit_mode": "kw",
"limit_value": 3500,
"duration_minutes": 120
}'DELETE /v1/sites/{site_id}/curtailment/group/{group_id}
Release a curtailment group (restores clamped power first).
Scope: curtailment:write · Module: basic_scada · Control write — commands the plant
| Path parameter | Type | Description |
|---|---|---|
site_id | string | Site identifier from GET /v1/sites. |
group_id | string | Curtailment group ID returned when the window/immediate curtailment was created. |
- No request body. Restores clamped power first (itself re-clamped to the grid permit), then cancels every row in the group.
- Control write — reduces plant output. It can never raise output above the grid-connection permit; every apply and restore is clamped to that permit by the edge. See the Curtailment guide.
- Supports the
Idempotency-Keyheader for safe retries (24-hour replay). Returns409 conflict_safe_modewhile the site is in commissioning safe mode.
curl -X DELETE "https://api.owner.dynvolt.com/v1/sites/pv-ljubas/curtailment/group/grp_8a1f" \
-H "Authorization: Bearer $DYNVOLT_API_KEY" \
-H "Idempotency-Key: $(uuidgen)"
