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:

MeasurementBatch endpoint(s)Units
Energy/energy/buildings, /energy/panels, /energy/breakers, /energy/circuitsWh (type=real, default) or VAh (type=apparent)
Power (average)/power/buildings, /power/panels, /power/breakers, /power/circuitsW
Power factor (average)/power-factor/panels, /power-factor/breakers, /power-factor/circuitsunitless, -1 to 1 (negative can indicate reverse flow, for example solar)
Total harmonic distortion (average)/thd/panelsvalue 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/circuitsV
Current (RMS)/current/circuitsA
Weather/weather/buildingsdegrees Celsius
Control (BMS)/control/buildingsas returned
Energy forecast/forecast/buildingsas 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

ParameterWhereNotes
idsquery, batch endpointsRequired. Comma-separated integers, for example ids=101,102,103. Duplicates are removed.
idpath, single-entity endpointsInteger.
intervalqueryRequired. One of 1m, 15m, 1h, 1d, 1M (monthly). Weather accepts only 1h and 1d.
start_time, end_timequeryRequired, ISO 8601. Must be aligned to the interval (see below).
timestamp_formatqueryOmit for Unix epoch in milliseconds; set ISO8601 for ISO strings.
timezonequeryIANA zone ID, for example America/Chicago. Only changes how ISO timestamps are displayed when timestamp_format=ISO8601. Default UTC.
typequery, energy onlyreal (default) or apparent. With apparent, the value key (and the CSV header) is apparent-energy instead of energy.
Acceptheaderapplication/json (default) or text/csv.

Time ranges and alignment

start_time and end_time must line up with interval:

  • 1m: any whole minute, for example 2020-01-01T12:34:00Z.
  • 15m: minutes 00, 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:00Z and 2020-01-01T00:00:00-08:00 are valid, while 2020-01-01T00:00:00Z is 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 timestamp is the start of its bucket.
  • end_time is exclusive for energy, power, current, voltage, power factor, THD and weather. Forecast treats end_time as inclusive.
  • 1h, 1d and 1M buckets follow each building's own timezone, so a batch that mixes buildings from different timezones is bucketed per building.
  • A request with start_time equal to end_time returns 200 with an empty array.
  • timezone only controls how timestamp_format=ISO8601 timestamps 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 familyRow fields
Energyid, timestamp, energy (apparent-energy when type=apparent)
Powerid, timestamp, power
Power factorid, timestamp, power-factor (unitless, -1 to 1)
Total harmonic distortionid, timestamp, thd
Weatherid, timestamp, temperature (°C), plus humidity (a fraction from 0 to 1) and dewPoint (°C) when you ask for them with include
Controlid (string), timestamp, device-id, control
Forecastid, 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

Errors specific to the Data API

Errors are JSON objects with name, message, and status.

StatusMeaning
401Missing or invalid token.
403The token lacks the required permission (code is permission_denied).
404One or more IDs do not exist in your account. The body lists them in invalidIds.
422Validation failed. errors[] lists location, param, msg, and value for each problem.

Recommended pattern for an optimizer

  1. Build the topology once and store nanoid to oldid mappings.
  2. Group the IDs you need by level and call the batch endpoint, one request per measurement and level, rather than one request per entity.
  3. Poll incrementally: request only the window since your last successful timestamp, at the coarsest interval that satisfies your control loop.
  4. Retry failures with backoff, as described in Rate limits.

Did this page help you?