GET /users/{user_id}) requires admin access — public profile data is available through the dedicated public endpoint.
GET /api/v1/users/
Get a user’s complete profile in the canonical schema. You can only retrieve your own profile with a standard user token. Admin tokens may retrieve any user.Path parameters
The user’s unique ID.
Response
The user’s unique Firebase UID.
The user’s email address.
Unique username. 3–30 alphanumeric characters and underscores.
Public display name. Up to 50 characters. Does not need to be unique.
First name.
Last name.
Short biography displayed on the public profile.
URL of the user’s avatar image.
Account status. One of
active, inactive, suspended, pending, or deactivated.Primary role.
"athlete" or "coach".Whether the user’s email has been verified.
Account creation time as a Unix epoch millisecond timestamp.
Last profile update time as a Unix epoch millisecond timestamp.
Last login time as a Unix epoch millisecond timestamp.
User preferences including language, timezone, unit system, AI coach persona, and preferred workout days.
Subscription details including tier (
free, etc.), status, and expiry dates.Connection status for Strava, Garmin, and Apple Health.
Per-event notification toggles (all boolean).
Per-field privacy settings controlling what other users can see (all boolean).
PUT /api/v1/users/
Update a user’s profile. You can only update your own profile. Sends a partial or complete profile object — only the keys you include are updated. Nested structures likeintegrations, zones, subscription, notification_settings, and privacy are also accepted.
Path parameters
The user’s unique ID. Must match the authenticated user’s ID.
Request body
Send any combination of the writable profile fields. The following top-level fields are accepted:Public display name. Maximum 50 characters.
First name.
Last name.
Short biography. Length limit enforced server-side.
URL to the user’s avatar image.
Preference fields to update. See PATCH /users/me/preferences for field-level validation rules.
Notification preferences. All values must be boolean.
Privacy settings. All values must be boolean.
Integration connection state. Accepted providers:
strava, garmin, apple_health, coros. Each must include a connected boolean.Training zones including
heartrate, pace, and vdot sub-objects.Subscription data. Status must be one of
active, inactive, cancelled, expired, trialing.Response
List of top-level field keys that were included in the update payload.
GET /api/v1/users//public
Get the privacy-filtered public profile of any user. The fields returned depend on the target user’s privacy settings.Path parameters
The user ID of the profile to view.
Response
The user’s unique ID.
The user’s username. Always present.
Public display name. Always present.
Avatar URL. Only included when the user’s
share_profile_info privacy setting is true.Biography. Only included when
share_profile_info is true.Account creation time as Unix epoch milliseconds.
PATCH /api/v1/users/me/preferences
Update the authenticated user’s preferences. Only the fields you send are updated — this is a partial update. Unrecognized fields are logged and ignored.Request body
"metric" or "imperial".A valid IANA timezone string (e.g.
"Asia/Taipei", "America/New_York").Locale code. Supported values:
"en", "zh-TW", "ja".AI coach persona.
"rex" or "joy".Preferred training days. Array of lowercase weekday strings:
"monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday".Enable or disable beta features.
Response
List of preference keys that were successfully updated.
The preference values that were applied.
PUT /api/v1/users/username
Update the authenticated user’s username. Usernames must be unique across the platform.Request body
The new username. 3–30 characters, letters, numbers, and underscores only. Must not already be in use.
Response
GET /api/v1/users/check-username
Check whether a username is available before attempting to claim it.Query parameters
The username to check. Must meet the format requirements (3–30 characters, alphanumeric and underscores).
Response
true if the username is not taken, false if it is already in use.The username that was checked.