Progress
Completed workouts
The workouts your clients finished, with every exercise's sets and the personal records they set.
A workout a client finished and logged, with each exercise's sets and any personal records it set. To compare clients' workouts over a period, use GET /client-summaries with include=workouts.

Attributes
- idstring
Its unique ID.
- clientobject
- namestring
The workout's name.
- completedAttimestamp
How long the client's workout timer ran.
nullif it wasn't timed.How the client rated the workout, from 1 (okay) to 5 (amazing).
nullif they didn't rate it.- notestring
The client's note on the workout. Empty if none.
- newPersonalRecordCountinteger
How many personal records the workout set.
- totalsobject
- weightUnitenum
The unit of every weight here, which is the client's unit setting. Weights aren't converted, the way amounts come with their currency. HubFit doesn't record the unit each workout was logged in, so a client who changed their setting may have older workouts logged in the other unit.
Known valueskglb - sectionsarray of objects
The sections the coach grouped exercises into, such as a warm-up or a circuit. Exercises outside a section aren't in one.
Show 7 child attributesHide child attributes
- idstring
What each of the section's exercises has as
sectionId. - namestring
- typeenum
New section types can appear.
Known valuesregularcircuitamrapinterval The rounds the coach set for a circuit or interval section.
nullfor other sections.The rounds the client finished in a circuit, interval or AMRAP section.
nullfor regular sections.The time the coach set for an AMRAP section.
nullfor other sections.How long the client took over a circuit, interval or AMRAP section.
nullfor regular sections or when it wasn't timed.
- exercisesarray of objects
Every exercise in the order of the workout, each pointing at its section, if any.
Show 8 child attributesHide child attributes
The same for every time the client logged this exercise, so it tells you which entries across workouts are the same exercise.
nullwhen HubFit has no shared id for it.- namestring
The
idof the section the exercise is in, ornullif it isn't in one.Shared by the exercises done together as a superset, or
nullwhen the exercise wasn't part of one.- isAlternativeboolean
Whether the client swapped in this exercise as an alternative to the planned one.
- notestring
The client's note on the exercise. Empty if none.
- setsarray of objects
One set, with a value for each thing the exercise tracks, or
nullwhen the client left it blank.weightis inweightUnitanddurationSecondsin seconds; other values are as the client entered them. - newPersonalRecordsarray of objects
The personal records the client set on this exercise in this workout. The first time a client logs an exercise sets none; records start from the next time.
Show 3 child attributesHide child attributes
- typeenum
max_weightfor the heaviest set,max_volumefor the most weight times reps added up over the exercise's sets in one workout,estimated_one_rep_maxfor the one-rep max HubFit estimates from a set's weight and reps (the Epley formula). New record types can appear.Known valuesmax_weightmax_volumeestimated_one_rep_max - valuenumber
The new record, in
weightUnit. - improvementPercentnumber
How much it beat the previous record by, as a percentage. 100 when the previous record was 0, such as when earlier sessions had no weight entered (HubFit doesn't keep the previous value, so this can't be told apart from doubling it).
{
"id": "6ad6af97b154fb96b1536899",
"client": {
"id": "6ad6af41d3199442d31b2743",
"name": "Jordan Miller"
},
"name": "Upper body A",
"completedAt": "2026-10-26T14:32:05.000Z",
"durationSeconds": 3120,
"rating": 5,
"note": "Felt strong. Added 5 lb on bench.",
"newPersonalRecordCount": 1,
"totals": {
"setCount": 18,
"reps": 142,
"volume": 18450
},
"weightUnit": "lb",
"sections": [
{
"id": "6ad6af11f9669110f964fe0f",
"name": "Main lifts",
"type": "regular",
"targetRounds": 3,
"completedRounds": 3,
"timeCapSeconds": null,
"durationSeconds": 3120
}
],
"exercises": [
{
"exerciseId": "6ad6afb311a359b211a1c6b1",
"name": "Barbell bench press",
"sectionId": null,
"supersetId": null,
"isAlternative": false,
"note": "",
"sets": [
{
"reps": 8,
"weight": 185,
"rpe": 8
}
],
"newPersonalRecords": [
{
"type": "max_weight",
"value": 182.4,
"improvementPercent": 4.2
}
]
}
]
}https://api.hubfit.com/v1/completed-workoutsWorkouts your clients logged, most recently completed first, without their exercises. Across every client you can reach (team members with the Standard role only see their assigned clients), or one client's with clientId. To pick up new workouts, pass the day before the newest one you've seen as startDate and skip ones you've seen. Workouts are ordered by when the client's app says they finished, so one can arrive after a workout that finished later. Requires clients:read.
Query parameters
- clientIdstring
Only this client's workouts.
- startDatedate
Only workouts from this day, included, as
YYYY-MM-DD, in your own calendar (the timezone in your HubFit settings), as the app shows workouts to you. - endDatedate
Only workouts up to this day, included, as
YYYY-MM-DD, in your own calendar. - limitinteger
How many results to return, from 1 to 100.
Default25 - cursorstring
The
nextCursorfrom the previous page.
Returns
A page of completed workouts.
curl -G https://api.hubfit.com/v1/completed-workouts \
-H "Authorization: Bearer $HUBFIT_API_KEY" \
-d clientId=6ad6af41d3199442d31b2743 \
-d startDate=2026-10-20const response = await fetch("https://api.hubfit.com/v1/completed-workouts?clientId=6ad6af41d3199442d31b2743&startDate=2026-10-20", {
headers: {
Authorization: `Bearer ${process.env.HUBFIT_API_KEY}`,
},
});
const { data, nextCursor } = await response.json();import os
import requests
response = requests.get(
"https://api.hubfit.com/v1/completed-workouts",
headers={"Authorization": f"Bearer {os.environ['HUBFIT_API_KEY']}"},
params={
"clientId": "6ad6af41d3199442d31b2743",
"startDate": "2026-10-20",
},
)
page = response.json()
data, next_cursor = page["data"], page["nextCursor"]{
"data": [
{
"id": "6ad6af97b154fb96b1536899",
"client": {
"id": "6ad6af41d3199442d31b2743",
"name": "Jordan Miller"
},
"name": "Upper body A",
"completedAt": "2026-10-26T14:32:05.000Z",
"durationSeconds": 3120,
"rating": 5,
"note": "Felt strong. Added 5 lb on bench.",
"newPersonalRecordCount": 1,
"totals": {
"setCount": 18,
"reps": 142,
"volume": 18450
},
"weightUnit": "lb"
}
],
"nextCursor": "eyJpZCI6IjZhZDZhZjNmMjljNTk3ZjE1In0",
"totalCount": 48
}https://api.hubfit.com/v1/completed-workouts/{workoutId}One completed workout with every exercise in order, its sets as the client logged them and any personal records, plus the sections the coach grouped exercises into. Requires clients:read.
curl https://api.hubfit.com/v1/completed-workouts/6ad6af97b154fb96b1536899 \
-H "Authorization: Bearer $HUBFIT_API_KEY"const response = await fetch("https://api.hubfit.com/v1/completed-workouts/6ad6af97b154fb96b1536899", {
headers: {
Authorization: `Bearer ${process.env.HUBFIT_API_KEY}`,
},
});
const { data } = await response.json();import os
import requests
response = requests.get(
"https://api.hubfit.com/v1/completed-workouts/6ad6af97b154fb96b1536899",
headers={"Authorization": f"Bearer {os.environ['HUBFIT_API_KEY']}"},
)
data = response.json()["data"]{
"data": {
"id": "6ad6af97b154fb96b1536899",
"client": {
"id": "6ad6af41d3199442d31b2743",
"name": "Jordan Miller"
},
"name": "Upper body A",
"completedAt": "2026-10-26T14:32:05.000Z",
"durationSeconds": 3120,
"rating": 5,
"note": "Felt strong. Added 5 lb on bench.",
"newPersonalRecordCount": 1,
"totals": {
"setCount": 18,
"reps": 142,
"volume": 18450
},
"weightUnit": "lb",
"sections": [
{
"id": "6ad6af11f9669110f964fe0f",
"name": "Main lifts",
"type": "regular",
"targetRounds": 3,
"completedRounds": 3,
"timeCapSeconds": null,
"durationSeconds": 3120
}
],
"exercises": [
{
"exerciseId": "6ad6afb311a359b211a1c6b1",
"name": "Barbell bench press",
"sectionId": null,
"supersetId": null,
"isAlternative": false,
"note": "",
"sets": [
{
"reps": 8,
"weight": 185,
"rpe": 8
}
],
"newPersonalRecords": [
{
"type": "max_weight",
"value": 182.4,
"improvementPercent": 4.2
}
]
}
]
}
}Subscribe a webhook endpoint to hear about these as they happen, instead of polling. An event carries the record's id and its clientId, not the record: fetch it with your key. See Webhooks.
- completed_workout.createdA workout was completed.
