Pagination & time ranges
The list envelope, limit/offset pagination, and UTC time windows.
The list envelope
Every list endpoint returns the same envelope:
{
"data": [ ... ],
"meta": {
"limit": 50,
"offset": 0,
"count": 137
}
}data— the items for this page.meta.count— always present: the number of items matching the query.meta.limit/meta.offset— present on paginated (O&M) lists, echoing the effective values.
Offset pagination (O&M lists)
The O&M lists — /work-orders and /defects — take limit and offset query parameters:
curl "https://api.owner.dynvolt.com/v1/sites/pv-ljubas/work-orders?limit=50&offset=100" \
-H "Authorization: Bearer $DYNVOLT_API_KEY"Page until offset + len(data) >= meta.count:
items, offset, limit = [], 0, 50
while True:
page = client.get(
"/v1/sites/pv-ljubas/work-orders",
params={"limit": limit, "offset": offset},
).json()
items += page["data"]
offset += len(page["data"])
if offset >= page["meta"]["count"] or not page["data"]:
breakTime ranges (time-series endpoints)
Time-series endpoints — telemetry history, energy matrices, hourly earnings, predictions, BESS logs, telemetry gaps — take a time window instead of an offset:
start/end— timestamps, interpreted as UTC.limit— caps the number of returned rows.
curl "https://api.owner.dynvolt.com/v1/sites/pv-ljubas/energy/hourly?start=2026-08-01T00:00:00Z&end=2026-08-08T00:00:00Z" \
-H "Authorization: Bearer $DYNVOLT_API_KEY"For long backfills, walk the window in chunks (e.g. one week at a time) rather than requesting months in a single call — smaller windows respond faster and retry more cheaply.
start/end as timestamps vs dates
Most windows want RFC3339 UTC timestamps (2026-08-01T00:00:00Z). A few take plain dates (YYYY-MM-DD):
- Timestamps — telemetry/history,
energy/hourly, predictions, BESS logs, gaps, I-V series. - Dates —
earnings/*(start/endare days) and the daily endpoints, which take a singledate(forecast,plant/summary) ortarget_date(markets prices, BESS schedules/deviations).
limit caps by area
limit is clamped to a per-area maximum — request more and you get the cap, not an error:
| Area | Endpoints | Cap |
|---|---|---|
| Telemetry history | loggers / inverters / strings / sensors / BESS history, dispatch & control logs, BESS alarm history | 10,000 |
| Weather / EMI | weather/logger/{id}/history | 2,000 |
| I-V expected | iv/strings/{…}/expected | 5,000 |
| Telemetry gaps | gaps, gaps/logger/{id} | 500 |
| O&M lists | work-orders, defects, om/notifications | 200 |
Everything is UTC
All timestamps in the API — request parameters and response fields — are UTC ISO-8601 (2026-08-11T06:00:00Z). The plants operate in local European time zones, but the API never returns local time. Convert at the display layer, not in storage:
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
utc = datetime.fromisoformat("2026-08-11T06:00:00+00:00")
local = utc.astimezone(ZoneInfo("Europe/Skopje"))Send Z-suffixed (or +00:00) timestamps in queries; naive timestamps are rejected with 422 validation_error.

