/v1/trainee, router traineeRouter in src/modules/trainee/trainee.routes.ts. Also /v1/trainee/notification-configs (notificationConfigsReadRouter) and /v1/trainee/notification-preferences (notificationPreferencesRouter) in src/modules/notification-configs/notification-configs.routes.ts.
Lane: trainee. Every endpoint needs a trainee token. The table shows which also use the app access guard (access) that returns 403 APP_LOCKED for a frozen or ended subscription. See Authentication.
Account
GET /v1/trainee/me
Returns the signed-in trainee, their studio and every studio the same phone number trains at. The app calls it on launch to refresh branding, subscription state and the lock flag.
Auth: trainee token.
string
ios or android. Saved as Client.lastCheckInPlatform when the check-in is stamped.Client.lastCheckInAt is updated at most once every 15 minutes (LAST_CHECK_IN_THROTTLE_MS). When it is updated, open automatic INACTIVE inbox items for the trainee are marked DONE and a ClientAppDay row is upserted for today in the trainee’s time zone. The write is fire and forget and never fails the request.
Response: 200.
client and studio objects are the same views returned by sign-in. Field notes are on Trainee sign-in. studio.branding is the studio’s stored branding JSON with the Instagram handle normalized. mbpEnabled, mbpAnchors and mbpUnitLabel describe the studio’s portion system and are read from Studio.settings. The numbers above are placeholders.
Errors:
DELETE /v1/trainee/me
Deletes the trainee’s account from inside the app. This is the store-mandated account deletion.
Auth: trainee token. Works for a locked account. Refused for preview tokens.
repo.deleteTraineeAccount runs one transaction that:
- deletes the trainee’s progress photos, technique videos, health samples, meal logs, nutrition day logs, favorite meals, shopping list, form responses, form assignments, inbox items, push tokens and WhatsApp messages,
- detaches calendar events (
clientIdset tonull), - anonymizes the
Clientrow:deletedAtset,statusARCHIVED, the name replaced with a fixed Hebrew placeholder, and name parts, email, phone, avatar, goal, id number, birth date, age, gender, height, weight, tags and coach cleared.planFrozenOnis set andappAccessWhileFrozenisfalse.
externalUserId is kept only when it starts with autofit:, so a later AutoFit import still recognizes the row. Workout logs, weight entries and daily metrics are not in the delete list.
Response: 200.
POST /v1/trainee/me/avatar
Sets the trainee’s profile photo. Upload the image first with Trainee uploads, then send the returned URL here.
Auth: trainee token and app access.
string
required
A valid URL, at most 1000 characters.
{ client, studio }. Same views as GET /v1/trainee/me, without studios. The update query does not load subscriptions, so client.subscription.status is none in this response regardless of the real state. Refetch me if you need it.
Errors:
App release
GET /v1/trainee/app-release
Tells the app the newest version live in its store, so it can prompt for an update.
Auth: trainee token.
string
ios or android. Without it the response is all null.TRAINEE_APP_IOS_VERSION, TRAINEE_APP_IOS_STORE_URL, TRAINEE_APP_ANDROID_VERSION, TRAINEE_APP_ANDROID_STORE_URL. The version must match ^\d+(\.\d+){0,3}$ and the store URL must be non-empty, otherwise both fields are null, which turns the prompt off. The comparison with the installed version happens in the app.
Response: 200.
Push tokens
POST /v1/trainee/push-token
Registers the device’s push token for this trainee.
Auth: trainee token.
string
required
The device push token. 1 to 300 characters.
string
ios or android.TraineePushToken is (clientId, token). In one transaction the repository first deletes rows with the same token that belong to other clients, then upserts this client’s row. That is what stops a handed-over phone from receiving the previous user’s notifications.
After the upsert, notifyPendingForms runs for the trainee: forms that were assigned before the device could receive a push are announced now, and the FORM_SENT task hook fires for each one that became visible. A failure there is logged and does not fail the request.
Response: 200.
VALIDATION (422) when the body fails the schema.
DELETE /v1/trainee/push-token
Removes the device token on sign-out.
Auth: trainee token.
string
required
The token to remove. Sent in the JSON body of the
DELETE request.VALIDATION (422) when token is missing.
Home
GET /v1/trainee/home
Everything the home tab renders: progress rings, today’s workout card, the next meal, the studio banner, the WhatsApp contact, weekly counters and the movement requirement.
Auth: trainee token and app access.
string
1 to 128 characters. The nutrition plan the app currently shows as today’s. A hint: used when it matches one of the trainee’s active plans.
string
1 to 128 characters. The plan day the app currently shows as today’s. Used together with
planId. When the hint does not resolve, the server infers the day from today’s saved snapshot and then from the plan’s day rotation.string
ios or android. Used for the check-in stamp.- Check-in. Same throttled
lastCheckInAtstamp asGET /v1/trainee/me, skipped for preview tokens. - Today. The day window is computed in the trainee’s time zone.
- Nutrition. All active nutrition programs are loaded. If the newest one is a file plan (a PDF or link), nutrition is in file-plan mode: no macro rings, no next meal,
mealsTodayisnull. Otherwise the day is picked from the query hint or inferred, then summarized bysummarizePlanDay, which mirrors the app’s own math over the saved day snapshot: only the option the trainee has selected counts, trainee-set portions replace plan quantities, and excluded foods are replaced the same way Trainee nutrition serves them. Free-logged meals fromMealLogare added on top, except logs already linked to a snapshot meal. - Rings. With the portion system off, four macro rings in kcal and grams. With it on, the same four keys carry portion units and the label is the studio’s unit label. Then water in litres (goal from the plan day’s water target, else
Client.waterGoalMl) and steps (goal from the training plan’s requirement for the next workout day, elseClient.stepsGoal). - Workout. The newest active training program. For a regular plan the card is the next day in rotation: the day after the last performed one, by label.
completedistruewhen any completed workout log exists today. For a file plan the card opens the file andestimatedMinutesisnull. - Next meal. The first plan meal whose
timeis at or after the current local time and that is neither ticked off nor removed for today. If none is later, the first remaining meal.caloriesis kcal, or portion units rounded to quarters when the portion system is on.itemsholds up to 4 food names. - Banner. The studio’s published home banner, resolved by
resolveTraineeBanner. - WhatsApp.
coachWhatsappisnullwhen the studio setsettings.contactWhatsappEnabledtofalse.
array
Ordered list. Macro rings are omitted in nutrition file-plan mode, so the array then holds only
water and steps. Labels are Hebrew strings from the server.object | null
null when the trainee has no active training program. kind is regular or file. For regular, id is the plan day id. For file, id is the program id.object | null
The latest outbound
WhatsappMessage with a body. coachName is the studio name and unread is always false.object | null
May carry
target when the plan meal defines a target the trainee composes against.object | null
null when there is no published banner or it has no title. mediaKind is image, video, youtube or null. cta.kind is content, link or whatsapp, and cta is null when the banner has no action.object
completed counts distinct days with a completed log in the last 7 days. total is the number of days in the plan, or the coach’s workoutsPerWeek for a file plan, which can be null.object | null
null in nutrition file-plan mode.object | null
null when the training plan has no cardio or steps requirement switched on. mode is cardioOnly, stepsOnly, both or bothCompensated. cardio.scope is perWorkout or weekly. The same block is returned by GET /v1/trainee/workouts. See Plans and workouts.Notification settings
Push notification behaviour has two layers. The studio configures each notification type (on or off, texts, sound, send time). The trainee can then mute whole groups. Both layers are read by the app.GET /v1/trainee/notification-configs
Returns the studio’s notification configuration as it applies to this trainee. The app uses it for notifications it schedules on the device, such as workout reminders.
Auth: trainee token.
The service lists the studio’s effective config per type and sets enabled to false for every type whose group the trainee muted. The COACH_MESSAGES group can never be muted.
Response: 200. data is an array.
type is one of the values in notificationConfigType. The active set is REST_TIMER, WORKOUT_IDLE, WORKOUT_UNFINISHED, FORM_SENT, FORM_REMINDERS, TRAINING_PLAN_ASSIGNED, TRAINING_PLAN_UPDATED, NUTRITION_PLAN_ASSIGNED, NUTRITION_PLAN_UPDATED, SUBSCRIPTION_RENEWED, SUBSCRIPTION_FROZEN and TRAINER_MESSAGE. The texts above are placeholders. Real templates come from the defaults and the studio’s edits.
Errors: NOT_FOUND (404) trainee not found when the client is not in the token’s studio.
GET /v1/trainee/notification-preferences
Lists the notification groups the trainee can switch on and off.
Auth: trainee token.
A group is listed only when the studio has at least one enabled notification type in it. Groups come from NOTIFICATION_TYPE_GROUPS. For FORM_SENT and FORM_REMINDERS the group depends on each enabled message’s form type: CHECK_IN messages belong to CHECK_INS, others to FORMS, and a message for all form types belongs to both.
Response: 200.
string
CHECK_INS, FORMS, PLANS, WORKOUT_REMINDERS, COACH_MESSAGES or SUBSCRIPTION, in that order.boolean
true for COACH_MESSAGES. A locked group is always enabled.boolean
false when the group is in Client.mutedNotificationGroups.NOT_FOUND (404) trainee not found.
PATCH /v1/trainee/notification-preferences
Switches one group on or off.
Auth: trainee token. Refused for preview tokens.
string
required
One of the six group keys.
boolean
required
false adds the group to the trainee’s muted list. true removes it.isNotificationMuted, and the next GET /v1/trainee/notification-configs reflects it for device-local notifications.
Response: 200 with the same { groups } shape as the GET, after the change.
Errors: