Telemetry
Telemetry is a high-volume time series associated with an athlete. Every sample is encoded as a compact numeric array instead of a JSON object. The first value is always a Unix timestamp in milliseconds, expressed in UTC.
Prefer the aggregate fields in a normal ClubTrainingDTO unless the integration
needs sample-level analysis, charting, or route reconstruction.
Raw telemetry operations
Section titled “Raw telemetry operations”The Club API exposes five raw telemetry series:
| Series | Operation | Tuple |
|---|---|---|
| Heart rate | GET /Athletes/{userId}/Telemetry/Heartbeats |
[timestampUnixMs, beatsPerMinute] |
| Geolocation | GET /Athletes/{userId}/Telemetry/GeoPositions |
[timestampUnixMs, distanceMeters, latitudeDegrees, longitudeDegrees, altitudeMeters] |
| Power | GET /Athletes/{userId}/Telemetry/Power |
[timestampUnixMs, watts] |
| Cadence | GET /Athletes/{userId}/Telemetry/Cadence |
[timestampUnixMs, revolutionsPerMinute] |
| HIT | GET /Athletes/{userId}/Telemetry/Hits |
19-value tuple described under HIT tuples |
Both from and to must be supplied as ISO 8601 timestamps. The boundaries
are inclusive and one request may cover at most five hours:
curl --request GET \ --url "https://api-gw.uptivo.fit/club/Athletes/300001/Telemetry/Heartbeats?from=2026-09-04T08%3A00%3A00Z&to=2026-09-04T09%3A00%3A00Z" \ --header "X-Sub-Key: <subscription-key>" \ --header "Authorization: Bearer <club-api-key>"Raw telemetry responses are not paginated. Split a longer period into adjacent windows of no more than five hours, remembering that both ends are inclusive. Deduplicate samples on the boundary timestamp if two windows share it.
The athlete must currently belong to the club selected by the Club API Key.
The endpoint returns 404 Not Found when the athlete is outside that scope.
When the athlete is accessible but the requested interval has no samples, the
API returns 200 OK with an empty array.
Decode the compact arrays
Section titled “Decode the compact arrays”Array positions are part of the public contract; do not infer them from the numeric type alone.
Heart rate
Section titled “Heart rate”[ [1603317955000, 92], [1603317960000, 91]]The first sample means 2020-10-21T22:05:55.000Z and 92 beats per minute.
Geolocation
Section titled “Geolocation”[ [1602916604000, 1750.98, 45.7227933, 9.1307737, 401.05]]This sample means:
| Position | Meaning | Unit |
|---|---|---|
| 0 | Timestamp | Unix epoch milliseconds, UTC |
| 1 | Distance from the beginning of the track | meters |
| 2 | Latitude | decimal degrees |
| 3 | Longitude | decimal degrees |
| 4 | Altitude | meters |
The example timestamp is 2020-10-17T06:36:44.000Z.
Power and cadence
Section titled “Power and cadence”{ "Powers": [[1603350935000, 203]], "Cadences": [[1596470835000, 82]]}The power sample is 203 watts at 2020-10-22T07:15:35.000Z. The cadence
sample is 82 revolutions per minute at 2020-08-03T16:07:15.000Z.
A decoder should convert tuples into named application objects immediately:
function decodeHeartRate([timestampUnixMs, beatsPerMinute]) { return { timestamp: new Date(timestampUnixMs), beatsPerMinute };}
function decodeGeoPosition([ timestampUnixMs, distanceMeters, latitudeDegrees, longitudeDegrees, altitudeMeters,]) { return { timestamp: new Date(timestampUnixMs), distanceMeters, latitudeDegrees, longitudeDegrees, altitudeMeters, };}Reject or quarantine tuples with an unexpected length. This prevents a future contract mismatch from silently shifting one measurement into another field.
Telemetry attached to trainings
Section titled “Telemetry attached to trainings”Set withTelemetry=true on any Training operation when telemetry must be
aligned to the exact Begin and End of each training:
GET /Trainings/{trainingId}?withTelemetry=trueGET /Trainings?withTelemetry=trueGET /Athletes/{userId}/Trainings?withTelemetry=true
An abbreviated response has this shape:
{ "TrainingId": 400001, "UserId": 300001, "Begin": "2026-09-04T08:00:00Z", "BeginDateLocal": "2026-09-04", "End": "2026-09-04T09:00:00Z", "Telemetry": { "HeartBeats": [[1788508805000, 92]], "GeoPositions": [], "Powers": [[1788508810000, 203]], "Cadences": [[1788508815000, 82]], "Hits": [] }}The response remains a flat ClubTrainingDTO. Telemetry is omitted when
withTelemetry is false; when requested, an empty series means that no
qualifying samples were found. Do not treat an empty series as an error for the
whole training.
The independent withUser=true flag adds the current ClubAthleteDTO as
User. It can be combined with withTelemetry=true. User is omitted when it
was not requested and when the owner of a historical club training is no
longer an Athlete of the selected club.
Lists with withTelemetry=true default to 10 trainings and cap count at 30.
They retrieve several time series for every item, so use the normal training
list for bulk synchronization and fetch telemetry only for the records that need
it. Both enrichment flags leave selection and the ID or (Begin, TrainingId)
cursor position unchanged, so withTelemetry and withUser may be changed
between pages. Keep the endpoint, range, and selection filters unchanged, then
pass NextCursor or PrevCursor without modification. See
Pagination and synchronization.
HIT tuples
Section titled “HIT tuples”HIT samples are available from the raw Athlete telemetry operation and inside
Training responses requested with withTelemetry=true. Each tuple contains 19
values:
| Positions | Meaning | Unit |
|---|---|---|
| 0 | UTC Unix timestamp | milliseconds since the Unix epoch |
| 1, 10 | Right and left hit count | count |
| 2, 11 | Right and left average force | g |
| 3, 12 | Right and left maximum force | g |
| 4, 13 | Right and left average speed | km/h |
| 5, 14 | Right and left maximum speed | km/h |
| 6, 15 | Right and left out time | seconds |
| 7, 16 | Right and left minimum out time | seconds |
| 8, 17 | Right and left in time | seconds |
| 9, 18 | Right and left minimum in time | seconds |
Protect performance and athlete data
Section titled “Protect performance and athlete data”- Request the narrowest time interval that satisfies the use case.
- Do not download raw telemetry during every reconciliation if aggregate training values are enough.
- Stream or process large arrays incrementally where your HTTP client permits it, and avoid copying the payload repeatedly in memory.
- Apply retention, access-control, and privacy rules appropriate to athlete health and location data.
- Log identifiers and range boundaries, not telemetry payloads or credentials.
The Club API allows 50 calls per minute and 25,000 calls per 30 days. Raw
telemetry can produce large payloads, so clients should use bounded concurrency
and avoid repeated downloads of the same interval. See
Trainings for synchronization and
Errors for quota headers and 429 Too Many Requests
handling.