WaterlyWaterlyConnect Developer Hub
API Guidedata-points:readRead only

Data Points API

Read normalized time-series values for one metric, one resource, or a larger set of metrics and resources. Every query requires an applied-at date range.

Choose the smallest query that fits

One known metric

Use GET /api/metrics/v1/{metricId}/data-points. This is the clearest route for charting or exporting one measurement.

One value per filter

Use GET /api/data-points/v1 when a URL with optional single metric, system, site, process, and component filters is convenient.

Several IDs at once

Use POST /api/data-points/v1/query for arrays of metric or resource IDs and a structured request body.

Need names and units

Request metric and/or unit includes to embed related metadata with each value.

Read data points for one metric

GET/api/metrics/v1/{metricId}/data-points
Example request
curl --digest \
  --user "$WATERLY_API_USERNAME:$WATERLY_API_SECRET" \
  "https://connect.waterly.com/api/metrics/v1/91/data-points?start=2026-01-01&end=2026-01-31&include=metric,unit&limit=100"
Example response
{
  "data": [{
    "metric_id": 91,
    "applied_at": "2026-01-02T00:00:00.000Z",
    "measured_at": "2026-01-02T00:01:00.000Z",
    "value_type": "numeric",
    "value": 1.42,
    "source": "human",
    "status": {
      "is_calculated": false,
      "is_interpolated": false,
      "is_nondetect": false
    },
    "metric": {
      "kind": "metric", "id": 91, "name": "Chlorine Residual",
      "parent": { "kind": "component", "id": 82 },
      "order": 1,
      "attributes": { "data_type": "NUMERIC", "unit_id": 5, "internal_keyname": "chlorine_residual" }
    },
    "unit": { "id": 5, "name": "mg/L" }
  }],
  "links": { "self": "...", "next": null, "prev": null },
  "meta": { "limit": 100, "has_next": false, "has_prev": false }
}

Make a simple filtered query

The organization ID, start, and end are required. All ID filters are optional. When you supply more than one filter, Waterly returns only data points that match all of them.

GET/api/data-points/v1
organization_idstartendmetric_idsystem_idsite_idprocess_idcomponent_idincludelimitcursor
curl --digest \
  --user "$WATERLY_API_USERNAME:$WATERLY_API_SECRET" \
  "https://connect.waterly.com/api/data-points/v1?organization_id=123&site_id=55&start=2026-01-01&end=2026-01-31&include=unit"

Query several metrics or resources

The query route accepts up to 200 unique IDs in each array. Empty arrays add no restriction. Non-empty metric and resource filters intersect, which makes this route useful for precise exports.

POST/api/data-points/v1/query
Example request
curl --digest \
  --user "$WATERLY_API_USERNAME:$WATERLY_API_SECRET" \
  --header "Content-Type: application/json" \
  --request POST \
  --data '{
    "organization_id": 123,
    "metric_ids": [91, 92, 93],
    "filters": {
      "system_ids": [40],
      "site_ids": [55],
      "process_ids": [],
      "component_ids": []
    },
    "range": {
      "start": "2026-01-01T00:00:00Z",
      "end": "2026-02-01T00:00:00Z"
    },
    "pagination": { "limit": 200, "cursor": null },
    "include": { "metric": true, "unit": true }
  }' \
  "https://connect.waterly.com/api/data-points/v1/query"
Following the next page — Reuse the same JSON body and make the next request to the absolute URL in links.next. Its query-string cursor overrides pagination.cursor.

Date ranges and filter behavior

  • Ranges apply to applied_at. A date-time range is half-open: start is included and end is excluded.
  • A date-only end such as 2026-01-31 includes that entire UTC calendar day.
  • Explicit metric IDs and every non-empty resource filter intersect; a data point must satisfy all of them.
  • Use the same filters when following cursor links. Cursors are tied to the original query and should be treated as opaque.
  • The default page size is 50; limit may be from 1 to 200.

Understand each normalized value

Field Meaning
metric_id Metric that owns the value.
applied_at Time at which Waterly applies the winning value in the time series.
measured_at Time at which the value was measured or recorded.
value_type How to interpret value: text, numeric, boolean, date, time, date_time, json, user_select, or image.
source human, calculated, waterly_connect, or null.
status Flags indicating calculated, interpolated, or nondetect values.
metric / unit Optional related records, present only when requested with include.