Profile

First-run setup

post/profile/onboarding

Request

  • Base URL: https://bodylab.lol/api/v1
  • URL: https://bodylab.lol/api/v1/profile/onboarding
  • Auth: HTTP bearer

Headers

X-Client-Platformstring

The native client's platform, e.g. ios. Server-side and non-native callers omit it.

X-Client-Versionstring

The native client's own semver version. With X-Client-Platform, a version below that platform's minimum is refused with CLIENT_UPGRADE_REQUIRED (426).

Request body

displayNamestring nullable
timezonestring required
clockFormat'12h' | '24h'

12h or 24h. Not nullable: there is always a clock, and 12h is the default.

units'metric' | 'imperial' required

How to display quantities; the API always speaks SI.

sex'm' | 'f' nullable
birthYearinteger nullable
weightKgnumber nullable
heightCmnumber nullable
bloodPressureSystolicMmHginteger nullable

Millimetres of mercury. Send it with bloodPressureDiastolicMmHg, and the pair is recorded as a reading taken now. Null removes the most recent reading, and the profile falls back to the one before it.

bloodPressureDiastolicMmHginteger nullable

Millimetres of mercury.

hrMaxinteger nullable

Null clears an entered value back to estimated.

hrRestinteger nullable

Null clears an entered value.

lthrinteger nullable
ftpWinteger nullable
sportsstring[] required
strengthEquipment'gym' | 'dumbbells' | 'bodyweight'
trainingFocus'endurance' | 'strength' | 'strength_first'
leaveOutJumpsboolean nullable

True leaves jumps out of strength sessions. False puts them back, and so does null, which clears it to the default.

homeAltitudeMnumber nullable

Metres. Null clears an entered value back to the one observed from recordings.

strengthEquipmentItemsobject

Replaces the whole set. Sending it also re-derives strengthEquipment, so the two can never disagree.

windDownFromHourinteger nullable

The hour to be off screens by, on the athlete's clock. 18-23 or 0-2 — the wrap is deliberate, for a late finisher or a shift worker. Any other hour is refused by the handler against isWindDownHour (@bodylab/engine/sleep), which is where that rule lives so the contract and the database CHECK can't drift from it. Null clears it.

barKind'standard' | 'custom' | 'unknown'
barWeightKgnumber nullable

Kilograms. Send it with barKind 'custom'; any other kind clears it.

dailyUpdateMode'daily' | 'unusual_only' | 'off'

daily, unusual_only or off.

hiddenExposuresstring[]

Replaces the list of hidden Daily Update chips. An empty list brings them all back.

cycleTracking'auto' | 'off'

auto, or off for "I don't have periods".

clipWeightKgnumber

Kilograms, for one clip or collar. 2.5 is a competition collar and is the most any federation recognises; 0 is an ordinary gym's spring clips and is the default.

Response

OK

displayNamestring nullable required
timezonestring required

IANA time zone, e.g. America/Denver.

clockFormatstring required

How the athlete reads clock times: 12h ("6:26 AM", the default) or 24h ("06:26"). A display preference for the apps, in the athlete's time zone; every time the API sends is still an ISO instant or an HH:MM field, whatever this says. Known values: 12h, 24h. Treat unknown values as "other".

units'metric' | 'imperial' required

How to display quantities; the API always speaks SI.

sex'm' | 'f' nullable required
birthYearinteger nullable required
weightKgnumber nullable required
heightCmnumber nullable required
bloodPressureSystolicMmHginteger nullable required

The athlete's most recent blood pressure, upper number, in millimetres of mercury: the newest reading they have, whether their cuff synced it or they typed it in. Always set together with bloodPressureDiastolicMmHg, and always the two numbers of that one reading — they are stored in one row and a pair can't be assembled from two readings. Every reading is kept, not just this one. A measurement and nothing more: Body Lab attaches no category, threshold or judgement to it, and nothing it prescribes reads it.

bloodPressureDiastolicMmHginteger nullable required

The lower number of the same reading, millimetres of mercury. Null exactly when bloodPressureSystolicMmHg is.

hrMaxinteger nullable required
hrMaxSourcestring nullable required

Where a heart-rate anchor comes from: typed in, estimated from age, or observed in the athlete's own data (observed replaces estimated; entered is never overwritten). Known values: entered, estimated, observed. Treat unknown values as "other".

hrRestinteger nullable required
hrRestSourcestring nullable required

Where a heart-rate anchor comes from: typed in, estimated from age, or observed in the athlete's own data (observed replaces estimated; entered is never overwritten). Known values: entered, estimated, observed. Treat unknown values as "other".

lthrinteger nullable required

Lactate threshold heart rate, bpm.

ftpWinteger nullable required

Functional threshold power, watts.

ftpUpdatedAtstring date-time nullable required

An instant: ISO-8601 with offset, e.g. 2026-09-13T06:30:00Z.

sportsstring[] required

Sports the athlete does, most important first.

homeAltitudeMnumber nullable required

The altitude the athlete lives and usually trains at, metres. Watt targets are lowered only where today's altitude differs from the one their FTP was set at, so an athlete at altitude with an FTP from there sees no change.

homeAltitudeSourcestring nullable required

Where home altitude comes from: typed in (never overwritten), or observed from where the athlete's recorded runs and rides usually start (follows the recordings). Known values: entered, observed. Treat unknown values as "other".

strengthEquipmentItemsobject required

The kit the athlete's sessions are currently written for — whichever of their places is active, which is their home one unless they have switched. Each item maps to the heaviest single implement of it in kilograms, or null for "enough" (a rack needs no number). Absent keys are not owned. This is what strength sessions are written for; strengthEquipment above is the nearest of three old rungs, derived from this, and kept so a client that hasn't learned the set still gets a sensible answer. A ceiling is the heaviest one of a pair: an exercise taking two implements can load twice it.

windDownFromHourinteger nullable required

The hour on the athlete's own clock they chose to be off screens by, 18-23 or 0-2, or null for not set. A convention the athlete picked, never a target Body Lab derived: no published study supports a particular cutoff, and the one popularly quoted was tested as a behaviour and did not hold up. Nothing is measured against it but what the athlete reports, and nothing about it reaches a prescription.

strengthEquipmentstring required

What the athlete lifts with. Strength sessions name only exercises this allows: gym is a barbell and rack (the default), dumbbells is dumbbells or kettlebells, bodyweight is no weights. Known values: gym, dumbbells, bodyweight. Treat unknown values as "other".

trainingFocusstring required

What the athlete wants training to build, one of three options that train differently. endurance (Endurance first, the default): two heavy strength sessions a week, fitted around the rest of the training. strength (Strength and endurance equally): three strength sessions a week, never straight after an interval session and often first in the day, with interval sessions unchanged. strength_first (Strength first): three longer strength sessions with more sets of the main lifts, usually first in the day, and endurance cut to a maintenance dose: shorter sessions at the same intensity and one interval session a week. A value a client doesn't recognise is read as endurance. Known values: endurance, strength, strength_first. Treat unknown values as "other".

leaveOutJumpsboolean required

True when the athlete has chosen to leave jumps out. When most of their training is supported (cycling, rowing, swimming), strength sessions open with a few minutes of jumps; this keeps them out of every session. False by default. Body Lab doesn't record why.

barKindstring required

Which barbell the athlete loads: standard is their unit system's own standard bar (20 kg metric, 45 lb imperial — different bars, not conversions), custom reads barWeightKg, unknown is them saying don't guess, which a Smith machine or a trap bar deserves. Standard by default. Known values: standard, custom, unknown. Treat unknown values as "other".

barWeightKgnumber nullable required

The athlete's own barbell, in kilograms. Non-null exactly when barKind is custom.

clipWeightKgnumber required

The weight of ONE clip or collar, in kilograms; both sleeves get one. Zero by default: gym spring clips weigh next to nothing, while a competition collar is 2.5 kg each and a pair would add 5 kg to every barbell lift.

dailyUpdateModestring required

How often the Daily Update asks: daily (the default) on the first open of each day, unusual_only when last night's readings give a reason, or off. Patterns need ordinary nights as well as unusual ones. Known values: daily, unusual_only, off. Treat unknown values as "other".

hiddenExposuresstring[] required

Daily Update chips the athlete hid for good. They never show; Settings lists them so each can be brought back.

cycleTrackingstring required

Whether the Daily Update may ask about a period starting: auto asks whom the profile says could have a cycle; off is the athlete saying they don't have periods (pregnancy, menopause and contraception that stops bleeding are covered, and Body Lab doesn't ask which). Known values: auto, off. Treat unknown values as "other".

onboardedAtstring date-time nullable required

An instant: ISO-8601 with offset, e.g. 2026-09-13T06:30:00Z.

signedInFromPhoneAppboolean required

True once this account has signed in from a phone app (iOS or Android), so a browser needn't offer the download again. Which device and when are deliberately left out. Only sign-ins that named their platform count: an athlete who was already using the app before platforms were recorded reads false until their next sign-in there.

Changes

No recorded changes to this operation across all 1 revision of this API.