Training events
Uptivo currently publishes one training event type.
Training.Created
Section titled “Training.Created”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.
Recommended consumer flow
Section titled “Recommended consumer flow”- Deduplicate by envelope
id. - Upsert by
data.TrainingId. - Associate the workout with
data.UserIdand the club event stream. Treatdata.ClubIdas the location context where it was performed, not ownership. - Parse metrics according to their documented units and tolerate additional properties.
- 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.