curl -X GET "https://api.fitsociety.io/public/v1/workout/clients/{clientId}/programme-day" \
-H "Authorization: Bearer <access_token>"const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.fitsociety.io/public/v1/workout/clients/{clientId}/programme-day', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.fitsociety.io/public/v1/workout/clients/{clientId}/programme-day"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text){
"data": {
"date": "2026-09-22",
"month": "2026-09",
"dayLabel": "Tue",
"dayName": "Tuesday",
"dayOfMonth": 22,
"isToday": true,
"programmeMonthCalendar": {
"month": "2026-09",
"monthLabel": "September 2026",
"monthStart": "2026-09-01",
"monthEnd": "2026-09-30",
"gridStart": "2026-08-31",
"gridEnd": "2026-10-04",
"planIds": [
"67f1234567890abcdef1234"
],
"dates": [
{
"date": "2026-09-22",
"dayOfMonth": 22,
"weekday": 2,
"isCurrentMonth": true,
"isToday": true,
"isRestDay": false,
"itemCount": 3,
"statuses": [
"completed",
"in_process",
"not_started"
]
}
]
},
"programmes": [
{
"planId": "67f1234567890abcdef1234",
"name": "Weekly Strength Program",
"thumbnail": "https://cdn.example.com/plan.jpg",
"status": "Active",
"weekNumber": 4,
"weekStartDate": "2026-09-21",
"weekEndDate": "2026-09-27",
"isWeekAvailable": true,
"planWeeks": [
{
"weekNumber": 1,
"startDate": "2026-09-14",
"endDate": "2026-09-20",
"isSkipWeek": false,
"isCurrentWeek": true
}
],
"day": {
"date": "2026-09-22",
"weekday": 2,
"dayNumber": 4,
"isRestDay": false,
"itemCount": 3,
"items": [
{
"_id": "67f1234567890abcdef1234",
"type": "workout",
"order": 1,
"startTime": "",
"plannedDurationMinutes": 60,
"status": "completed",
"name": "Upper Body",
"description": "",
"activityType": "running",
"targetDistanceMeters": 5000,
"planMomentId": "67f1234567890abcdef1234",
"workout": {
"planMomentId": "67f1234567890abcdef1234",
"name": "Upper Body",
"description": "",
"exerciseCount": 6,
"exercises": [
{
"_id": "67f1234567890abcdef1234",
"exerciseId": "67f1234567890abcdef1234",
"exerciseName": "Incline Dumbbell Press",
"thumbnail": "https://cdn.example.com/ex.jpg",
"primaryMuscle": "Chest",
"equipment": [
"string"
],
"sets": 4,
"minReps": 8,
"maxReps": 12,
"rest": 90,
"intensity": "Medium",
"difficulty": "Intermediate",
"notes": "",
"isFavourite": false
}
],
"progress": {
"total": 6,
"completed": 6,
"progressPercentage": 100,
"isCompleted": true
},
"sessionId": "67f1234567890abcdef1234",
"sessionStatus": "completed",
"isCompleted": true,
"scoring": {
"scoringType": "forTime",
"descriptionOnly": true,
"acceptsManualResult": true,
"targetValue": null,
"timeDomain": {
"windowSeconds": null,
"timeCapSeconds": 900,
"rounds": 3,
"intervalSeconds": null,
"intervalCount": null,
"workSeconds": null,
"restSeconds": null
},
"scoreValidation": {
"timeCapSeconds": 900,
"maxReps": null,
"expectedIntervals": null
},
"result": {
"roundsCompleted": 5,
"repsPerRound": 30,
"extraReps": 12,
"totalReps": 162,
"intervalReps": [
12,
11,
10
],
"elapsedSeconds": 742,
"finishedBeforeCap": true,
"timeCapSeconds": 900,
"maxLoadKg": 120
}
}
},
"activity": {
"performanceId": "67f1234567890abcdef1234",
"status": "in_progress",
"startedAt": "2026-04-12T10:00:00.000Z",
"completedAt": "2026-04-12T10:00:00.000Z",
"actualDurationMinutes": 32,
"actualDistanceMeters": 5100,
"rpe": 7,
"notes": ""
}
}
]
}
}
]
},
"meta": {
"requestId": "4f849d7d-f4f1-45cc-b4b7-3984a3d17f83",
"rateLimit": {
"limit": 10,
"remaining": 9,
"resetSeconds": 1
}
}
}{
"error": {
"code": 400,
"key": "request.invalid",
"message": "The request is invalid."
},
"meta": {
"requestId": "4f849d7d-f4f1-45cc-b4b7-3984a3d17f83",
"rateLimit": {
"limit": 10,
"remaining": 9,
"resetSeconds": 1
}
}
}{
"error": {
"code": 403,
"key": "scopes.insufficient",
"message": "The access token does not include the required scope.",
"details": {
"requiredScopes": [
"required:scope"
]
}
},
"meta": {
"requestId": "4f849d7d-f4f1-45cc-b4b7-3984a3d17f83",
"rateLimit": {
"limit": 10,
"remaining": 9,
"resetSeconds": 1
}
}
}{
"error": {
"code": 500,
"key": "server.internal_error",
"message": "An unexpected Public API server error occurred."
},
"meta": {
"requestId": "4f849d7d-f4f1-45cc-b4b7-3984a3d17f83",
"rateLimit": {
"limit": 10,
"remaining": 9,
"resetSeconds": 1
}
}
}Get every programme's scheduled work for one date
Everything the authenticated client’s multi-week calendar programmes have scheduled on ONE date, plus the month dot grid that sits above the list.
programmes[] is a LIST because a client can be on several programmes at once — one entry per programme that actually has something on that date. A programme is OMITTED when it has nothing there (the date falls outside its span, or its calendar authors no day for that weekday), so programmes.length is the number of cards to render. A REST day is kept and flagged day.isRestDay, since an empty rest card is still meaningful.
Each day.items[] is produced by the same helper GET /app/v1/workout/plans/client/template-with-progress/{templateId} uses, so the item shape is identical between the two endpoints — including the nested workout summary with its exercises, and activity carrying what was logged.
programmeMonthCalendar is the same shape and helper the training page returns, for the month containing date, so the calendar needs no second request.
Switched-off (Inactive) programmes are INCLUDED, matching the month calendar this screen is opened from: a date that showed a dot there always resolves to a card here. Each entry carries status and isActive so the client can badge or blur a paused programme rather than the server hiding it. Draft plans are never returned.
Scoped to mode: "multi_week" + layout: "calendar_week": a day’s items need per-day dates and a schedule that authors them, and only that combination has both. date omitted → today in the company’s timezone.
Requires the workout_calendar:read scope. This operation maps to /app/v1/workout/client/programme-day and retains its Workout V2 permission, feature-flag, and resource-scope checks.
The clientId path parameter identifies the client represented by the request context.
curl -X GET "https://api.fitsociety.io/public/v1/workout/clients/{clientId}/programme-day" \
-H "Authorization: Bearer <access_token>"const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.fitsociety.io/public/v1/workout/clients/{clientId}/programme-day', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.fitsociety.io/public/v1/workout/clients/{clientId}/programme-day"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text){
"data": {
"date": "2026-09-22",
"month": "2026-09",
"dayLabel": "Tue",
"dayName": "Tuesday",
"dayOfMonth": 22,
"isToday": true,
"programmeMonthCalendar": {
"month": "2026-09",
"monthLabel": "September 2026",
"monthStart": "2026-09-01",
"monthEnd": "2026-09-30",
"gridStart": "2026-08-31",
"gridEnd": "2026-10-04",
"planIds": [
"67f1234567890abcdef1234"
],
"dates": [
{
"date": "2026-09-22",
"dayOfMonth": 22,
"weekday": 2,
"isCurrentMonth": true,
"isToday": true,
"isRestDay": false,
"itemCount": 3,
"statuses": [
"completed",
"in_process",
"not_started"
]
}
]
},
"programmes": [
{
"planId": "67f1234567890abcdef1234",
"name": "Weekly Strength Program",
"thumbnail": "https://cdn.example.com/plan.jpg",
"status": "Active",
"weekNumber": 4,
"weekStartDate": "2026-09-21",
"weekEndDate": "2026-09-27",
"isWeekAvailable": true,
"planWeeks": [
{
"weekNumber": 1,
"startDate": "2026-09-14",
"endDate": "2026-09-20",
"isSkipWeek": false,
"isCurrentWeek": true
}
],
"day": {
"date": "2026-09-22",
"weekday": 2,
"dayNumber": 4,
"isRestDay": false,
"itemCount": 3,
"items": [
{
"_id": "67f1234567890abcdef1234",
"type": "workout",
"order": 1,
"startTime": "",
"plannedDurationMinutes": 60,
"status": "completed",
"name": "Upper Body",
"description": "",
"activityType": "running",
"targetDistanceMeters": 5000,
"planMomentId": "67f1234567890abcdef1234",
"workout": {
"planMomentId": "67f1234567890abcdef1234",
"name": "Upper Body",
"description": "",
"exerciseCount": 6,
"exercises": [
{
"_id": "67f1234567890abcdef1234",
"exerciseId": "67f1234567890abcdef1234",
"exerciseName": "Incline Dumbbell Press",
"thumbnail": "https://cdn.example.com/ex.jpg",
"primaryMuscle": "Chest",
"equipment": [
"string"
],
"sets": 4,
"minReps": 8,
"maxReps": 12,
"rest": 90,
"intensity": "Medium",
"difficulty": "Intermediate",
"notes": "",
"isFavourite": false
}
],
"progress": {
"total": 6,
"completed": 6,
"progressPercentage": 100,
"isCompleted": true
},
"sessionId": "67f1234567890abcdef1234",
"sessionStatus": "completed",
"isCompleted": true,
"scoring": {
"scoringType": "forTime",
"descriptionOnly": true,
"acceptsManualResult": true,
"targetValue": null,
"timeDomain": {
"windowSeconds": null,
"timeCapSeconds": 900,
"rounds": 3,
"intervalSeconds": null,
"intervalCount": null,
"workSeconds": null,
"restSeconds": null
},
"scoreValidation": {
"timeCapSeconds": 900,
"maxReps": null,
"expectedIntervals": null
},
"result": {
"roundsCompleted": 5,
"repsPerRound": 30,
"extraReps": 12,
"totalReps": 162,
"intervalReps": [
12,
11,
10
],
"elapsedSeconds": 742,
"finishedBeforeCap": true,
"timeCapSeconds": 900,
"maxLoadKg": 120
}
}
},
"activity": {
"performanceId": "67f1234567890abcdef1234",
"status": "in_progress",
"startedAt": "2026-04-12T10:00:00.000Z",
"completedAt": "2026-04-12T10:00:00.000Z",
"actualDurationMinutes": 32,
"actualDistanceMeters": 5100,
"rpe": 7,
"notes": ""
}
}
]
}
}
]
},
"meta": {
"requestId": "4f849d7d-f4f1-45cc-b4b7-3984a3d17f83",
"rateLimit": {
"limit": 10,
"remaining": 9,
"resetSeconds": 1
}
}
}{
"error": {
"code": 400,
"key": "request.invalid",
"message": "The request is invalid."
},
"meta": {
"requestId": "4f849d7d-f4f1-45cc-b4b7-3984a3d17f83",
"rateLimit": {
"limit": 10,
"remaining": 9,
"resetSeconds": 1
}
}
}{
"error": {
"code": 403,
"key": "scopes.insufficient",
"message": "The access token does not include the required scope.",
"details": {
"requiredScopes": [
"required:scope"
]
}
},
"meta": {
"requestId": "4f849d7d-f4f1-45cc-b4b7-3984a3d17f83",
"rateLimit": {
"limit": 10,
"remaining": 9,
"resetSeconds": 1
}
}
}{
"error": {
"code": 500,
"key": "server.internal_error",
"message": "An unexpected Public API server error occurred."
},
"meta": {
"requestId": "4f849d7d-f4f1-45cc-b4b7-3984a3d17f83",
"rateLimit": {
"limit": 10,
"remaining": 9,
"resetSeconds": 1
}
}
}Authorizations
Public API access token issued by /public/v1/oauth/token. Example: Authorization: Bearer fspt_.... Each resource request rechecks the token company's current provider access. Disabling access blocks existing tokens with 403 auth.provider_unavailable.
Path Parameters
Client in the company bound to the Public API token.
^[a-fA-F0-9]{24}$Query Parameters
The day to load, canonical YYYY-MM-DD. Omit for today in the company's timezone.
^\d{4}-\d{2}-\d{2}$"2026-09-22"