List loss events
BearerAuthorizationBearer <token>project_id*stringThe DUET project ID. You must have access to the project.
dt_start*stringThe first date to include, in ISO 8601 format, for example 2026-05-25.
dt_end*stringThe last date to include, in ISO 8601 format, for example 2026-05-31.
sentinel_tag?stringThe deployment tag. Most projects have one deployment, default. A project with several data streams can name a specific deployment.
"default"group_by*stringHow to group the rows:
asset: one row for each inverter, asset, and label. A component that spans inverters, such as a tracker, gets one row for each affected inverter. TheInvestigateresidual is also split by inverter.inverter: one row for each inverter and label.block: one row for each block and label.label: one row for each label, rolled up across the site.
"asset""inverter""block""label"labels_include?array<string>Return only these labels. Repeat the parameter for each label, for example ?labels_include=Investigate&labels_include=Combiner+Outage. Accepts display labels or raw labels.
labels_exclude?array<string>Leave out these labels. Repeat the parameter for each label. Accepts display labels or raw labels. By default, DUET leaves out Grid Curtailment. To include it, pass your own labels_exclude list or list Grid Curtailment in labels_include.
inverter_ids_include?array<string>Return only these inverters. The values match the inverter_id field on response rows. Repeat the parameter for each ID.
inverter_ids_exclude?array<string>Leave out these inverters. Repeat the parameter for each ID.
loss_wh_gt?|Leave out rows where abs(attributed_loss_wh) is less than or equal to this value, in watt-hours.
loss_wh_lt?|Leave out rows where abs(attributed_loss_wh) is greater than or equal to this value, in watt-hours.
limit?integerThe maximum number of rows to return. The default is 10,000 and the maximum is 100,000. If you receive exactly limit rows, more rows might exist. To get them, increase offset by limit and call again.
1 <= value <= 10000010000offset?|The zero-based number of rows to skip. Use it with limit to page through large results.
0 <= value0Accept?string"application/vnd.apache.arrow.stream""application/vnd.apache.arrow.stream""application/vnd.apache.parquet""application/json-seq"A stream of loss-event rows, one for each group_by key. The Accept
header sets the format: an Arrow IPC stream (the default), Parquet, or
JSON-seq, which is newline-delimited JSON objects.
Each row carries attributed_loss_wh (less than or equal to 0),
attributed_gain_wh (greater than or equal to 0), and
attributed_delta_wh (the signed sum). Summed across rows, the signed
sum matches the per-label waterfall total.
- response
project_id*stringThe project ID from the request. Every row has the same value.
label*stringThe display form of the loss label, for example Investigate, Combiner Outage, or Tracker Controller Fault. Investigate covers the unclassified residual and any catch-all classifier output.
inverter_id*|The stable ID of the inverter, which is the AC-power asset that the loss flowed through. It's a DUET composite ID, typically {block_uuid}-inverter-{n}. Set when group_by is asset or inverter. Null otherwise.
inverter_name*|The inverter's display name, for example Feeder-12-Inverter-09.
inverter_sensor_tag*|The SCADA sensor tag of the inverter. Use it to look up the inverter itself, rather than the asset that the label is attached to.
asset_id*|The stable ID of the asset that the loss is attributed to: a combiner for Combiner Outage, a tracker for Tracker Stuck, and the inverter itself for inverter-level labels and Investigate. It's a DUET composite ID, for example {block_uuid}-inverter-6-combiner-9. Equals inverter_id when the label is attached at the inverter level. Set when group_by is asset. Null otherwise.
asset_name*|The asset's display name, for example Feeder-09-Tracker-Controller-1.
sensor_tag*|The SCADA sensor tag of the asset. Use it to find the asset in your monitoring system. Equals inverter_sensor_tag when the label is attached at the inverter level.
duet_block_id*|The ID of the block that the row belongs to. Set when group_by is block. Also set when group_by is asset or inverter and the block is unambiguous.
active_duration_seconds*numberThe total time, in seconds, during which the group had non-zero attribution. Use this field for duration. Don't use max_ts minus min_ts, which is the range that the group's events covered, including gaps.
attributed_loss_wh*numberThe attribution clamped to negative values, in watt-hours. Always less than or equal to 0. It's the loss caused by this group. The sum of abs(attributed_loss_wh) adds up correctly across any grouping.
attributed_gain_wh*numberThe attribution clamped to positive values, in watt-hours. Always greater than or equal to 0, and typically near 0. A non-zero value means the meter exceeded the model during a classified period. This reflects model noise, not asset overperformance.
attributed_delta_wh*numberThe signed sum, in watt-hours. Summed across rows, it matches the per-label waterfall total. attributed_loss_wh + attributed_gain_wh always equals attributed_delta_wh.
min_ts*stringThe earliest time at which the group had non-zero attribution. Format: YYYY-MM-DD HH:MM:SS, in site-local time, with no time zone.
max_ts*stringThe latest time at which the group had non-zero attribution. Format: YYYY-MM-DD HH:MM:SS, in site-local time, with no time zone. The interval from min_ts to max_ts is the range, not the active duration. For the active duration, use active_duration_seconds.
curl -X GET 'https://api.enurgen.com/platform/v1/loss-events?project_id=string&dt_start=string&dt_end=string&group_by=asset'{ "project_id": "string", "label": "string", "inverter_id": "string", "inverter_name": "string", "inverter_sensor_tag": "string", "asset_id": "string", "asset_name": "string", "sensor_tag": "string", "duet_block_id": "string", "active_duration_seconds": 0, "attributed_loss_wh": 0, "attributed_gain_wh": 0, "attributed_delta_wh": 0, "min_ts": "string", "max_ts": "string"}
