Skip to content

Training events

Uptivo currently publishes one training event type.

Training.Created is sent when a completed training for an athlete in the club is created. The subject is Trainings/{trainingId}. The data object contains the same public ClubTrainingDTO fields returned by the Training operations, plus contact, activity totals, and goals reached by this training.

Webhook delivery does not request response enrichments, so the optional Telemetry and User properties are omitted. If either is needed, use data.TrainingId with GET /Trainings/{trainingId} and the corresponding withTelemetry or withUser flag after acknowledging the event.

The following event is abbreviated: it shows representative training metrics and the additional event fields, not every ClubTrainingDTO property.

[
{
"id": "example-training-created-event",
"topic": "club-100001-events",
"subject": "Trainings/400001",
"data": {
"TrainingId": 400001,
"UserId": 300001,
"ClubId": 100001,
"Begin": "2026-09-07T15:56:22.470+00:00",
"BeginDateLocal": "2026-09-07",
"End": "2026-09-07T16:37:00.434+00:00",
"Duration": "00:40:37.964",
"Points": 139,
"CaloriesTotal": 401,
"TargetZoneTime": "00:13:48",
"Zone0Time": "00:00:00",
"Zone1Time": "00:00:00",
"Zone2Time": "00:11:20",
"Zone3Time": "00:05:40",
"Zone4Time": "00:05:44",
"Zone5Time": "00:11:32",
"Distance": 0,
"MinBpm": 115,
"MaxBpm": 185,
"AvgBpm": 149,
"IsSubTraining": false,
"IsLive": false,
"TrainingType": "Unspecified",
"Contact": {
"Email": "athlete@example.test",
"FirstMidName": "Alex",
"LastName": "Example",
"Nickname": "Alex",
"Phone": null
},
"TrainingMonthTotals": {
"Trainings": 12,
"Points": 1800,
"Calories": 4100,
"DurationSecs": 21600,
"Distance": 18000,
"TargetZoneTimeSecs": 7800,
"HitsACount": 0,
"HitsPoints": 0,
"ClubPoints": 1200
},
"LifetimeTotals": {
"Trainings": 83,
"Points": 12000,
"Calories": 29500,
"DurationSecs": 148000,
"Distance": 124000,
"TargetZoneTimeSecs": 51000,
"HitsACount": 0,
"HitsPoints": 0,
"ClubPoints": 7500
},
"AchievedGoals": [
{
"ChallengeId": 900001,
"ChallengeName": "September Challenge",
"GoalStep": 1,
"BadgeId": 910001,
"BadgeName": "First milestone"
}
]
},
"eventType": "Training.Created",
"eventTime": "2026-09-07T15:56:22.470Z",
"dataVersion": "1.0"
}
]

Depending on the workout, the shared Training fields also include power, cadence, speed, elevation, position, and HIT metrics. BeginDateLocal is the start date in the athlete’s timezone, formatted YYYY-MM-DD; it may differ from the UTC date of Begin. Ignore properties unknown to the current consumer and use the Trainings guide for metric units.

Additional data field Meaning
Contact Athlete contact snapshot: Email, FirstMidName, LastName, Nickname, and Phone. It may be null when contact data is unavailable. Handle it as personal data.
TrainingMonthTotals Athlete activity totals for the training’s local calendar month, including this training. It may be null if the monthly aggregate is unavailable.
LifetimeTotals Athlete activity totals across all time, including this training. It may be null if the aggregate is unavailable.
AchievedGoals Goals reached by this training. It is an empty array when none are reported. Each item has ChallengeId, ChallengeName, GoalStep, and optional BadgeId and BadgeName. Reaching a goal does not guarantee that its badge has already been awarded.

Both totals use the same metrics: Trainings, Points, Calories, DurationSecs, Distance (meters), TargetZoneTimeSecs, HitsACount, HitsPoints, and ClubPoints. They cover the athlete’s activity across clubs, not just activity in the receiving club. These are creation-time snapshots, not values refreshed at delivery. A training uploaded late may therefore have TrainingMonthTotals for an earlier month. For current engagement results, call GET /Athletes/{userId}/EngagementSummary.

For this event, eventTime is the training Begin instant. It is not the time at which the webhook was delivered and may be substantially earlier when a workout is uploaded later.

Use data.TrainingId with GET /Trainings/{trainingId} when the current API representation is required. Do not use the envelope id as the training identifier.

  1. Deduplicate by envelope id.
  2. Upsert by data.TrainingId.
  3. Associate the workout with data.UserId and the club event stream. Treat data.ClubId as the location context where it was performed, not ownership.
  4. Parse metrics according to their documented units and tolerate additional properties.
  5. If a complete or current representation is required, call GET /Trainings/{trainingId} after acknowledging the webhook.

There is currently no Training.Updated or Training.Deleted event in the public filter list. Use paginated reconciliation to recover changes not represented by Training.Created.