TL;DR
GET /devicesreturns each device'scapabilities[]— this is the only source of truth for what a device can do right nowPUT /devices/{id}/{capabilityName}to write — returns202 Accepted(async), then re-fetch the device to see the result- If a capability has
interventions[], it's blocked — show the user what to do (e.g. re-authenticate, upgrade subscription) - Capability not in the array? The device doesn't support it. Don't treat it as an error.
time-controlschedule times must be exact five-minute grid points (for example,14:35:00)- See the Capability Reference for all payloads,
actionDetailsper action, and which actions work on which device category
This documentation is intended for B2B customers of the clever-PV Connect API and explains the capability concept from an API perspective.
Basic idea
A device has a list of capabilities. A capability describes one ability of the device (e.g., turning on/off, setting a charge limit, displaying SoC, connecting a vendor).
- Read: Capabilities are returned via the device endpoints as part of the device object.
- Write: Some capabilities can be updated/executed via a generic "PUT capability" endpoint.
- Important: Capabilities are dynamic (see section "Dynamics: capabilities are not static").
API objects (response view)
Device (simplified)
A device contains, among other fields, model and capabilities.
Code
The core capability's connectivityStatus is one of:
online— device is reachable and reporting.offline— device is unreachable (repeated polling failures, or onboarding not completed).connecting— device onboarded but has not reported any signal yet; status is still being determined.
Capability (response view)
Each capability is an object with:
name: string, the unique capability name (e.g.,core,connect,set-charge-limit)data: arbitrary JSON object (capability-specific; structure depends on the capability)options: arbitrary JSON object with capability-specific metadata (e.g., how the capability should be executed or). It may be empty or missing, and its shape is capability-dependent.interventions: list of blockers (see Interventions (blockers) – meaning & examples) that explain why a capability is currently not usable
Endpoints (read & write capabilities)
Read capabilities
- GET
v1/users/{userId}/devices
Returns a paginated list of devices (wrapper object) incl.capabilities:
Code
- GET
v1/users/{userId}/devices/{deviceId}
Returns a device incl.capabilities.
Write/execute capabilities
- PUT
v1/users/{userId}/devices/{deviceId}/{capability}{capability}is the capability name (e.g.,on-off,connect,set-charge-limit)- Request body is capability-specific (see "Capability Reference")
- Response is
202 Accepted(asynchronous) – then fetch the device again via GET
Example (turn device on/off):
Code
Response:
Code
Dynamics: capabilities are not static
Capabilities can appear, disappear, or be blocked depending on:
- Device category & model (e.g., a car may have
set-charge-limit, an electric meter may not) - Vendor/onboarding flow (e.g.,
connectwith Form/OIDC/OCPP options) - Current device state (online/offline, data available, telemetry delayed)
- Subscription/product enablement (e.g., features may show
subscription-upgrade-required) - Setup completeness (e.g.,
home-location-required,connector-type-required)
Blocked vs unsupported:
- Blocked capability: The capability exists in
capabilities[]but includes one or moreinterventions. It is present but not currently usable. - Unsupported capability: The capability does not exist in
capabilities[]. A PUT to that capability results in a capability-not-supported error.
What "CapabilityData" means:
Most capabilities have a corresponding *CapabilityData (and for writable ones often *CapabilityUpdateData) schema that defines the shape of the JSON payload. This is the contract for what you receive in capabilities[].data and what you send in the PUT body for writable capabilities.
How clients should handle this
- Treat capabilities as a server-driven contract: Do not assume a capability exists.
- If a capability is missing: The device cannot currently do it (or not for this user). Do not treat it as an error.
- If interventions are present: The capability exists, but is currently blocked. Use the intervention id to show the user the next action.
- Always re-fetch after PUT: After a
202 Accepted, fetch the device again via GET to see the new status/blocker. - Be tolerant of unknown fields: In
data,options, and enum values.
Interventions (blockers) – meaning & examples
Some capabilities include an interventions[] array that explains why the capability is currently blocked (even though it is present in capabilities[]). Each intervention has a stable id you can use to drive UI actions and troubleshooting.
For a full list of known intervention IDs and typical resolutions, see Interventions.
Error handling (Problem Details)
The OpenAPI specification defines two different error response shapes:
ProblemDetails(generic ASP.NET problem details; used by many endpoints)ConnectApiProblemDetails(partner-friendly problem details withtype+errorCode+traceId+ optional validationissues)
Which one you receive depends on the endpoint and status code.
ConnectApiProblemDetails shape (simplified)
Code
ProblemDetails shape (simplified)
Code
Relevant HTTP status codes for capability PUT
- 400: Request/validation failed (e.g., wrong type, missing required fields)
- 401: Unauthorized (token/app id/signature missing/invalid)
- 402: Payment required (feature/subscription required)
- 412: Precondition failed (e.g., consent/certificate missing)
- 422: Capability not supported (device does not support it / currently not executable)
Which devices typically have which capabilities?
This is guidance. The decisive factor is always what is returned in the device's
capabilities[].
Car (vehicles)
- Typical (read):
core,display-soc,display-estimated-range,display-charging-state,display-power - Typical (write):
set-charge-limit,set-charging-power,charging-mode,phase-mode(if supported) - Optional:
min-max-amperage,phase-switching,sleep-mode,location-detection - Onboarding/setup:
connect,home-location,connector-type, (vendor-specific)add-charging-location - Tesla-specific:
install-certificate,set-scopes,support-tesla-vehicle-command-protocol
Notes:
display-charging-stateis the capability to use for the device's charging state.set-charge-limitlimits the car battery (currently only supported for Tesla).- “Target SoC” is part of
target-charging(TargetChargingCapabilityData.targetSoC).
Wallbox
- Typical (read):
core,display-charging-state,display-charging-current,display-charging-phases,display-power - Typical (write):
set-charging-power,phase-mode(if supported) - Optional:
phase-switching,sleep-mode,connect(vendor/ocpp dependent),battery-capacity(when the wallbox reports onboard EV battery info)
Heat pump
- Typical (read):
core,display-temperature,display-heating-state - Optional (read):
display-power(only when the vendor/model reports power),pv-control,consumption-overview - Onboarding/setup:
connect,email-verification - Control (write, when present in
capabilities[]): heat-pump optimization is exposed through the same write capabilities as other controllable devices — e.g.smart-mode(master switch),preferred-operating-mode,price-control,target-control, and the PV-surplus tuning settingspriority/rated-capacity/switch-delay. Which of these a given model exposes is catalog-driven, so always rely on the device'scapabilities[].
Notes:
- No raw setpoint or temperature control. clever-PV never writes a target temperature or power value to a heat pump. Every optimization decision (smart, price, target) is translated into a single internal on/off command that maps to an SG-Ready state — recommended (encourage the unit to consume now) or normal (hand control back to the unit's own program). SG-Ready states are not addressable directly through the API.
- What "on" physically does: for the integrated cloud vendors (Vaillant, Bosch/Buderus, Viessmann, Solvis) the recommended signal triggers a domestic-hot-water (DHW) charge via the vendor cloud — it does not drive the space-heating circuit, and the unit may defer or ignore it (e.g. when the DHW tank is already at its target temperature). A heat pump can alternatively be driven by an external SG-Ready relay modeled as a
switchdevice. boostis not available for heat pumps (car/wallbox only).display-heating-statereports the currentmode/state/reason(e.g.reason: "solar"or"price") — i.e. which optimization currently drives the unit. Enum values are vendor-dependent; tolerate unknowns.display-temperaturecurrently exposes only a single temperature value (expected to be expanded later). We do not provide temperature curves/time series via the Connect API.consumption-overviewcan display consumption bars for today and yesterday (see the Electric meter section for the typical capability set).
Electric meter
- Typical (read):
core,display-grid-power,display-solar-power,display-community-power,consumption-overview - Setup (write):
measurement-purpose(one-time / may be immutable depending on the device) - Optional:
connect(if vendor auth is required) - Optional (read, when a battery is attached):
display-battery-state,display-soc(when the vendor exposes SoC telemetry),battery-capacity - Optional (write, when a controllable battery is attached):
operation-modeto set the battery tonormal,idle, orforceCharge;control-permissionto grant clever-PV permission to control the battery (required by some vendors — e.g. SigEnergy, Fronius — beforeoperation-modewrites are accepted);battery-capacityto register the battery's nominal energy capacity (Wh) when the vendor integration does not expose it automatically
Notes:
- Hybrid inverters (a single physical device that combines a grid/PV meter with battery storage) are modeled as a single
electricMeterdevice that additionally exposes the battery-related capabilities listed above. They do not appear as a separatepowerStoragedevice. As always,capabilities[]is the source of truth for which features are actually exposed for a given hybrid inverter (varies by vendor/model). - Battery operating-mode control (
normal/idle/forceCharge) is exposed as theoperation-modecapability on the electric meter the battery is attached to, not on the power storage device itself.
PowerStorage (battery/storage)
- Currently unused, no devices available. Batteries are exposed through their hybrid inverters as type electricMeter
Switch
- Typical (read):
core,display-power - Typical (write):
on-off, plus optimization-related settings (depending on product/setup)
Notes:
- Switch devices can participate in optimizations (e.g., as a SG-Ready relay for heat pumps).
- Some devices are dual-purpose and appear in the device list under both
switchandelectricMeter— pick the role by whichmodelIdyou onboard; theelectricMetervariant is metering-only (noon-off). This covers most Shelly metering models and AVM SmartEnergy 200/210. Only Shelly EM/3EM meters additionally requiremeasurement-purpose(gridMeter/pvProduction); choosingpvProductionre-creates the meter as a producingswitchthat reports PV output but is still noton-off-controllable.
When to use which write capability
Many writable capabilities have overlapping intent (e.g. multiple ways to "turn a wallbox on"). Pick by the user goal:
| User goal | Use this capability | Don't confuse with |
|---|---|---|
| Turn a switch / wallbox on or off right now, indefinitely | on-off (state: on/off) | target-control (time-bound), time-control (scheduled) |
| Run a session until a target SoC, runtime, or end time is reached, then auto-stop | target-control (with targetRuntime/endTime/SoC) | on-off (no auto-stop), time-control (scheduled, recurring) |
| Optimize a switch/relay to only consume PV surplus | solar-optimization (enabled: true, sunShare) | smart-mode (broader smart logic), on-off (manual override) |
| Run scheduled turn-on/off events (weekly or one-time) | time-control (replace-all schedule list) | target-control (single run), on-off (immediate) |
| Cap a car's max state of charge | set-charge-limit (Tesla only) | target-charging.targetSoC (per-session target) |
| Set a per-session SoC target for a car / wallbox | target-charging (targetSoC) | set-charge-limit (vehicle-wide limit) |
| Force a wallbox into 1-phase or 3-phase charging | phase-mode (single setting) | phase-switching (auto-switch behaviour) |
| Force-charge / idle / normal-mode an attached battery | operation-mode on the electric meter, not the storage device | a write to the powerStorage device (no such write) |
| Allow clever-PV to control the battery at all (one-time grant, some vendors) | control-permission (request: "allow") | operation-mode (the per-command mode write — blocked with a control-permission-required intervention until permission is granted) |
| Disable smart logic and just let the device run as-is | preferred-operating-mode (mode: "manual" or "smartControl") | smart-mode (per-feature toggle) |
Rule of thumb: check capabilities[] for the device — if a capability is present, it is the right path. If two seem to overlap, prefer the more specific one (e.g. target-control over on-off when there is an end condition).
Capability Reference
All examples use camelCase JSON. Enums are serialized as strings (e.g., "online", "threePhases").
Note:
datain GET can differ depending on the vendor (e.g., telemetry availability). Always apply null-tolerance. Schema names refer to OpenAPI component schemas from the Swagger file.
The list below is the single source of truth for per-capability payload formats and detailed semantics (e.g., units like Watt/Ampere, SoC meaning, edge cases). The category lists above are only illustrative; always rely on capabilities[] returned by the API.
core
{
"name": "Device Name",
"connectivityStatus": "online"
}{
"name": "New Device Name"
}connect
{
"connectionId": "00000000-0000-0000-0000-000000000000",
"vendorId": "11111111-1111-1111-1111-111111111111"
}{
"type": "oidcProxy",
"data": {
"url": "proto://intercepted?code=..."
}
}home-location
{
"city": "Munich",
"postalCode": "80331",
"street": "Example Street 1",
"latitude": 48.137154,
"longitude": 11.576124
}latitude/longitude are what the system uses to detect whether the vehicle is at its home location (see location-detection), which is what gates solar-optimized charging. city, postalCode and street are stored, but are not used in any control logic. The API does not validate this payload: omitting latitude/longitude defaults them to 0,0, so the request still returns 202 and clears the home-location-required intervention — but a position of 0,0 means the vehicle is never detected as at home and solar-aware charging stays silently disabled. Always send real coordinates. Valid ranges: latitude -90 to +90, longitude -180 to +180 (WGS84); these are not range-checked server-side, so validate them client-side.connector-type
{
"connectorType": "wallPlug",
"powerMode": "eleven"
}add-charging-location
{
"chargingLocationId": "vendor-location-id"
}{}install-certificate
{
"url": "https://..."
}{}set-scopes
{
"url": "https://..."
}{}support-tesla-vehicle-command-protocol
{
"supported": true
}email-verification
{
"consentGiven": false
}{}on-off-smart
{
"mode": "smart"
}measurement-purpose
{
"purpose": "gridMeter"
}on-off
{
"state": "on"
}{
"state": "off"
}charging-mode
{
"chargingMode": "clever"
}set-charge-limit
{
"chargeLimit": 80
}set-charging-power
{
"desiredAmperage": 10
}min-max-amperage
{
"minAmperage": 6,
"maxAmperage": 16
}phase-mode
{
"phaseMode": "threePhases"
}phase-switching
{
"supported": true
}sleep-mode
{
"supported": true
}boost
{
"enabled": true
}{
"enabled": true
}link-to-wallbox
{
"linked": true
}location-detection
{
"latitude": 48.137154,
"longitutde": 11.576124,
"atHome": true
}display-soc
{
"soc": 52,
"lastUpdate": "2026-01-30T12:00:00Z"
}soc is state of charge in percent (0–100). If you need kWh, compute from SoC (%) and the known total capacity (see battery-capacity). Appears on cars and on electricMeter devices with an attached battery (including hybrid inverters), whenever the vendor exposes SoC telemetry.display-estimated-range
{
"range": 280
}display-charging-state
{
"chargingState": "charging"
}charging (energy is actively flowing), completed (the charge target was reached and charging stopped), waitingOnCar (cable plugged in and clever-PV requested charging, but the car is not drawing power — e.g. its own charge limit is reached or it paused), awaitingStart (cable plugged in and ready, charging not yet started), error (the vendor reports a fault), noCarConnected (see below), and waitingForStatus (no usable state has been reported yet — typically right after onboarding or while the vendor state can't be mapped). Be tolerant of unknown values. noCarConnected does not mean the device is offline or mis-onboarded. It means the charging cable is currently not plugged into the vehicle — a normal operating state for a car that isn't charging. For VW/Audi/Škoda/Cupra vehicles it maps directly from the vendor's notReadyForCharging / disconnected state. To tell whether the device itself is reachable, use connectivityStatus on the core capability (online / offline), not this value — a device can be online and report noCarConnected at the same time.display-charging-current
{
"amperage": 10
}display-charging-phases
{
"phases": 3
}display-power
{
"power": 3200,
"lastUpdate": "2026-01-30T12:00:00Z"
}display-temperature
{
"temperature": 43.5,
"lastUpdate": "2026-01-30T12:00:00Z"
}display-heating-state
{
"mode": "heating",
"state": "running",
"reason": "solar",
"type": "heating",
"lastUpdate": "2026-01-30T12:00:00Z"
}display-grid-power
{
"gridPower": -450,
"lastUpdate": "2026-01-30T12:00:00Z"
}display-solar-power
{
"solarPower": 1800,
"lastUpdate": "2026-01-30T12:00:00Z"
}display-community-power
{
"communityPower": 120,
"lastUpdate": "2026-01-30T12:00:00Z"
}display-battery-state
{
"state": "charging",
"chargingPower": 1500,
"lastUpdate": "2026-01-30T12:00:00Z"
}state (idle | charging | discharging | disabled) is the authoritative direction. chargingPower is in Watt (W); treat it as a magnitude — use abs(chargingPower). The sign of chargingPower is not normalised across vendors: some adapters forward the raw vendor value (where positive may mean discharging), others normalise to "positive = charging". It is therefore valid to see, e.g., state = "discharging" together with chargingPower > 0 — always derive direction from state, never from the sign.operation-mode
{
"mode": "normal"
}{
"mode": "idle"
}electricMeter device when a controllable battery is attached and the vendor adapter supports it. Allowed values on PUT: normal, idle, forceCharge; forceDischarge is rejected. GET may return unknown when the current battery state cannot be mapped to a supported mode. options.supportedModes lists the modes this specific battery supports. Blocked when the home's battery Smart Price Control automation is active — see smart-price-control-enabled in Interventions. Some vendors (currently SigEnergy and Fronius) additionally require clever-PV to be granted control of the battery first: until control-permission is allowed, this capability carries the control-permission-required intervention and a PUT fails with 400.control-permission
{
"state": "allowed"
}{
"request": "allow"
}electricMeter devices whose battery vendor requires an explicit controllable state (currently SigEnergy and Fronius). state: allowed | pending | forbidden (be tolerant of unknown values). request on PUT: allow or forbid; any other value returns 400. Vendor specifics: for SigEnergy, allow switches the inverter into its remote-control (NorthBound) mode and takes effect immediately; for Fronius, allow starts a vendor registration that sends a verification e-mail to the user — state stays pending until the e-mail is confirmed, then becomes allowed. forbid reverts this (SigEnergy back to self-consumption mode, Fronius deregisters). The state is read from the vendor and fails safe to forbidden when the vendor cannot be reached; it may be cached for up to 1 hour, so a change made directly in the vendor portal can lag — changes made via this API are reflected immediately. Returns 422 capabilityNotSupported when no controllable battery is attached to the meter yet (batteries are detected from live telemetry, so a freshly onboarded inverter may first need to report battery data). While state is not allowed, operation-mode carries the control-permission-required intervention and PUTs to it fail with 400.battery-capacity
{
"batteryCapacity": 10000
}{
"batteryCapacity": 10000
}10000 = 10 kWh. On GET, batteryCapacity is nullable: null means no capacity has been registered yet (either the vendor integration doesn't expose it automatically, or it hasn't been configured manually). Used internally for charging/discharging planning and forecasting. Typically appears on an electricMeter with an attached controllable battery, and on wallbox devices that report onboard EV battery information.consumption
{
"consumption": 150
}{
"consumption": 150
}150 = 15 kWh/100 km. On GET, consumption is nullable: null means it has not been configured yet. Appears on car and wallbox devices. Together with battery-capacity it forms the target-charging setup: while either value is missing, target-charging carries the target-charging-setup-required intervention and cannot be enabled.price-control
{
"enabled": true,
"threshold": 0.25
}price-optimization
{
"enabled": true
}solar-optimization
{
"enabled": true
}pv-control
{
"enabled": true,
"priority": 1,
"ratedCapacity": 2200
}smart-mode
{
"enabled": true
}preferred-operating-mode
{
"mode": "smartControl"
}soc-plan
{
"enabled": true,
"minControlSoc": 20,
"maxControlSoc": 80
}rated-capacity
{
"ratedCapacity": 2200
}priority
{
"priority": 1
}switch-delay
{
"switchDelayOn": 300,
"switchDelayOff": 180
}target-control
{
"enabled": true,
"startTime": "06:00:00",
"endTime": "18:00:00",
"targetRuntime": "02:00:00",
"weekDays": [
"monday",
"tuesday",
"wednesday",
"thursday",
"friday"
],
"type": "repeat",
"useSmartChargePlan": true,
"sendPushNotification": false,
"enableTargetControlLimit": true
}target-charging
{
"enabled": true,
"executionTime": "02:30:00",
"targetWh": 12000,
"targetSoC": 80,
"unitType": "kwh",
"weekDays": [
"monday",
"wednesday",
"friday"
],
"type": "repeat",
"useSmartChargePlan": true,
"sendPushNotification": true,
"enableTargetControlLimit": true
}targetSoC is the target state of charge (Zielladestand). GET may include additional telemetry fields like batteryCapacity, currentSoC, socLimit (nullable). Fields depend on device/product. Requires setup: the device's battery-capacity and consumption must both be configured — otherwise the capability carries the target-charging-setup-required intervention and enabling fails with 422 interventionFound (see Interventions).time-control
{
"nextSchedule": {
"id": "schedule-id",
"type": "repeat",
"weekDays": [
"monday"
],
"executionTime": "02:30:00",
"action": "turnOn",
"actionDetails": null,
"isActive": true,
"description": "Example",
"sendPushNotification": false
},
"schedules": [
{
"id": "schedule-id",
"type": "repeat",
"weekDays": [
"monday"
],
"executionTime": "02:30:00",
"action": "turnOn",
"actionDetails": null,
"isActive": true,
"description": "Example",
"sendPushNotification": false
}
]
}{
"schedules": [
{
"id": "existing-schedule-id",
"type": "repeat",
"weekDays": [
"monday"
],
"executionTime": "09:30:00",
"action": "turnOff",
"actionDetails": null,
"isActive": true,
"description": "Turn off Monday morning",
"sendPushNotification": false
},
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"type": "repeat",
"weekDays": [
"tuesday"
],
"executionTime": "10:30:00",
"action": "socPlanOn",
"actionDetails": {
"minSoC": 20,
"maxSoC": 80
},
"isActive": true,
"description": "SoC plan Tuesday morning",
"sendPushNotification": false
}
]
}executionTime must be an exact five-minute grid point. Details and validation errors: time-control reference.consumption-overview
{ "series": [{ "startTimeUtc": "2026-01-29T00:00:00Z", "endTimeUtc": "2026-01-30T00:00:00Z", "interval": "hourly", "entries": [{ "timestamp": "2026-01-29T00:00:00", "total": 0.12, "solar": 0.05, "price": 0.00, "normal": 0.07 }], "solarHours": 1.5, "priceHours": 0.0, "normalHours": 22.5 } }] }time-control details
PUT uses replace-all semantics: send the full desired list of schedules. Any schedule not included in the request will be deleted.
The API validates every schedule in the incoming list before deleting or recreating any existing schedule. If schedule validation fails, the request returns 400 Bad Request and the existing schedule list is left unchanged.
Execution-time grid
executionTime must be an exact point on the five-minute execution grid:
- Use
HH:mm:ssbetween00:00:00and23:55:00, inclusive. - Minutes must be divisible by 5 (
00,05,10, …,55). - Seconds and fractional seconds must be zero.
Examples: 14:35:00 is valid; 14:37:00, 14:35:12, and 14:37:10 are invalid. An off-grid value returns 400 Bad Request with errorCode: "invalidScheduleExecutionTime" instead of creating a schedule that can never run.
Existing legacy schedules may contain an off-grid time. They can still appear in GET responses, but a replace-all PUT that sends one back unchanged is rejected. Move the time to a five-minute grid point before submitting the full list.
Schedule fields:
| Field | Type | Description |
|---|---|---|
id | string or null | Pass the existing id to update. Use null for a server-generated id, or provide your own GUID. |
type | string | repeat (weekly) or once (one-time). |
weekDays | string[] | e.g. ["monday", "tuesday"]. repeat requires at least one day; once accepts at most one. |
executionTime | string | HH:mm:ss on an exact five-minute grid from 00:00:00 through 23:55:00; seconds must be 00. |
action | string | See actions table below. |
actionDetails | object or null | Required for some actions (see the Actions & actionDetails per device category table immediately below this one), null for all others. |
isActive | boolean | Whether the schedule is enabled. |
description | string or null | PUT requires a non-empty description. GET can return null for legacy schedules. |
sendPushNotification | boolean | Send a push notification when the schedule fires. |
Actions & actionDetails per device category:
| Action | Car | Wallbox | Switch | HeatingRod | actionDetails |
|---|---|---|---|---|---|
turnOn | yes | yes | yes | yes | Car/Wallbox: { "amperage": 16, "phaseMode": "singlePhase" } (required). Others: null. |
turnOff | yes | yes | yes | yes | null |
smartOn | yes | yes | yes | yes | null |
boostOn | yes | yes | — | — | null |
boostOff | yes | yes | — | — | null |
socPlanOn | yes | yes | yes | yes | { "minSoC": 20, "maxSoC": 80 } (required) |
socPlanOff | yes | yes | yes | yes | null |
targetTimesOn | — | — | yes | yes | null |
targetTimesOff | — | — | yes | yes | null |
phaseMode values: singlePhase, twoPhases, threePhases, automatic2Phases, automatic3Phases.
Schedule validation errors
Schedule-specific failures use the ConnectApiProblemDetails response shape. Handle the stable errorCode; use detail only as a human-readable explanation.
| Status | errorCode | Meaning |
|---|---|---|
400 | invalidScheduleExecutionTime | executionTime is outside the supported day range or is not exactly on the five-minute grid. |
400 | invalidSchedulePayload | Schedule fields are missing or inconsistent, such as an empty description, a repeating schedule without weekdays, more than one weekday for once, or missing required actionDetails. |
409 | scheduleOverlapping | Two schedules in the submitted desired state overlap. |
Example off-grid response:
Code
Client checklist
- Always evaluate the device's
capabilities[](instead of assumptions per vendor/model). - Render interventions in the UI (blocker → clear user action).
- Only apply PUT to capabilities you actually see on the device.
- After PUT, reload the device (asynchronous process).
- Evaluate ProblemDetails:
type,status,errorCode,traceId.