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.