Skip to main content
Version: V3.2

Raw time series Read API

Read endpoints for time-series data on the v2 Data API. These are the replacements for the legacy /api/data endpoint (see Query Time Series Data) and are designed to be consumed without knowledge of the underlying store.

info

These endpoints are supported in Capture Cloud 3.6 and later.

info

All timestamps are epoch milliseconds, UTC. Both from and to are inclusive.

Endpoints

All routes are GET requests under https://portal.captureplatform.com and share the headers below.

PathPurpose
/v2/data/{database}/{retentionPolicy}/{measurement}Query datapoints
/v2/data/{database}/measurementsList measurements in a database
/v2/data/{database}/{retentionPolicy}/{measurement}/schemaGet field and tag keys for a measurement
info

{retentionPolicy} is the name of the retention policy that holds the measurement's data (e.g. oneYear). You can find the retention policies configured for your database in the Storage Hub.

Headers

HeaderValue
AuthVersionV0.0.1 (only value accepted; others return 401)
Authorization[Bearer / ApiToken] <Received auth token>
tip

The caller needs the Data Explorer → View right on the company that owns the target database. Missing rights return 403.

Query Datapoints

GET /v2/data/{database}/{retentionPolicy}/{measurement}

Parameters (Query String)

ParameterReason
fromStart of window, epoch ms UTC, inclusive. Must be < to.
toEnd of window, epoch ms UTC, inclusive.
tags (Optional)Tag filters, AND-combined. One pair per key: ?tags[location]=room1&tags[device]=sensor-a. Keys and values must be non-empty.
fields (Optional)Fields to return. Repeat the parameter to request several: ?fields=temp&fields=humidity (default: all).
limit (Optional)Max rows per page. 1..10000 (default: 1000).
offset (Optional)Rows to skip (default: 0, min 0).

Response

[
{
"measurement": "temperature",
"tags": { "location": "room1", "device": "sensor-a" },
"fields": { "temp": 23.5, "humidity": 48.2 },
"timestamp": 1703000000000
}
]

Results are ordered by timestamp ascending, then by tag columns ascending. Ordering is stable across pages for a fixed from/to.

List Measurements

GET /v2/data/{database}/measurements

Parameters (Query String)

ParameterReason
limit (Optional)Max rows per page. 1..10000 (default: 1000).
offset (Optional)Rows to skip (default: 0, min 0).

Response

["temperature", "pressure", "flow"]

Get Measurement Schema

GET /v2/data/{database}/{retentionPolicy}/{measurement}/schema

Returns the known field and tag keys.

Response

{
"measurement": "temperature",
"fields": ["temp", "humidity"],
"tags": ["location", "device"]
}
tip

Fetch the schema once and cache it. Use the exact tag and field names it returns: querying unknown or mis-cased names can return 400.

Pagination

Two complementary techniques. Pick based on how much data you're pulling.

Within-Window Pagination (limit + offset)

Use for a fixed time window small enough to scan in one go. Historical data is immutable and the connector orders rows deterministically, so pages are stable.

page 0:  GET /v2/data/db/rp/meas?from=FROM&to=TO&limit=1000&offset=0
page 1: GET /v2/data/db/rp/meas?from=FROM&to=TO&limit=1000&offset=1000
page 2: GET /v2/data/db/rp/meas?from=FROM&to=TO&limit=1000&offset=2000

End of results: stop when a page returns fewer rows than limit. There is no total field and no next-page cursor.

For large ranges (hours of dense data, days of sparse data, or full-history backfills), do not use deep offsets. Slide the time window instead.

warning

Offset-based paging typically requires the server to walk past the skipped rows before returning a page, so cost grows with offset and becomes slow at large values (see PostgreSQL docs on LIMIT/OFFSET). Time-window chunking keeps every request bounded to a narrow window regardless of how much total data you're pulling.

Recipe:

  1. Pick a window [cursor, windowEnd] narrow enough that it rarely holds more than ~10,000 rows (tune to your measurement's density).
  2. Request with from=cursor, to=windowEnd, limit=10000, offset=0.
  3. If fewer than limit rows come back, the window is fully drained: advance cursor to windowEnd + 1.
  4. If exactly limit rows come back, the window may still hold more: advance cursor to (last datapoint's timestamp) + 1 and repeat against the same windowEnd.
  5. Stop when cursor > overallEnd.

A single chunk request looks like the filtered example in Examples below, with a narrow from/to and limit=10000.

info

Step 4 advances by +1 ms. In high-cardinality measurements with thousands of sensors reporting on synchronized intervals, more than limit datapoints can share a single millisecond; peers beyond limit at that timestamp will be skipped. Raise limit to its maximum (10000) or apply tags filters to reduce the row count per millisecond. There is no within-millisecond cursor.

Best Practices

  • Prefer narrow from/to windows over deep offsets.
  • Tune window size to data density, not wall-clock time. A window that holds a few thousand rows is the sweet spot.
  • Fetch the schema once and cache it.
  • Historical data is immutable, so repeating a completed chunk is idempotent.

Error Responses

The body is a plain message string.

StatusWhen
400Validation failed (from >= to, limit out of range, empty tag/field), or the connector raised InvalidOperationException / NotImplementedException (for example, querying an unknown field/tag on the Timescale wide backend).
401AuthVersion is not V0.0.1, or the token is missing/invalid/expired.
403Valid token but missing Data Explorer → View on the owning company.
404database name does not exist, or retentionPolicy is not configured for that database.
500Database connection failure (NpgsqlException) or any unexpected exception.

Examples

# List measurements
curl -sG "https://portal.captureplatform.com/v2/data/mydb/measurements" \
-H "AuthVersion: V0.0.1" \
-H "Authorization: Bearer <token>" \
--data-urlencode "limit=100"

# Get schema
curl -s "https://portal.captureplatform.com/v2/data/mydb/oneYear/temperature/schema" \
-H "AuthVersion: V0.0.1" \
-H "Authorization: Bearer <token>"

# Query datapoints, filtered by tag, with two specific fields
curl -sG "https://portal.captureplatform.com/v2/data/mydb/oneYear/temperature" \
-H "AuthVersion: V0.0.1" \
-H "Authorization: Bearer <token>" \
--data-urlencode "from=1703000000000" \
--data-urlencode "to=1703086400000" \
--data-urlencode "tags[location]=room1" \
--data-urlencode "fields=temp" \
--data-urlencode "fields=humidity" \
--data-urlencode "limit=1000"