Skip to content

Data model

The Club API exposes the Uptivo entities needed for club-management integrations. Every request is scoped to the club selected by the Club API Key.

The examples below are representative, anonymized responses. They deliberately show only the fields that are useful for understanding each entity. Properties may be omitted when they are not requested, do not apply, or are configured to be excluded when their value is null. Use the API reference as the authoritative source for complete schemas, enum values, validation limits, and nullability.

The examples reproduce the public API’s PascalCase property names exactly.

A Club is the scope of every Club API operation. The Club API Key determines which club is selected; callers do not pass a club ID to switch scope.

GET /Profile returns the selected club:

{
"ClubId": 100001,
"BrandId": 200001,
"ClubCode": "EXAMPLE",
"Name": "Example Fitness Club",
"PictureUri": "https://cdn.example.test/clubs/example/profile.png",
"Address": "1 Example Street\nMilan\nItaly",
"Latitude": 45.4642,
"Longitude": 9.19,
"Phone": "+390200000000",
"Email": "club@example.test",
"WebSiteUri": "https://club.example.test",
"CountryCode": "IT",
"TimeZoneCode": "Europe/Rome",
"FirstDayOfWeek": "Monday",
"DateFormat": "ddmmyyyy",
"TimeFormat": "h24",
"UnitsSystem": "Metric",
"Language": "Italian",
"DefaultCurrency": "EUR"
}

Use ClubId as the stable Uptivo identifier and verify it before performing write operations. TimeZoneCode, DateFormat, TimeFormat, and UnitsSystem describe club settings; they do not change the ISO 8601 representation used by API timestamps. Latitude and Longitude are either both populated or both null. The profile always contains every ClubProfileDTO property; optional values are serialized as null.

A User is a person with an Uptivo account. A user may belong to one, multiple, or no clubs. The Club API cannot access users globally.

An Athlete is a user associated with the selected club. The same UserId identifies the person in athlete, training, subscription, and participation responses within the public API.

An existing user can be invited to join a club by email. A user that does not exist can instead be created and immediately associated with the club. The Club API operates only on the resulting Athlete relationship; removing an athlete from a club does not delete the global Uptivo user.

Relationship between users, athletes, and clubs

Representative ClubAthleteDTO response:

{
"UserId": 300001,
"Email": "athlete@example.test",
"FirstMidName": "Alex",
"LastName": "Example",
"Nickname": null,
"Phone": null,
"Gender": "Unspecified",
"Weight": 70,
"Height": 180,
"IsDemo": false,
"JoinMode": "System",
"IsGuest": false,
"CreatedAt": "2026-01-15T09:30:00+01:00",
"QualifiedUtc": null,
"ProspectUtc": null,
"ClientUtc": "2026-01-20T10:00:00Z",
"ClientStage": "Client",
"TaxId": null,
"BirthDate": "1990-06-15"
}

Age is returned only for demo athletes, while BirthDate is omitted for demo athletes. IsGuest and ClientStage describe this club’s Athlete relationship, not the global User. ClientStage is Lead, Qualified, Prospect, or Client. The corresponding UTC milestone is retained once the Athlete first reaches Qualified, Prospect, or Client. See the Athletes guide for the complete workflow.

A Contact is a non-demo Uptivo user associated with the selected club without an Athlete membership there. It has the same global UserId if it later becomes an Athlete, but its club relationship is separate. Contact access does not expose training, telemetry, subscriptions, or engagement data.

Representative ClubContactDTO response:

{
"ClubId": 100001,
"UserId": 300001,
"Email": "contact@example.test",
"FirstMidName": "Alex",
"LastName": "Example",
"Nickname": null,
"Phone": "+390200000001",
"CreatedAt": "2026-02-10T09:00:00+01:00",
"JoinedAt": null,
"ClientStage": "Lead"
}

CreatedAt is when the Contact relationship began. JoinedAt may contain the original joining date when this person was previously an Athlete. ClientStage is specific to the club, may be unassigned, and can be set through a dedicated Contact operation without converting the user to an Athlete. The Contacts guide explains lookups and reconciliation.

A Training represents one athlete workout. A workout may have been recorded at the club or outside it, depending on its origin and ClubId. The API can return trainings with or without raw telemetry.

Representative partial ClubTrainingDTO response:

{
"TrainingId": 400001,
"UserId": 300001,
"ClubId": 100001,
"GroupTrainingId": null,
"IsSubTraining": false,
"IsLive": false,
"Title": "Indoor cycling",
"TrainingType": "IndoorCycling",
"Begin": "2026-02-10T17:00:00Z",
"BeginDateLocal": "2026-02-10",
"End": "2026-02-10T17:45:00Z",
"Duration": "0.00:45:00.000",
"MinBpm": 82,
"MaxBpm": 176,
"AvgBpm": 142,
"TargetZoneLowBpm": 130,
"TargetZoneHighBpm": 160,
"TargetZoneTime": "0.00:27:30.000",
"Points": 245,
"CaloriesTotal": 410,
"Distance": 18750,
"AvgPower": 165,
"MaxPower": 420,
"AvgCadence": 84
}

Begin and End are ISO 8601 timestamps. BeginDateLocal is a calendar date in the athlete’s timezone (YYYY-MM-DD), which can differ from the UTC date of Begin. Duration and heart-rate/power-zone times use the .NET duration format shown above, not an ISO timestamp. Every Training operation returns this same flat representation. withTelemetry=true adds an optional Telemetry object containing HeartBeats, GeoPositions, Powers, Cadences, and Hits; withUser=true independently adds the current ClubAthleteDTO as User. See the Trainings guide for retrieval and synchronization.

Telemetry is the raw time series associated with an athlete’s activity. The available series are heart rate, geolocation, power, cadence, and HIT data. Each series is represented as compact numeric arrays whose first value is a Unix timestamp in milliseconds.

Telemetry can be large. Request it only when the integration needs raw samples, and keep time ranges as narrow as possible. Prefer normal training responses when aggregate values are sufficient. The Telemetry guide defines every public tuple position and its unit.

A Subscription is a commercial definition owned by the club. It describes a membership or activity package; it is not an athlete’s purchased or assigned instance.

Representative SubscriptionForListDTO response:

{
"ClassSubscriptionId": 500001,
"Name": "Monthly classes",
"ShortDescription": "Eight classes over 30 days",
"MaxWeeklyBookings": 3,
"MaxMonthlyBookings": 8,
"AutoAssign": false,
"LongDescription": "Access to eligible on-site classes.",
"PublishState": "Published",
"Type": "Membership",
"Plans": [
{
"UnitMultiplier": 100,
"ClassSubscriptionPlanId": 510001,
"DurationDays": 30,
"MaxActivities": 8,
"Amount": 12000,
"Currency": "eur",
"Interval": "None",
"IntervalCount": 0,
"Iterations": 0
}
]
}

LongDescription and Plans are included only when their corresponding query options are enabled. PublishState may be omitted when the request already filters by that value. Type identifies the catalog entry as Other, Trial, or Membership. Monetary Amount uses the currency’s smallest unit; divide it by UnitMultiplier for the major-unit value. In the example, 12000 / 100 is EUR 120.00. A MaxActivities value of 0 means unlimited activities. See Subscriptions for catalog filtering and plan interpretation, then User subscriptions for assignment workflows.

A UserSubscription associates an Athlete with a Subscription for a defined period. It is the athlete-specific entitlement used when eligibility and remaining activities are evaluated.

Relationship between athletes and subscriptions

Representative UserClassSubscriptionDTO response:

{
"UserClassSubscriptionId": 600001,
"ClassSubscriptionId": 500001,
"UserId": 300001,
"From": "2026-02-01T00:00:00+01:00",
"To": "2026-03-03T00:00:00+01:00",
"DurationDays": 30,
"MaxActivities": 8,
"AvailableActivities": 5,
"ClassSubscriptionPlanId": 510001,
"SuspendedAtUTC": null,
"ReactivationDate": null,
"Interval": "None",
"IntervalCount": 0,
"PaymentAccount": null,
"ExtSubscriptionId": null,
"ExtStatus": null,
"Disabled": false,
"ExtInvoiceId": null,
"DueDateUTC": null,
"IsSuspended": false,
"SuspendedDays": 0
}

AvailableActivities is the current remaining allowance and cannot exceed MaxActivities; 0 for MaxActivities means unlimited. A deleted source plan can leave ClassSubscriptionPlanId as null. IsSuspended and SuspendedDays are calculated response fields. The active endpoint applies the server’s current active-subscription rules; do not reproduce those rules by checking only From and To locally. The User subscriptions guide defines the complete active predicate and synchronization strategy.

ClubAthleteMembershipSummaryDTO describes an Athlete’s effective membership in the selected club at CalculatedAtUtc. Status is None, Active, Paused, Pending, Expired, or Canceled. It is derived from all club assignments, not from a single representative Subscription.

Memberships contains the assignment IDs, Subscription name, dates, ticket balances, and suspension information, including disabled and exhausted assignments. Its suspension field is SuspendedAtUtc; use this exact casing when mapping the summary. ActiveFrom, ActiveUntil, NextPendingStart, and MostRecentEnd describe assignment boundaries, not state-transition dates.

Individual and bulk reads return this same representation. See Read effective membership states for precedence, empty assignments, and reconciliation.

A Class is one scheduled club activity, such as a lesson, course occurrence, personal-training session, or service appointment. The public calendar returns ClubActivityForCalendarDTO objects.

Representative response from a calendar endpoint:

{
"ClassId": 700001,
"Name": "Evening yoga",
"Description": "A guided 45-minute session.",
"Begin": "2026-02-12T18:30:00+01:00",
"End": "2026-02-12T19:15:00+01:00",
"ActivityType": "Yoga",
"Color": "#54e5cd",
"PictureUri": null,
"TrainerId": 800001,
"TrainerName": "Example Trainer",
"TrainerPictureUri": null,
"CreditsCostLocal": 2,
"CreditsCostRemote": 1,
"TicketsCostLocal": 1,
"TicketsCostRemote": 1,
"MaxLocalParticipants": 12,
"MaxRemoteParticipants": 20,
"LocalSubscriptionIds": [500001],
"RemoteSubscriptionIds": [500001],
"ParticipantUserIds": [300001]
}

Description, eligible subscription ID arrays, and participant IDs are conditional fields controlled by the calendar request options. If an option is not enabled, the related property can be omitted. Begin and End include the applicable UTC offset and should be treated as complete instants.

GET /Classes/{classId} returns the same public representation for one published Class. Its Description is populated; subscription and participant ID arrays are not expanded.

A ClassParticipant is the association between an Athlete and a Class. It records how the athlete attends, whether the athlete has a confirmed place or is queued, and how participation was booked.

Relationship between athletes and classes

GET /Classes/{classId}/Participants returns a complete, non-paginated array of ClubClassParticipationDTO objects. The same item representation is used by the individual and paginated booking reads:

{
"ClubId": 100001,
"ClassId": 700001,
"ClassName": "Evening yoga",
"ClassBegin": "2026-02-12T18:30:00+01:00",
"UserId": 300001,
"Mode": "InSite",
"State": "Participant",
"CreatedAtUtc": "2026-02-01T14:05:00Z",
"CreditsCost": 0,
"ClassSubscriptionId": 500001,
"NoShow": false,
"Trial": false,
"BookActorId": 800001,
"BookActorName": "Example Trainer"
}

Mode is InSite or Remote; State is Participant or InQueue. Subscription properties are nullable because participation does not always consume a subscription. BookActorId and BookActorName are retained for existing clients and omitted when no booking actor is available.

Adding or removing a participant returns ClassParticipantOpResultDTO, a different operation-result schema. Consult the API reference for that response and Errors for the domain conflicts that can prevent a booking.

GET /Classes/{classId}/Participants/{userId}, the complete participant array, GET /Classes/Participants/Recent, and the three /Bookings operations all return ClubClassParticipationDTO. It includes the Class interval, calendar and activity types, location, trainer, costs, and associated UserSubscription information. Nullable subscription properties are null when the booking is free, credit-only, or its assignment is unavailable. CreditsCost and SubscriptionCost describe the booking; they are not signed transaction amounts.

GET /Athletes/{userId}/AttendanceSummary returns ClubAttendanceSummaryDTO: lifetime first/last check-in and total count, plus counts for the last days elapsed UTC days and the days days before them (default 30). Check-ins require confirmed NoShow=false bookings whose Classes have started. Dates use Class Begin and reflect current saved booking flags; there is no arbitrary Class date filter.

The bulk summary operations return these same engagement and attendance DTOs for every current, non-demo Athlete. They include explicit zero rows so absence from the result is not used to infer inactivity.

A Challenge defines a time-bounded activity goal or ranking owned by a club or brand. Its public identifier is TrainingChallengeId. ClubChallengeDTO contains its interval, display content, ranking criterion, Training origin, assignment mode, eligibility, and award-policy settings.

A Challenge result associates the Challenge with an Athlete through UserId. TrainingChallengeRankingDTO contains the Athlete’s score, rank, percentage, Training totals, display data, and optional badge image. Result lists are paginated by UserId, not rank. Rank, RankPrc, and Participants remain relative to all scored participants in the Challenge, including eligible participants from other clubs of the same brand.

Ranks are live calculations rather than saved award records. Use Badge awards for award history and Badge.Awarded for notifications. See Challenges and results for visibility, pagination, and synchronization rules.

ClubBadgeAwardDTO identifies one challenge badge award through AchievedBadgeId. BadgeId identifies the design; repeated awards of that design have different award IDs. AchievedAt is the effective award date, not the list ordering position. Id is the equivalent string badge-<AchievedBadgeId>.

Club-wide, Athlete-specific, and individual reads use this same DTO. Optional challenge, goal, and ranking context may be null. The Badge.Awarded event also supplies TrainingChallengeId and AwardType, which are not in the read response. See Badge awards for visibility and reconciliation.