Pull time-series data
Request measurements in batches, align your time ranges, and read the response shapes.
Use the Data API v4 (https://api.verdigris.co/data/v4) to pull time-series data for the entities you discovered in Rebuild your building topology.
Pick the level (building, panel, breaker, circuit)
Data API v4 takes the integer oldid values from the v3 API, not NanoIDs. Which measurements exist at which level:
| Measurement | Batch endpoint(s) | Units |
|---|---|---|
| Energy | /energy/buildings, /energy/panels, /energy/breakers, /energy/circuits | Wh (type=real, default) or VAh (type=apparent) |
| Power (average) | /power/buildings, /power/panels, /power/breakers, /power/circuits | W |
| Power factor (average) | /power-factor/panels, /power-factor/breakers, /power-factor/circuits | unitless, -1 to 1 (negative can indicate reverse flow, for example solar) |
| Total harmonic distortion (average) | /thd/panels | value key thd; the unit is not specified (site metrics label THD as a percentage, but returned values are small fractions, about 0.006 to 0.03) |
| Voltage (RMS) | /voltage/circuits | V |
| Current (RMS) | /current/circuits | A |
| Weather | /weather/buildings | degrees Celsius |
| Control (BMS) | /control/buildings | as returned |
| Energy forecast | /forecast/buildings | as returned |
Most batch endpoints have a single-entity twin, for example GET /power/panels/{id} (weather, control and forecast are batch-only). Prefer the batch endpoint: one request for many entities uses your rate limit far more efficiently.
Guidance for level selection:
- Building and panel level are the cheapest way to get totals and trends, for example for HVAC optimization baselines.
- Breaker level covers a single protected feed. Circuit level is the finest grain and is per phase.
Common parameters
| Parameter | Where | Notes |
|---|---|---|
ids | query, batch endpoints | Required. Comma-separated integers, for example ids=101,102,103. Duplicates are removed. |
id | path, single-entity endpoints | Integer. |
interval | query | Required. One of 1m, 15m, 1h, 1d, 1M (monthly). Weather accepts only 1h and 1d. |
start_time, end_time | query | Required, ISO 8601. Must be aligned to the interval (see below). |
timestamp_format | query | Omit for Unix epoch in milliseconds; set ISO8601 for ISO strings. |
timezone | query | IANA zone ID, for example America/Chicago. Only changes how ISO timestamps are displayed when timestamp_format=ISO8601. Default UTC. |
type | query, energy only | real (default) or apparent. With apparent, the value key (and the CSV header) is apparent-energy instead of energy. |
Accept | header | application/json (default) or text/csv. |
Time ranges and alignment
start_time and end_time must line up with interval:
1m: any whole minute, for example2020-01-01T12:34:00Z.15m: minutes00,15,30,45.1h: on the hour.1d: midnight in the building's timezone. For a building in Pacific Standard Time,2020-01-01T08:00:00Zand2020-01-01T00:00:00-08:00are valid, while2020-01-01T00:00:00Zis not.
A misaligned 15m or 1h value returns 422 with a message naming the parameter. For 1d and 1M, always use the building's local midnight or month start: the service does not reject a misaligned value, and the buckets returned for one are not defined. Weather requests cannot end more than 10 days in the future. The order of returned timestamps is not guaranteed, so sort on the client. No maximum range or number of IDs per request is enforced, so size your windows to what you need and keep batches reasonable.
Time semantics
- Each row's
timestampis the start of its bucket. end_timeis exclusive for energy, power, current, voltage, power factor, THD and weather. Forecast treatsend_timeas inclusive.1h,1dand1Mbuckets follow each building's own timezone, so a batch that mixes buildings from different timezones is bucketed per building.- A request with
start_timeequal toend_timereturns200with an empty array. timezoneonly controls howtimestamp_format=ISO8601timestamps are displayed (default UTC).
No data and unknown IDs
A valid request with no data in the range returns 200 with an empty array. If any ID does not exist or is not accessible to you, the whole request fails with 404 and invalidIds lists them. Remove those IDs and retry.
Advanced troubleshooting overrides
Circuit endpoints accept override_phase (A, B, C) and override_sensor_orientation (normal, reversed) on energy, power, power-factor. Voltage accepts override_phase. These are for troubleshooting suspect data and can produce wrong results if misused. Do not use them in production integrations.
Examples
Hourly average power (W) for three breakers:
curl -s -G 'https://api.verdigris.co/data/v4/power/breakers' \
-H "Authorization: Bearer $TOKEN" \
--data-urlencode 'ids=201,202,203' \
--data-urlencode 'interval=1h' \
--data-urlencode 'start_time=2025-01-01T00:00:00Z' \
--data-urlencode 'end_time=2025-01-02T00:00:00Z' \
--data-urlencode 'timestamp_format=ISO8601'[
{ "id": 201, "timestamp": "2025-01-01T00:00:00Z", "power": 1523.4 }
]Daily real energy (Wh) for a building, using the building's local timezone for alignment (Pacific Standard Time in this example):
curl -s -G 'https://api.verdigris.co/data/v4/energy/buildings' \
-H "Authorization: Bearer $TOKEN" \
--data-urlencode 'ids=42' \
--data-urlencode 'interval=1d' \
--data-urlencode 'type=real' \
--data-urlencode 'start_time=2025-01-01T00:00:00-08:00' \
--data-urlencode 'end_time=2025-01-08T00:00:00-08:00'[
{ "id": 42, "timestamp": 1735718400000, "energy": 18273.97 }
]15-minute energy as CSV for a panel:
curl -s -G 'https://api.verdigris.co/data/v4/energy/panels' \
-H "Authorization: Bearer $TOKEN" \
-H 'Accept: text/csv' \
--data-urlencode 'ids=101' \
--data-urlencode 'interval=15m' \
--data-urlencode 'start_time=2025-01-01T00:00:00Z' \
--data-urlencode 'end_time=2025-01-01T06:00:00Z'id,timestamp,energy
101,1735689600000,18273.97
Hourly outdoor temperature and humidity for buildings (weather uses include):
curl -s -G 'https://api.verdigris.co/data/v4/weather/buildings' \
-H "Authorization: Bearer $TOKEN" \
--data-urlencode 'ids=42' \
--data-urlencode 'interval=1h' \
--data-urlencode 'include=temperature,humidity' \
--data-urlencode 'start_time=2025-01-01T00:00:00Z' \
--data-urlencode 'end_time=2025-01-02T00:00:00Z'All example values are illustrative.
Response shapes
Responses are flat arrays with one row per entity and timestamp:
| Endpoint family | Row fields |
|---|---|
| Energy | id, timestamp, energy (apparent-energy when type=apparent) |
| Power | id, timestamp, power |
| Power factor | id, timestamp, power-factor (unitless, -1 to 1) |
| Total harmonic distortion | id, timestamp, thd |
| Weather | id, timestamp, temperature (°C), plus humidity (a fraction from 0 to 1) and dewPoint (°C) when you ask for them with include |
| Control | id (string), timestamp, device-id, control |
| Forecast | id, timestamp, and quantile columns q1, q5, q10, q15, ... q95, q99 |
timestamp is an integer (epoch milliseconds) unless timestamp_format=ISO8601. CSV responses carry the same columns, with the same header names.
Control accepts one building ID per request and only returns data for sites with an integrated building management system. Forecast returns future time steps (15-minute resolution), so a window in the past is empty, and its end_time is inclusive.
Other Data API resources
- Waveforms: raw current and voltage waveforms per circuit: circuit current waveform, circuit voltage waveform, and the batch versions.
- Pro Capture events: power-quality event records and waveforms for a panel or a whole building: building events, panel events, panel waveforms. These are different from Signals events in API v3.
Errors specific to the Data API
Errors are JSON objects with name, message, and status.
| Status | Meaning |
|---|---|
| 401 | Missing or invalid token. |
| 403 | The token lacks the required permission (code is permission_denied). |
| 404 | One or more IDs do not exist in your account. The body lists them in invalidIds. |
| 422 | Validation failed. errors[] lists location, param, msg, and value for each problem. |
Recommended pattern for an optimizer
- Build the topology once and store
nanoidtooldidmappings. - Group the IDs you need by level and call the batch endpoint, one request per measurement and level, rather than one request per entity.
- Poll incrementally: request only the window since your last successful timestamp, at the coarsest
intervalthat satisfies your control loop. - Retry failures with backoff, as described in Rate limits.
Updated 27 days ago

