Time Series
Returns GNSS measurements for one or more stations over a time range. Use it to get Zenith Total Delay (ZTD), Precipitable Water Vapour (PWV), and per-satellite data for historical analysis.
Get station ids from Stations first.
Request format
POST https://api.skyfora.com/api/v1/measurements/query
| Header | Required | Value |
|---|---|---|
X-API-Key |
Yes | Your organization API key |
Content-Type |
Yes | application/json |
curl -X POST https://api.skyfora.com/api/v1/measurements/query \
-H "X-API-Key: your-api-key-here" \
-H "Content-Type: application/json" \
-d '{
"start_time": "2026-03-20T00:00:00Z",
"end_time": "2026-03-21T00:00:00Z",
"station_ids": ["4f9b1c2e-6a70-4a3e-9a4f-2d8f5b7c0e11"],
"data_vars": ["ztd", "ztd_sigma"]
}'
import requests
resp = requests.post(
"https://api.skyfora.com/api/v1/measurements/query",
headers={"X-API-Key": "your-api-key-here"},
json={
"start_time": "2026-03-20T00:00:00Z",
"end_time": "2026-03-21T00:00:00Z",
"station_ids": ["4f9b1c2e-6a70-4a3e-9a4f-2d8f5b7c0e11"],
"data_vars": ["ztd", "ztd_sigma"],
},
)
resp.raise_for_status()
rows = resp.json()["data"]
Required parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
start_time |
ISO 8601 string | Start of the time range, inclusive. | 2026-03-20T00:00:00Z |
end_time |
ISO 8601 string | End of the time range, exclusive. | 2026-03-21T00:00:00Z |
station_ids |
array of UUID | One or more station ids from GET /stations. |
["4f9b1c2e-..."] |
data_vars |
array of string | Variables to return. See Variables. | ["ztd", "pwv"] |
Optional parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
interval_seconds |
integer | none | Group observations into intervals of this many seconds, at least 30, aligned to UTC (for example 900 for 00:00, 00:15, 00:30). See Intervals. Omit to get every observation. |
raw |
boolean | false |
When true, the response also includes observations that the default quality filter excludes. Use for diagnostics. |
Response format
The response is JSON: one row per station and epoch, in time order.
{
"data": [
{
"timestamp": "2026-03-20T12:00:00.000Z",
"station_id": "4f9b1c2e-6a70-4a3e-9a4f-2d8f5b7c0e11",
"display_name": "RAW_RAAS",
"ztd": 2353.5,
"ztd_sigma": 4.0
}
],
"count": 1
}
| Field | Description |
|---|---|
data[].timestamp |
Observation time (UTC) |
data[].station_id |
Station id (UUID) |
data[].display_name |
Station display name |
data[].<variable> |
One field for each requested variable |
count |
Number of rows in the response |
Per-satellite variables come as comma-separated strings in the order of prn; see Variables for each format. A row with satellite variables:
{
"timestamp": "2026-03-20T12:00:00.000Z",
"station_id": "4f9b1c2e-6a70-4a3e-9a4f-2d8f5b7c0e11",
"display_name": "RAW_RAAS",
"prn": "E03,E05,G08",
"el": "22.3,74.2,9.8",
"az": "278.2,255.4,94.4"
}
Intervals
With interval_seconds, the response has one row per station and interval instead of one per observation. timestamp is the start of the interval.
| Variable | Value in an interval |
|---|---|
ztd, ztd_sigma, pwv |
Mean of the observations in the interval |
snr, el, az, prn |
From the first observation in the interval |
The quality filter applies before the mean. An interval with no observation for a station has no row for it.
Intervals make long ranges smaller to download and easier to plot. Use 900 (15 minutes) or 3600 (1 hour) for weeks or months of data.
Data checks and quality control
By default, the response contains only observations that pass the Skyfora quality filter. Set raw: true to get all observations, including the excluded ones.
Skyfora calculates each observation with precise point positioning (PPP): a station position and tropospheric delay solved from satellite signals and precise satellite orbit and clock corrections. An observation is returned only when that solution is stable and the station tracked enough good signals:
| Check | What it detects |
|---|---|
| Convergence | The solution has not settled yet. This happens after processing starts or restarts for a station, for example after the correction source changes. The ZTD uncertainty is high until it settles. |
| Solution state | No full PPP solution for the epoch. |
| Tracking quality | Too few satellites, weak signals, or many measurements rejected as outliers. Radio interference such as jamming, and obstructions around the antenna, cause these. |
A gap in the response means the station sent no observations in that period, or none passed these checks. To tell the two apart, repeat the request with raw: true.
The observation interval is different for each station. Read resolution_seconds from GET /stations to get the epoch interval of a station.
Limits
All observations in the time range come back in one response. There is no pagination.
Data points
The size of a request is counted in data points: the epochs in the range, summed over the stations. A station's epoch is its observation rate, resolution_seconds in Stations, which differs between networks. When interval_seconds is longer than that, each interval counts once.
For stations with a 30-second resolution:
| Request | Data points |
|---|---|
| 1 station, 1 day, every epoch | 2,880 |
1 station, 7 days, interval_seconds: 900 |
672 |
10 stations, 3 days, interval_seconds: 3600 |
720 |
Each organization has a data-point limit per request. A request over the limit is rejected with 413 Content Too Large before it runs, and the error message states the limit. Set interval_seconds, or split a larger request by time range or by groups of stations and combine the results.
A request that runs past the processing deadline is rejected with 408 Request Timeout. Too many requests at the same time are rejected with 429 Too Many Requests; retry after the time in the Retry-After header. See Errors for every status code.