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.
These endpoints are supported in Capture Cloud 3.6 and later.
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.
| Path | Purpose |
|---|---|
/v2/data/{database}/{retentionPolicy}/{measurement} | Query datapoints |
/v2/data/{database}/measurements | List measurements in a database |
/v2/data/{database}/{retentionPolicy}/{measurement}/schema | Get field and tag keys for a measurement |
{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
| Header | Value |
|---|---|
| AuthVersion | V0.0.1 (only value accepted; others return 401) |
| Authorization | [Bearer / ApiToken] <Received auth token> |
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)
| Parameter | Reason |
|---|---|
from | Start of window, epoch ms UTC, inclusive. Must be < to. |
to | End 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)
| Parameter | Reason |
|---|---|
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"]
}
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.
Time-Window Chunking (Recommended for Bulk Export)
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.
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:
- Pick a window
[cursor, windowEnd]narrow enough that it rarely holds more than ~10,000 rows (tune to your measurement's density). - Request with
from=cursor,to=windowEnd,limit=10000,offset=0. - If fewer than
limitrows come back, the window is fully drained: advancecursortowindowEnd + 1. - If exactly
limitrows come back, the window may still hold more: advancecursorto(last datapoint's timestamp) + 1and repeat against the samewindowEnd. - Stop when
cursor > overallEnd.
A single chunk request looks like the filtered example in Examples below, with a narrow from/to and limit=10000.
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/towindows over deepoffsets. - 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.
| Status | When |
|---|---|
400 | Validation 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). |
401 | AuthVersion is not V0.0.1, or the token is missing/invalid/expired. |
403 | Valid token but missing Data Explorer → View on the owning company. |
404 | database name does not exist, or retentionPolicy is not configured for that database. |
500 | Database 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"