{"openapi":"3.1.0","info":{"title":"NetFit public API","version":"1.0.0","description":"The routes a coach's own integration may call, with the caller's NetFit session, and the outbound webhooks. Every other route under /api is internal and may change without notice."},"servers":[{"url":"https://{host}","description":"Your NetFit deployment","variables":{"host":{"default":"netfit.example.com"}}}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Webhooks"},{"name":"Clients"},{"name":"Workouts"},{"name":"Bookings"},{"name":"Check-ins"},{"name":"Habits"},{"name":"Metrics"},{"name":"Messages"},{"name":"Nutrition"},{"name":"Comments"},{"name":"Exports"},{"name":"Studios"},{"name":"Feedback"},{"name":"Referrals"}],"paths":{"/api/assigned-workouts":{"get":{"operationId":"listAssignedWorkouts","tags":["Workouts"],"summary":"Workouts assigned to clients (the item count, not the items)","parameters":[{"name":"clientId","in":"query","required":false,"description":"Only this client (a coach must coach them)","schema":{"type":"string"}},{"name":"status","in":"query","required":false,"description":"Only this status, for example completed","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Rows to return (default 500, at most 2000)","schema":{"type":"integer"}}],"responses":{"200":{"description":"Assignments, newest first","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignedWorkoutListResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/assigned-workouts/{id}":{"get":{"operationId":"getAssignedWorkout","tags":["Workouts"],"summary":"One assignment with the full prescription","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The assignment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignedWorkoutDetailResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/booking/public-page":{"get":{"operationId":"getPublicBookingPage","tags":["Bookings"],"summary":"The coach's public booking page settings (coach only); the page is /book/<slug>","parameters":[],"responses":{"200":{"description":"Whether the page is live, and its slug (null until chosen)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicBookingPageSettings"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"updatePublicBookingPage","tags":["Bookings"],"summary":"Turn the public booking page on or off, or change its slug (coach only)","parameters":[],"responses":{"200":{"description":"The saved settings. 409 when the slug is taken or reserved; 400 when turning the page on with no slug saved or sent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicBookingPageSettings"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicBookingPageUpdate"}}}}}},"/api/booking/waitlist":{"get":{"operationId":"listBookingWaitlist","tags":["Bookings"],"summary":"Live 1:1 waitlist places: a client's own, or every place in a coach's diary","parameters":[],"responses":{"200":{"description":"Places by start, each with its position in the queue","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingWaitlistListResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"joinBookingWaitlist","tags":["Bookings"],"summary":"A client queues for a taken start of one of their coach's session types","parameters":[],"responses":{"201":{"description":"The place. 409 when the start is open (book it instead). When the start frees up the head of the queue is offered it for 15 minutes.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingWaitlistPlace"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingWaitlistJoin"}}}}}},"/api/booking/waitlist/{id}":{"delete":{"operationId":"leaveBookingWaitlist","tags":["Bookings"],"summary":"Leave a waitlist; an offer held is passed to the next in line","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Left"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/bookings":{"get":{"operationId":"listBookings","tags":["Bookings"],"summary":"Sessions overlapping a window: a coach's diary or a client's own","parameters":[{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}},{"name":"to","in":"query","required":true,"schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}}],"responses":{"200":{"description":"Bookings by start time; at most 63 days per request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingListResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/bookings/{id}":{"get":{"operationId":"getBooking","tags":["Bookings"],"summary":"One booking","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The booking","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingView"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/checkins/due":{"get":{"operationId":"listDueCheckins","tags":["Check-ins"],"summary":"Scheduled check-in occurrences and their status","parameters":[{"name":"clientId","in":"query","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","required":false,"schema":{"default":"pending","anyOf":[{"type":"string","enum":["pending","done","missed","skipped"]},{"type":"string","const":"all"}]}},{"name":"limit","in":"query","required":false,"description":"Rows to return (default 200, at most 2000)","schema":{"type":"integer"}}],"responses":{"200":{"description":"Occurrences by due date","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckinDueListResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/clients":{"get":{"operationId":"listClients","tags":["Clients"],"summary":"A coach's client roster, or a client's coaches","parameters":[{"name":"trainerId","in":"query","required":false,"description":"The coach's own id: list their clients","schema":{"type":"string"}},{"name":"clientId","in":"query","required":false,"description":"The client's own id: list their coaches","schema":{"type":"string"}},{"name":"sort","in":"query","required":false,"description":"With `trainerId`: `recent` (default, newest first) or `risk` (highest at-risk score first)","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Rows to return (default 500, at most 2000)","schema":{"type":"integer"}}],"responses":{"200":{"description":"Active coaching links, newest first. One of trainerId or clientId is required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientListResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/clients/{id}":{"get":{"operationId":"getClient","tags":["Clients"],"summary":"One client's profile with their latest metrics, nutrition, tasks and workouts","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The client","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientDetailResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/clients/{id}/compliance":{"get":{"operationId":"getClientCompliance","tags":["Clients"],"summary":"Planned sessions done over the last 7, 30 and 90 days, and whether it is dropping","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"include","in":"query","required":false,"schema":{"description":"Comma-separated: `nutrition`, `habits`. Default: training only","type":"string","pattern":"^(nutrition|habits)(,(nutrition|habits))?$"}},{"name":"X-Timezone","in":"header","required":false,"description":"IANA time zone that decides \"today\", for example Europe/Skopje","schema":{"type":"string"}}],"responses":{"200":{"description":"Each window ends yesterday; `previous` is the same window before it","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ComplianceResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/exports/coach":{"get":{"operationId":"listCoachExports","tags":["Exports"],"summary":"The coach's recent whole-practice exports, with download links for ready parts. Start one with POST (second factor required, not part of this reference)","parameters":[],"responses":{"200":{"description":"Up to five exports, newest first","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoachExportJobList"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/exports/coach/{id}":{"get":{"operationId":"getCoachExport","tags":["Exports"],"summary":"One of the caller's whole-practice exports","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The export; parts carry 15-minute links once it is ready","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoachExportJob"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/foods/favourites":{"get":{"operationId":"listFavouriteFoods","tags":["Nutrition"],"summary":"The caller's starred foods, newest first, each with the amount last logged","parameters":[],"responses":{"200":{"description":"`{ items, attribution }`; attribution is set when an Open Food Facts product is listed"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"addFavouriteFood","tags":["Nutrition"],"summary":"Star a food: an Open Food Facts product or one of the caller's own foods","parameters":[],"responses":{"201":{"description":"`{ item, attribution }`. Starring a starred food again is the same answer."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodFavouriteCreate"}}}}}},"/api/foods/favourites/{foodRef}":{"delete":{"operationId":"removeFavouriteFood","tags":["Nutrition"],"summary":"Un-star a food; `foodRef` is `off:<id>` or `custom:<id>`","parameters":[{"name":"foodRef","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Removed"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/foods/recognise":{"post":{"operationId":"recogniseMealPhoto","tags":["Nutrition"],"summary":"Suggest what is in a meal photo, as editable estimates. Needs `ai_processing` consent (403 CONSENT_REQUIRED) and a configured provider (501 otherwise)","parameters":[],"responses":{"200":{"description":"`{ items }`, each a name with estimated calories and macros. Nothing is logged."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodRecognise"}}}}}},"/api/form-responses":{"get":{"operationId":"listCheckinResponses","tags":["Check-ins"],"summary":"Submitted check-in and form responses","parameters":[{"name":"formId","in":"query","required":false,"description":"Only responses to this form","schema":{"type":"string"}},{"name":"clientId","in":"query","required":false,"description":"Only this client (ignored for a client, who sees their own)","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Rows to return (default 500, at most 2000)","schema":{"type":"integer"}}],"responses":{"200":{"description":"Responses, newest first. A coach passes formId or clientId.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FormResponseListResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/forms/{id}/sign":{"post":{"operationId":"signFormResponse","tags":["Check-ins"],"summary":"E-sign your own submitted response to this form. Behind ESIGN_ENABLED: 404 while it is off","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"The signed document. `waiverAccepted` must be true (the signer was shown the waiver). 404 while ESIGN_ENABLED is off or the response belongs to someone else; 409 for a pending request or a response already signed. The receipt is emailed to the client and the coach.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignedDocumentCreated"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FormSign"}}}}}},"/api/forms/parq":{"post":{"operationId":"addParqForm","tags":["Check-ins"],"summary":"Add the PAR-Q health screen to the coach's forms (one copy per coach)","parameters":[],"responses":{"201":{"description":"201 when created, 200 with the existing copy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParqFormSummary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParqFormCreate"}}}}}},"/api/habit-entries":{"get":{"operationId":"listHabitEntries","tags":["Habits"],"summary":"A client's habit check-offs","parameters":[{"name":"clientId","in":"query","required":false,"description":"Whose entries (default: the caller)","schema":{"type":"string"}},{"name":"habitId","in":"query","required":false,"description":"Only this habit","schema":{"type":"string"}},{"name":"date","in":"query","required":false,"description":"One day, YYYY-MM-DD","schema":{"type":"string"}},{"name":"startDate","in":"query","required":false,"description":"From this day, YYYY-MM-DD","schema":{"type":"string"}},{"name":"endDate","in":"query","required":false,"description":"Up to this day, YYYY-MM-DD","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Rows to return (default 500, at most 2000)","schema":{"type":"integer"}}],"responses":{"200":{"description":"Entries, newest day first","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HabitEntryListResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/habits":{"get":{"operationId":"listHabits","tags":["Habits"],"summary":"A coach's habits with recent entries","parameters":[{"name":"trainerId","in":"query","required":false,"description":"The coach (required for a client)","schema":{"type":"string"}},{"name":"days","in":"query","required":false,"description":"Entry window in days (1 to 365)","schema":{"type":"integer"}},{"name":"limit","in":"query","required":false,"description":"Rows to return (default 500, at most 2000)","schema":{"type":"integer"}},{"name":"X-Timezone","in":"header","required":false,"description":"IANA time zone that decides \"today\", for example Europe/Skopje","schema":{"type":"string"}}],"responses":{"200":{"description":"Habits, newest first","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HabitListResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/habits/packs/{slug}/apply":{"post":{"operationId":"applyHabitPack","tags":["Habits"],"summary":"Add a habit pack (hydration, sleep, steps, protein, mobility, stress) to clients","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The pack habits, created where the coach lacked them. Idempotent; every client must be an active client of the caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HabitPackApplyResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HabitPackApply"}}}}}},"/api/log-comments/counts":{"get":{"operationId":"getLogCommentCounts","tags":["Comments"],"summary":"Comments per thread for one target type on one day: how many, and how many the caller has not read","parameters":[{"name":"targetType","in":"query","required":true,"description":"What the threads hang off, for example `nutrition_entry`","schema":{"type":"string"}},{"name":"date","in":"query","required":true,"description":"YYYY-MM-DD","schema":{"type":"string"}},{"name":"clientId","in":"query","required":false,"description":"A coach's linked client (default: every active client); ignored for a client","schema":{"type":"string"}}],"responses":{"200":{"description":"`{ counts: { \"<targetType>:<targetId>\": { total, unread } } }`; threads with no comment are left out"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/messages":{"get":{"operationId":"listMessages","tags":["Messages"],"summary":"One thread between the caller and another person, a page at a time","parameters":[{"name":"userId","in":"query","required":true,"description":"The caller","schema":{"type":"string"}},{"name":"otherUserId","in":"query","required":true,"description":"The other person","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Rows to return (default 50, at most 200)","schema":{"type":"integer"}},{"name":"cursor","in":"query","required":false,"description":"The `nextCursor` of the previous page","schema":{"type":"string"}}],"responses":{"200":{"description":"Messages, oldest first, each with its read receipt","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagePage"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/messages/{id}":{"patch":{"operationId":"markMessageRead","tags":["Messages"],"summary":"Mark a message addressed to the caller read; stamps `readAt` once","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The message","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/messages/voice-notes":{"get":{"operationId":"getVoiceNotesConfig","tags":["Messages"],"summary":"Whether voice notes are on, and the limits a recorder must keep to","parameters":[],"responses":{"200":{"description":"The switch and the limits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceNotesConfig"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/metric-definitions":{"get":{"operationId":"listMetricDefinitions","tags":["Metrics"],"summary":"The coach's custom metrics (a client sees their coaches')","parameters":[{"name":"includeArchived","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"limit","in":"query","required":false,"description":"Rows to return (default 100, at most 200)","schema":{"type":"integer"}},{"name":"cursor","in":"query","required":false,"description":"The `nextCursor` of the previous page","schema":{"type":"string"}}],"responses":{"200":{"description":"Definitions by id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricDefinitionPage"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/metrics":{"get":{"operationId":"listMetrics","tags":["Metrics"],"summary":"Body metric entries, a page at a time","parameters":[{"name":"clientId","in":"query","required":false,"schema":{"type":"string"}},{"name":"date","in":"query","required":false,"schema":{"type":"string"}},{"name":"metricType","in":"query","required":false,"schema":{"type":"string","enum":["weight","body_fat","bmi","steps","waist","chest","arms","thighs","neck","hips","custom"]}},{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":3650}},{"name":"limit","in":"query","required":false,"description":"Rows to return (default 30, at most 200)","schema":{"type":"integer"}},{"name":"cursor","in":"query","required":false,"description":"The `nextCursor` of the previous page","schema":{"type":"string"}}],"responses":{"200":{"description":"Entries, newest day first","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricEntryPage"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/metrics/{id}":{"get":{"operationId":"getMetric","tags":["Metrics"],"summary":"One metric entry","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The entry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricEntryDetail"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/nps":{"get":{"operationId":"getNpsState","tags":["Feedback"],"summary":"Whether the NPS prompt is on and the caller is due it","parameters":[],"responses":{"200":{"description":"The switch and the caller eligibility","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NpsState"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"submitNps","tags":["Feedback"],"summary":"Answer the NPS prompt (0-10 and an optional comment) or dismiss it","parameters":[],"responses":{"201":{"description":"Stored; 409 when not due, 404 while NPS is off","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NpsResponseCreated"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NpsSubmit"}}}}}},"/api/nutrition/compliance":{"get":{"operationId":"getNutritionCompliance","tags":["Nutrition"],"summary":"How closely a client ate to their targets over 7, 14 or 30 days","parameters":[{"name":"clientId","in":"query","required":false,"description":"Whose diary (default: the caller)","schema":{"type":"string"}},{"name":"endDate","in":"query","required":false,"description":"YYYY-MM-DD (default: today in X-Timezone)","schema":{"type":"string"}},{"name":"days","in":"query","required":false,"description":"7 (default), 14 or 30","schema":{"type":"string"}},{"name":"X-Timezone","in":"header","required":false,"description":"IANA time zone that decides \"today\", for example Europe/Skopje","schema":{"type":"string"}}],"responses":{"200":{"description":"Per-day status against that day's target (within 10 % is on track) and averages","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NutritionComplianceResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/nutrition/copy":{"post":{"operationId":"copyNutritionEntries","tags":["Nutrition"],"summary":"Copy a day or one meal of the diary to another date or meal (photos are not copied; notes, food links and micros are)","parameters":[],"responses":{"201":{"description":"`{ created, skipped }`. 404 NOTHING_TO_COPY when the source is empty. Honours Idempotency-Key."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NutritionCopy"}}}}}},"/api/nutrition/from-plan":{"post":{"operationId":"logPlannedMeal","tags":["Nutrition"],"summary":"Log a meal of a meal plan the client follows on that date, with its linked food's extra nutrients and micros","parameters":[],"responses":{"201":{"description":"The diary entry (`source: plan`). 409 ALREADY_LOGGED when that meal is logged for the day, unless `force` (then a copy with no plan link). Honours Idempotency-Key."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NutritionFromPlan"}}}}}},"/api/nutrition/report":{"get":{"operationId":"getNutritionWeeklyReport","tags":["Nutrition"],"summary":"A client's weekly nutrition report","parameters":[{"name":"clientId","in":"query","required":false,"description":"Whose report (default: the caller)","schema":{"type":"string"}},{"name":"weekEnding","in":"query","required":false,"description":"YYYY-MM-DD, the last day of the week (default: yesterday in X-Timezone)","schema":{"type":"string"}},{"name":"X-Timezone","in":"header","required":false,"description":"IANA time zone that decides \"today\", for example Europe/Skopje","schema":{"type":"string"}}],"responses":{"200":{"description":"Averages, averaged targets, compliance, best and worst day, top foods, photos, comments and OFF attribution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NutritionWeeklyReportResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/nutrition/summary":{"get":{"operationId":"getNutritionSummary","tags":["Nutrition"],"summary":"A day's nutrition totals against the client's goals","parameters":[{"name":"clientId","in":"query","required":false,"description":"Whose day (default: the caller)","schema":{"type":"string"}},{"name":"date","in":"query","required":false,"description":"YYYY-MM-DD (default: today in X-Timezone)","schema":{"type":"string"}},{"name":"X-Timezone","in":"header","required":false,"description":"IANA time zone that decides \"today\", for example Europe/Skopje","schema":{"type":"string"}}],"responses":{"200":{"description":"Totals, per-meal totals, extra nutrients (with which are partial), what remains, water, and the goals with where they came from","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NutritionDaySummaryResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/nutrition/targets/overrides":{"put":{"operationId":"setNutritionTargetOverride","tags":["Nutrition"],"summary":"Use one day type, or one calorie figure, on one date only","parameters":[{"name":"clientId","in":"query","required":false,"description":"Whose target (default: the caller); a coach's linked client","schema":{"type":"string"}}],"responses":{"200":{"description":"That date with the goals it now resolves to and where they come from"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NutritionTargetOverride"}}}}},"delete":{"operationId":"clearNutritionTargetOverride","tags":["Nutrition"],"summary":"Remove a one-date override: the date follows the week again","parameters":[{"name":"clientId","in":"query","required":false,"schema":{"type":"string"}},{"name":"date","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Removed (or there was none)"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/readiness":{"get":{"operationId":"getReadiness","tags":["Clients"],"summary":"How ready to train a client is today, from sleep, mood and energy and training load","parameters":[{"name":"clientId","in":"query","required":false,"schema":{"type":"string"}},{"name":"date","in":"query","required":false,"schema":{"type":"string"}},{"name":"X-Timezone","in":"header","required":false,"description":"IANA time zone that decides \"today\", for example Europe/Skopje","schema":{"type":"string"}}],"responses":{"200":{"description":"The score, its inputs with their points, and what was not logged","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadinessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/recipes/{id}/log":{"post":{"operationId":"logRecipe","tags":["Nutrition"],"summary":"Log servings of a recipe the client may use, with the items' summed micros","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"The diary entry (`source: recipe`). Honours Idempotency-Key."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeLog"}}}}}},"/api/recipes/{id}/save-as-food":{"post":{"operationId":"saveRecipeAsFood","tags":["Nutrition"],"summary":"Save one serving of a recipe as one of the caller's own foods","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"The new custom food"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/referrals":{"get":{"operationId":"getReferralSummary","tags":["Referrals"],"summary":"The coach's referral code, link and ledger totals","parameters":[],"responses":{"200":{"description":"Code, link, referred count and rewards; 404 while referrals are off","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReferralSummary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/signed-documents/{id}":{"get":{"operationId":"getSignedDocument","tags":["Check-ins"],"summary":"A signed form response (its signer, or the coach it was signed for)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"format","in":"query","required":false,"description":"`pdf` for the receipt, `text` for the signed UTF-8 text the SHA-256 is over","schema":{"type":"string"}}],"responses":{"200":{"description":"The record; with `format=pdf`, the receipt as application/pdf; with `format=text`, the exact signed text as text/plain","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignedDocumentView"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/tenants/{id}/audit":{"get":{"operationId":"listStudioAudit","tags":["Studios"],"summary":"The studio's audit log, for its owner only","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"actorId","in":"query","required":false,"schema":{"type":"string","minLength":1,"maxLength":64}},{"name":"action","in":"query","required":false,"schema":{"type":"string","minLength":1,"maxLength":64}},{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","maxLength":256}},{"name":"limit","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{1,3}$"}}],"responses":{"200":{"description":"Entries newest first, with the studio coaches for filtering","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudioAuditPage"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/users/me/dietary":{"get":{"operationId":"getDietaryProfile","tags":["Nutrition"],"summary":"The caller's allergens and diets, which the food screens flag","parameters":[],"responses":{"200":{"description":"`{ allergens, diet }`, both empty when never set"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"setDietaryProfile","tags":["Nutrition"],"summary":"Replace the caller's allergens and diets (from the fixed lists)","parameters":[],"responses":{"200":{"description":"The saved profile"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DietaryProfile"}}}}}},"/api/water":{"post":{"operationId":"logWater","tags":["Nutrition"],"summary":"Set or add to a day's water: exactly one of `glasses`, `ml` (the day's total) or `addMl` (added in one atomic step; negative takes back)","parameters":[],"responses":{"200":{"description":"The day: `ml`, and `glasses` kept in step (ml / 250). Honours Idempotency-Key."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaterUpsert"}}}}}},"/api/webhook-endpoints":{"get":{"operationId":"listWebhookEndpoints","tags":["Webhooks"],"summary":"List the coach's webhook endpoints (never the secret)","parameters":[],"responses":{"200":{"description":"The endpoints, newest first","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointList"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"createWebhookEndpoint","tags":["Webhooks"],"summary":"Add a webhook endpoint; the signing secret is returned once","parameters":[],"responses":{"201":{"description":"The endpoint with its plain `whsec_` secret. Store it now.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointCreated"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointCreate"}}}}}},"/api/webhook-endpoints/{id}":{"patch":{"operationId":"updateWebhookEndpoint","tags":["Webhooks"],"summary":"Change the URL or events of an endpoint, or switch it on or off (on also clears an automatic switch-off)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The updated endpoint","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointUpdate"}}}}},"delete":{"operationId":"deleteWebhookEndpoint","tags":["Webhooks"],"summary":"Remove an endpoint and its delivery log","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeleteResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/webhook-endpoints/{id}/deliveries":{"get":{"operationId":"listWebhookDeliveries","tags":["Webhooks"],"summary":"The latest 50 deliveries to an endpoint, newest first","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deliveries with their attempts and last result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryList"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/webhook-endpoints/{id}/deliveries/{deliveryId}/replay":{"post":{"operationId":"replayWebhookDelivery","tags":["Webhooks"],"summary":"Send a finished (delivered or failed) delivery again, as a copy with a new delivery id; 409 while it is still pending or the endpoint is off","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"deliveryId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"202":{"description":"The queued copy; the next delivery run sends it, within 15 minutes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookReplayResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/webhook-endpoints/{id}/rotate-secret":{"post":{"operationId":"rotateWebhookSecret","tags":["Webhooks"],"summary":"Replace the signing secret; the old one keeps signing as a second v1 for 24 hours unless revokePrevious is true","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The endpoint with its new plain `whsec_` secret. Store it now.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSecretRotated"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSecretRotate"}}}}}},"/api/webhook-endpoints/{id}/test":{"post":{"operationId":"sendWebhookTest","tags":["Webhooks"],"summary":"Queue a signed `ping` delivery to an active endpoint","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"202":{"description":"The queued ping; the next delivery run sends it, within 15 minutes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTestResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/workout-logs":{"get":{"operationId":"listWorkoutLogs","tags":["Workouts"],"summary":"Completed workout logs, a page at a time","parameters":[{"name":"clientId","in":"query","required":false,"description":"Whose logs (default: the caller)","schema":{"type":"string"}},{"name":"include","in":"query","required":false,"description":"Comma-separated: setLog, feedback","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Rows to return (default 30, at most 200)","schema":{"type":"integer"}},{"name":"cursor","in":"query","required":false,"description":"The `nextCursor` of the previous page","schema":{"type":"string"}}],"responses":{"200":{"description":"Logs, newest first","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkoutLogPage"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/workout-logs/{id}":{"get":{"operationId":"getWorkoutLog","tags":["Workouts"],"summary":"One workout log with its exercises","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkoutLog"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/workouts":{"get":{"operationId":"listWorkouts","tags":["Workouts"],"summary":"The coach's workout templates with their exercises","parameters":[{"name":"category","in":"query","required":false,"description":"Only this category","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Rows to return (default 500, at most 2000)","schema":{"type":"integer"}}],"responses":{"200":{"description":"Workouts, newest first","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkoutListResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/workouts/{id}":{"get":{"operationId":"getWorkout","tags":["Workouts"],"summary":"One workout with its items in order","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The workout","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Workout"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}}},"webhooks":{"workout.completed":{"post":{"summary":"A client completed an assigned workout","description":"Every delivery is a POST with a JSON body and a `NetFit-Signature: t=<unix seconds>,v1=<hex>` header. `v1` is the HMAC-SHA256, under the endpoint secret (`whsec_...`), of the string `<t>.<raw body>`. Recompute it over the raw bytes before parsing, compare in constant time, and refuse a `t` more than 300 seconds from your clock. For 24 hours after a secret rotation the header carries two `v1` values, one per secret: accept the request when any of them matches. Answer any 2xx within 10 seconds; anything else is retried after 1 min, 5 min, 30 min and 2 h, then marked failed. After 10 failed deliveries in a row the endpoint is switched off and its owner notified; switching it back on sends what was queued. `NetFit-Delivery` is the delivery id: the same on every retry, so use it to ignore duplicates. A replay is a new delivery with a new id.","parameters":[{"name":"NetFit-Signature","in":"header","required":true,"description":"t=<unix seconds>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\">","schema":{"type":"string"}},{"name":"NetFit-Event","in":"header","required":true,"schema":{"type":"string","const":"workout.completed"}},{"name":"NetFit-Delivery","in":"header","required":true,"description":"Delivery id, stable across retries","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Delivery id; the same as the NetFit-Delivery header"},"event":{"type":"string","const":"workout.completed"},"createdAt":{"type":"string","description":"ISO-8601 time the event was queued"},"data":{"type":"object","properties":{"assignedWorkoutId":{"type":"string"},"workoutLogId":{"description":"null when the session was marked done without logging sets","type":["string","null"]},"clientId":{"type":"string"},"completedAt":{"type":"string"}},"required":["assignedWorkoutId","workoutLogId","clientId","completedAt"],"additionalProperties":false}},"required":["id","event","createdAt","data"],"additionalProperties":false}}}},"responses":{"2XX":{"description":"Received. Anything else, or no answer in 10 s, is retried."}}}},"checkin.submitted":{"post":{"summary":"A client submitted a check-in form","description":"Every delivery is a POST with a JSON body and a `NetFit-Signature: t=<unix seconds>,v1=<hex>` header. `v1` is the HMAC-SHA256, under the endpoint secret (`whsec_...`), of the string `<t>.<raw body>`. Recompute it over the raw bytes before parsing, compare in constant time, and refuse a `t` more than 300 seconds from your clock. For 24 hours after a secret rotation the header carries two `v1` values, one per secret: accept the request when any of them matches. Answer any 2xx within 10 seconds; anything else is retried after 1 min, 5 min, 30 min and 2 h, then marked failed. After 10 failed deliveries in a row the endpoint is switched off and its owner notified; switching it back on sends what was queued. `NetFit-Delivery` is the delivery id: the same on every retry, so use it to ignore duplicates. A replay is a new delivery with a new id.","parameters":[{"name":"NetFit-Signature","in":"header","required":true,"description":"t=<unix seconds>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\">","schema":{"type":"string"}},{"name":"NetFit-Event","in":"header","required":true,"schema":{"type":"string","const":"checkin.submitted"}},{"name":"NetFit-Delivery","in":"header","required":true,"description":"Delivery id, stable across retries","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Delivery id; the same as the NetFit-Delivery header"},"event":{"type":"string","const":"checkin.submitted"},"createdAt":{"type":"string","description":"ISO-8601 time the event was queued"},"data":{"type":"object","properties":{"responseId":{"type":"string"},"formId":{"type":"string"},"clientId":{"type":"string"},"submittedAt":{"type":"string"}},"required":["responseId","formId","clientId","submittedAt"],"additionalProperties":false}},"required":["id","event","createdAt","data"],"additionalProperties":false}}}},"responses":{"2XX":{"description":"Received. Anything else, or no answer in 10 s, is retried."}}}},"booking.created":{"post":{"summary":"A session was booked","description":"Every delivery is a POST with a JSON body and a `NetFit-Signature: t=<unix seconds>,v1=<hex>` header. `v1` is the HMAC-SHA256, under the endpoint secret (`whsec_...`), of the string `<t>.<raw body>`. Recompute it over the raw bytes before parsing, compare in constant time, and refuse a `t` more than 300 seconds from your clock. For 24 hours after a secret rotation the header carries two `v1` values, one per secret: accept the request when any of them matches. Answer any 2xx within 10 seconds; anything else is retried after 1 min, 5 min, 30 min and 2 h, then marked failed. After 10 failed deliveries in a row the endpoint is switched off and its owner notified; switching it back on sends what was queued. `NetFit-Delivery` is the delivery id: the same on every retry, so use it to ignore duplicates. A replay is a new delivery with a new id.","parameters":[{"name":"NetFit-Signature","in":"header","required":true,"description":"t=<unix seconds>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\">","schema":{"type":"string"}},{"name":"NetFit-Event","in":"header","required":true,"schema":{"type":"string","const":"booking.created"}},{"name":"NetFit-Delivery","in":"header","required":true,"description":"Delivery id, stable across retries","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Delivery id; the same as the NetFit-Delivery header"},"event":{"type":"string","const":"booking.created"},"createdAt":{"type":"string","description":"ISO-8601 time the event was queued"},"data":{"type":"object","properties":{"bookingId":{"type":"string"},"clientId":{"type":["string","null"]},"startsAt":{"type":"string"}},"required":["bookingId","clientId","startsAt"],"additionalProperties":false}},"required":["id","event","createdAt","data"],"additionalProperties":false}}}},"responses":{"2XX":{"description":"Received. Anything else, or no answer in 10 s, is retried."}}}},"booking.cancelled":{"post":{"summary":"A session was cancelled","description":"Every delivery is a POST with a JSON body and a `NetFit-Signature: t=<unix seconds>,v1=<hex>` header. `v1` is the HMAC-SHA256, under the endpoint secret (`whsec_...`), of the string `<t>.<raw body>`. Recompute it over the raw bytes before parsing, compare in constant time, and refuse a `t` more than 300 seconds from your clock. For 24 hours after a secret rotation the header carries two `v1` values, one per secret: accept the request when any of them matches. Answer any 2xx within 10 seconds; anything else is retried after 1 min, 5 min, 30 min and 2 h, then marked failed. After 10 failed deliveries in a row the endpoint is switched off and its owner notified; switching it back on sends what was queued. `NetFit-Delivery` is the delivery id: the same on every retry, so use it to ignore duplicates. A replay is a new delivery with a new id.","parameters":[{"name":"NetFit-Signature","in":"header","required":true,"description":"t=<unix seconds>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\">","schema":{"type":"string"}},{"name":"NetFit-Event","in":"header","required":true,"schema":{"type":"string","const":"booking.cancelled"}},{"name":"NetFit-Delivery","in":"header","required":true,"description":"Delivery id, stable across retries","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Delivery id; the same as the NetFit-Delivery header"},"event":{"type":"string","const":"booking.cancelled"},"createdAt":{"type":"string","description":"ISO-8601 time the event was queued"},"data":{"type":"object","properties":{"bookingId":{"type":"string"},"clientId":{"type":["string","null"]},"startsAt":{"type":"string"}},"required":["bookingId","clientId","startsAt"],"additionalProperties":false}},"required":["id","event","createdAt","data"],"additionalProperties":false}}}},"responses":{"2XX":{"description":"Received. Anything else, or no answer in 10 s, is retried."}}}},"client.joined":{"post":{"summary":"A client accepted an invite and joined the coach","description":"Every delivery is a POST with a JSON body and a `NetFit-Signature: t=<unix seconds>,v1=<hex>` header. `v1` is the HMAC-SHA256, under the endpoint secret (`whsec_...`), of the string `<t>.<raw body>`. Recompute it over the raw bytes before parsing, compare in constant time, and refuse a `t` more than 300 seconds from your clock. For 24 hours after a secret rotation the header carries two `v1` values, one per secret: accept the request when any of them matches. Answer any 2xx within 10 seconds; anything else is retried after 1 min, 5 min, 30 min and 2 h, then marked failed. After 10 failed deliveries in a row the endpoint is switched off and its owner notified; switching it back on sends what was queued. `NetFit-Delivery` is the delivery id: the same on every retry, so use it to ignore duplicates. A replay is a new delivery with a new id.","parameters":[{"name":"NetFit-Signature","in":"header","required":true,"description":"t=<unix seconds>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\">","schema":{"type":"string"}},{"name":"NetFit-Event","in":"header","required":true,"schema":{"type":"string","const":"client.joined"}},{"name":"NetFit-Delivery","in":"header","required":true,"description":"Delivery id, stable across retries","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Delivery id; the same as the NetFit-Delivery header"},"event":{"type":"string","const":"client.joined"},"createdAt":{"type":"string","description":"ISO-8601 time the event was queued"},"data":{"type":"object","properties":{"clientId":{"type":"string"},"joinedAt":{"type":"string"}},"required":["clientId","joinedAt"],"additionalProperties":false}},"required":["id","event","createdAt","data"],"additionalProperties":false}}}},"responses":{"2XX":{"description":"Received. Anything else, or no answer in 10 s, is retried."}}}},"ping":{"post":{"summary":"Sent by \"Send test\" only; not subscribable","description":"Every delivery is a POST with a JSON body and a `NetFit-Signature: t=<unix seconds>,v1=<hex>` header. `v1` is the HMAC-SHA256, under the endpoint secret (`whsec_...`), of the string `<t>.<raw body>`. Recompute it over the raw bytes before parsing, compare in constant time, and refuse a `t` more than 300 seconds from your clock. For 24 hours after a secret rotation the header carries two `v1` values, one per secret: accept the request when any of them matches. Answer any 2xx within 10 seconds; anything else is retried after 1 min, 5 min, 30 min and 2 h, then marked failed. After 10 failed deliveries in a row the endpoint is switched off and its owner notified; switching it back on sends what was queued. `NetFit-Delivery` is the delivery id: the same on every retry, so use it to ignore duplicates. A replay is a new delivery with a new id.","parameters":[{"name":"NetFit-Signature","in":"header","required":true,"description":"t=<unix seconds>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\">","schema":{"type":"string"}},{"name":"NetFit-Event","in":"header","required":true,"schema":{"type":"string","const":"ping"}},{"name":"NetFit-Delivery","in":"header","required":true,"description":"Delivery id, stable across retries","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Delivery id; the same as the NetFit-Delivery header"},"event":{"type":"string","const":"ping"},"createdAt":{"type":"string","description":"ISO-8601 time the event was queued"},"data":{"type":"object","properties":{"endpointId":{"type":"string"},"sentAt":{"type":"string"}},"required":["endpointId","sentAt"],"additionalProperties":false}},"required":["id","event","createdAt","data"],"additionalProperties":false}}}},"responses":{"2XX":{"description":"Received. Anything else, or no answer in 10 s, is retried."}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"The Supabase access token of a signed-in NetFit user, as the mobile app sends it: `Authorization: Bearer <access_token>`. Every call acts as that user."}},"responses":{"BadRequest":{"description":"Invalid request (VALIDATION_ERROR lists the issues)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"Unauthorized":{"description":"Missing or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"Forbidden":{"description":"Signed in, but not allowed to touch this row","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"NotFound":{"description":"Not found, or not visible to the caller","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"RateLimited":{"description":"Rate limited; retry later","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"schemas":{"ApiErrorResponse":{"type":"object","properties":{"error":{"type":"string"},"code":{"description":"Machine-readable, for example VALIDATION_ERROR","type":"string"},"message":{"type":"string"},"issues":{"description":"VALIDATION_ERROR only","type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false}}},"required":["error"],"additionalProperties":{}},"AssignedWorkoutDetailResponse":{"type":"object","properties":{"id":{"type":"string"},"workoutId":{"type":"string"},"clientId":{"type":"string"},"trainerId":{"type":"string"},"scheduledDate":{"anyOf":[{"type":"string","description":"Calendar day, YYYY-MM-DD"},{"type":"null"}]},"status":{"type":"string"},"clientNotes":{"type":["string","null"]},"completedAt":{"anyOf":[{"type":"string","description":"ISO-8601 timestamp"},{"type":"null"}]},"programmeAssignmentId":{"type":["string","null"]},"createdAt":{"type":"string","description":"ISO-8601 timestamp"},"updatedAt":{"type":"string","description":"ISO-8601 timestamp"},"client":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"avatar":{"type":["string","null"]}},"required":["id","name","avatar"],"additionalProperties":{}},"trainer":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"avatar":{"type":["string","null"]}},"required":["id","name","avatar"],"additionalProperties":{}},"workout":{"type":"object","properties":{"id":{"type":"string"},"trainerId":{"type":["string","null"]},"name":{"type":"string"},"description":{"type":["string","null"]},"category":{"type":["string","null"]},"difficulty":{"type":"string"},"estimatedDuration":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Minutes"},"isTemplate":{"type":"boolean"},"createdAt":{"type":"string","description":"ISO-8601 timestamp"},"updatedAt":{"type":"string","description":"ISO-8601 timestamp"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"workoutId":{"type":"string"},"exerciseId":{"type":"string"},"sets":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"reps":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"weight":{"type":["number","null"]},"restTime":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"duration":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"notes":{"type":["string","null"]},"exercise":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"category":{"type":["string","null"]}},"required":["id","name","category"],"additionalProperties":{}}},"required":["id","workoutId","exerciseId","sets","reps","weight","restTime","duration","order","notes","exercise"],"additionalProperties":{}}}},"required":["id","trainerId","name","description","category","difficulty","estimatedDuration","isTemplate","createdAt","updatedAt","items"],"additionalProperties":{}}},"required":["id","workoutId","clientId","trainerId","scheduledDate","status","clientNotes","completedAt","programmeAssignmentId","createdAt","updatedAt","client","trainer","workout"],"additionalProperties":{}},"AssignedWorkoutListResponse":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"workoutId":{"type":"string"},"clientId":{"type":"string"},"trainerId":{"type":"string"},"scheduledDate":{"anyOf":[{"type":"string","description":"Calendar day, YYYY-MM-DD"},{"type":"null"}]},"status":{"type":"string"},"clientNotes":{"type":["string","null"]},"completedAt":{"anyOf":[{"type":"string","description":"ISO-8601 timestamp"},{"type":"null"}]},"programmeAssignmentId":{"type":["string","null"]},"createdAt":{"type":"string","description":"ISO-8601 timestamp"},"updatedAt":{"type":"string","description":"ISO-8601 timestamp"},"client":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"avatar":{"type":["string","null"]}},"required":["id","name","avatar"],"additionalProperties":{}},"trainer":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"avatar":{"type":["string","null"]}},"required":["id","name","avatar"],"additionalProperties":{}},"workout":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"category":{"type":["string","null"]},"difficulty":{"type":"string"},"estimatedDuration":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"_count":{"type":"object","properties":{"items":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["items"],"additionalProperties":false}},"required":["id","name","description","category","difficulty","estimatedDuration","_count"],"additionalProperties":{}}},"required":["id","workoutId","clientId","trainerId","scheduledDate","status","clientNotes","completedAt","programmeAssignmentId","createdAt","updatedAt","client","trainer","workout"],"additionalProperties":{}}},"BookingListResponse":{"maxItems":1000,"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"startsAt":{"type":"string","description":"ISO-8601 timestamp"},"endsAt":{"type":"string","description":"ISO-8601 timestamp"},"status":{"type":"string","enum":["pending","confirmed","cancelled","no_show","attended","late_cancel"]},"clientNote":{"type":["string","null"]},"coachNote":{"description":"Coach only; absent for a client","type":["string","null"]},"notes":{"description":"Deprecated: read clientNote and coachNote","type":["string","null"]},"meetingUrl":{"type":["string","null"]},"seriesId":{"type":["string","null"]},"cancelReason":{"type":["string","null"]},"createdAt":{"type":"string","description":"ISO-8601 timestamp"},"sessionType":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"color":{"type":["string","null"]},"durationMin":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"mode":{"type":"string"}},"required":["id","name","color","durationMin","mode"],"additionalProperties":{}},"trainer":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"avatar":{"type":["string","null"]}},"required":["id","name","avatar"],"additionalProperties":{}},"client":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"avatar":{"type":["string","null"]}},"required":["id","name","avatar"],"additionalProperties":{}},{"type":"null"}]},"location":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"address":{"type":["string","null"]}},"required":["id","name","address"],"additionalProperties":{}},{"type":"null"}]}},"required":["id","startsAt","endsAt","status","clientNote","notes","meetingUrl","seriesId","cancelReason","createdAt","sessionType","trainer","client","location"],"additionalProperties":{}}},"BookingView":{"type":"object","properties":{"id":{"type":"string"},"startsAt":{"type":"string","description":"ISO-8601 timestamp"},"endsAt":{"type":"string","description":"ISO-8601 timestamp"},"status":{"type":"string","enum":["pending","confirmed","cancelled","no_show","attended","late_cancel"]},"clientNote":{"type":["string","null"]},"coachNote":{"description":"Coach only; absent for a client","type":["string","null"]},"notes":{"description":"Deprecated: read clientNote and coachNote","type":["string","null"]},"meetingUrl":{"type":["string","null"]},"seriesId":{"type":["string","null"]},"cancelReason":{"type":["string","null"]},"createdAt":{"type":"string","description":"ISO-8601 timestamp"},"sessionType":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"color":{"type":["string","null"]},"durationMin":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"mode":{"type":"string"}},"required":["id","name","color","durationMin","mode"],"additionalProperties":{}},"trainer":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"avatar":{"type":["string","null"]}},"required":["id","name","avatar"],"additionalProperties":{}},"client":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"avatar":{"type":["string","null"]}},"required":["id","name","avatar"],"additionalProperties":{}},{"type":"null"}]},"location":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"address":{"type":["string","null"]}},"required":["id","name","address"],"additionalProperties":{}},{"type":"null"}]}},"required":["id","startsAt","endsAt","status","clientNote","notes","meetingUrl","seriesId","cancelReason","createdAt","sessionType","trainer","client","location"],"additionalProperties":{}},"BookingWaitlistJoin":{"type":"object","properties":{"sessionTypeId":{"type":"string","pattern":"^[cC][^\\s-]{8,}$"},"startsAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}},"required":["sessionTypeId","startsAt"],"additionalProperties":false},"BookingWaitlistListResponse":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"trainerId":{"type":"string"},"clientId":{"type":"string"},"sessionTypeId":{"type":"string"},"startsAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"status":{"type":"string","enum":["waiting","offered","booked","expired","left"]},"offeredAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},{"type":"null"}]},"holdExpiresAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"position":{"anyOf":[{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},{"type":"null"}]}},"required":["id","trainerId","clientId","sessionTypeId","startsAt","status","offeredAt","holdExpiresAt","createdAt","position"],"additionalProperties":false}}},"required":["items"],"additionalProperties":false},"BookingWaitlistPlace":{"type":"object","properties":{"id":{"type":"string"},"trainerId":{"type":"string"},"clientId":{"type":"string"},"sessionTypeId":{"type":"string"},"startsAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"status":{"type":"string","enum":["waiting","offered","booked","expired","left"]},"offeredAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},{"type":"null"}]},"holdExpiresAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"position":{"anyOf":[{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},{"type":"null"}]}},"required":["id","trainerId","clientId","sessionTypeId","startsAt","status","offeredAt","holdExpiresAt","createdAt","position"],"additionalProperties":false},"CheckinDueListResponse":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"scheduleId":{"type":"string"},"clientId":{"type":"string"},"dueDate":{"type":"string","description":"Calendar day, YYYY-MM-DD"},"status":{"type":"string","enum":["pending","done","missed","skipped"]},"formResponseId":{"type":["string","null"]},"remindedAt":{"anyOf":[{"type":"string","description":"ISO-8601 timestamp"},{"type":"null"}]},"completedAt":{"anyOf":[{"type":"string","description":"ISO-8601 timestamp"},{"type":"null"}]},"schedule":{"type":"object","properties":{"id":{"type":"string"},"cadence":{"type":"string","enum":["once","weekly","biweekly","monthly"]},"trainerId":{"type":"string"},"form":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]}},"required":["id","title","description"],"additionalProperties":false}},"required":["id","cadence","trainerId","form"],"additionalProperties":false}},"required":["id","scheduleId","clientId","dueDate","status","formResponseId","remindedAt","completedAt","schedule"],"additionalProperties":false}},"ClientDetailResponse":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"},"avatar":{"type":["string","null"]},"bio":{"type":["string","null"]},"phone":{"type":["string","null"]},"dateOfBirth":{"type":["string","null"]},"height":{"type":["number","null"]},"createdAt":{"type":"string","description":"ISO-8601 timestamp"},"metricEntries":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"}},"required":["id"],"additionalProperties":{}},"description":"Latest 10"},"nutritionEntries":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"}},"required":["id"],"additionalProperties":{}},"description":"Latest 10"},"assignedTasks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"}},"required":["id"],"additionalProperties":{}},"description":"Latest 10"},"assignedWorkoutsClient":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"workout":{"type":"object","properties":{"id":{"type":"string"}},"required":["id"],"additionalProperties":{}}},"required":["id","workout"],"additionalProperties":{}},"description":"Latest 5, with the workout"}},"required":["id","name","email","avatar","bio","phone","dateOfBirth","height","createdAt","metricEntries","nutritionEntries","assignedTasks","assignedWorkoutsClient"],"additionalProperties":{}},"ClientListResponse":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"clientId":{"type":"string"},"trainerId":{"type":"string"},"status":{"type":"string","description":"Link status; `ended` links are never listed"},"notes":{"type":["string","null"]},"createdAt":{"type":"string","description":"ISO-8601 timestamp"},"updatedAt":{"type":"string","description":"ISO-8601 timestamp"},"client":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"},"avatar":{"type":["string","null"]},"bio":{"type":["string","null"]},"phone":{"type":["string","null"]},"dateOfBirth":{"type":["string","null"]},"height":{"type":["number","null"]},"createdAt":{"type":"string","description":"ISO-8601 timestamp"}},"required":["id","name","email","avatar","bio","phone","dateOfBirth","height","createdAt"],"additionalProperties":{}},"risk":{"description":"W4: the at-risk score; null for a link that is not active","anyOf":[{"type":"object","properties":{"score":{"type":"integer","minimum":0,"maximum":100},"band":{"type":"string","enum":["low","medium","high"]},"reasons":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Locale key, `insights.risk.reasons.<reason>`"},"weight":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"detail":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"number"},"description":"ICU values for the locale key"}},"required":["key","weight","detail"],"additionalProperties":false}}},"required":["score","band","reasons"],"additionalProperties":false},{"type":"null"}]}},"required":["id","clientId","trainerId","status","notes","createdAt","updatedAt","client"],"additionalProperties":{}},"description":"`?trainerId=`: the coach roster"},{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"clientId":{"type":"string"},"trainerId":{"type":"string"},"status":{"type":"string","description":"Link status; `ended` links are never listed"},"notes":{"type":["string","null"]},"createdAt":{"type":"string","description":"ISO-8601 timestamp"},"updatedAt":{"type":"string","description":"ISO-8601 timestamp"},"trainer":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"},"avatar":{"type":["string","null"]},"bio":{"type":["string","null"]},"specializations":{"type":["string","null"]}},"required":["id","name","email","avatar","bio","specializations"],"additionalProperties":{}}},"required":["id","clientId","trainerId","status","notes","createdAt","updatedAt","trainer"],"additionalProperties":{}},"description":"`?clientId=`: the client's coaches"}]},"CoachExportJobList":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["queued","running","ready","failed"]},"createdAt":{"type":"string","description":"ISO-8601 timestamp"},"finishedAt":{"anyOf":[{"type":"string","description":"ISO-8601 timestamp"},{"type":"null"}]},"expiresAt":{"anyOf":[{"type":"string","description":"ISO-8601 timestamp"},{"type":"null"}],"description":"After this the parts are no longer offered"},"parts":{"type":"array","items":{"type":"object","properties":{"part":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"1-based part number"},"bytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"files":{"type":"array","items":{"type":"string"},"description":"File names in this ZIP, besides manifest.json"},"url":{"description":"15-minute download link; null unless ready","type":["string","null"]}},"required":["part","bytes","files","url"],"additionalProperties":{}}}},"required":["id","status","createdAt","finishedAt","expiresAt","parts"],"additionalProperties":{}},"description":"The five most recent exports, newest first"},"nextCursor":{"type":"null"}},"required":["items","nextCursor"],"additionalProperties":false},"CoachExportJob":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["queued","running","ready","failed"]},"createdAt":{"type":"string","description":"ISO-8601 timestamp"},"finishedAt":{"anyOf":[{"type":"string","description":"ISO-8601 timestamp"},{"type":"null"}]},"expiresAt":{"anyOf":[{"type":"string","description":"ISO-8601 timestamp"},{"type":"null"}],"description":"After this the parts are no longer offered"},"parts":{"type":"array","items":{"type":"object","properties":{"part":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"1-based part number"},"bytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"files":{"type":"array","items":{"type":"string"},"description":"File names in this ZIP, besides manifest.json"},"url":{"description":"15-minute download link; null unless ready","type":["string","null"]}},"required":["part","bytes","files","url"],"additionalProperties":{}}}},"required":["id","status","createdAt","finishedAt","expiresAt","parts"],"additionalProperties":{}},"ComplianceResponse":{"type":"object","properties":{"windows":{"type":"object","properties":{"d7":{"type":"object","properties":{"pct":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"null when nothing was planned"},"completed":{"type":"integer","minimum":0,"maximum":9007199254740991},"scheduled":{"type":"integer","minimum":0,"maximum":9007199254740991},"parts":{"type":"object","properties":{"training":{"type":"object","properties":{"pct":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"null when nothing was planned"},"completed":{"type":"integer","minimum":0,"maximum":9007199254740991},"scheduled":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["pct","completed","scheduled"],"additionalProperties":false},"nutrition":{"type":"object","properties":{"pct":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"null when nothing was planned"},"completed":{"type":"integer","minimum":0,"maximum":9007199254740991},"scheduled":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["pct","completed","scheduled"],"additionalProperties":false},"habits":{"type":"object","properties":{"pct":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"null when nothing was planned"},"completed":{"type":"integer","minimum":0,"maximum":9007199254740991},"scheduled":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["pct","completed","scheduled"],"additionalProperties":false}},"required":["training"],"additionalProperties":false}},"required":["pct","completed","scheduled","parts"],"additionalProperties":false},"d30":{"type":"object","properties":{"pct":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"null when nothing was planned"},"completed":{"type":"integer","minimum":0,"maximum":9007199254740991},"scheduled":{"type":"integer","minimum":0,"maximum":9007199254740991},"parts":{"type":"object","properties":{"training":{"type":"object","properties":{"pct":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"null when nothing was planned"},"completed":{"type":"integer","minimum":0,"maximum":9007199254740991},"scheduled":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["pct","completed","scheduled"],"additionalProperties":false},"nutrition":{"type":"object","properties":{"pct":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"null when nothing was planned"},"completed":{"type":"integer","minimum":0,"maximum":9007199254740991},"scheduled":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["pct","completed","scheduled"],"additionalProperties":false},"habits":{"type":"object","properties":{"pct":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"null when nothing was planned"},"completed":{"type":"integer","minimum":0,"maximum":9007199254740991},"scheduled":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["pct","completed","scheduled"],"additionalProperties":false}},"required":["training"],"additionalProperties":false}},"required":["pct","completed","scheduled","parts"],"additionalProperties":false},"d90":{"type":"object","properties":{"pct":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"null when nothing was planned"},"completed":{"type":"integer","minimum":0,"maximum":9007199254740991},"scheduled":{"type":"integer","minimum":0,"maximum":9007199254740991},"parts":{"type":"object","properties":{"training":{"type":"object","properties":{"pct":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"null when nothing was planned"},"completed":{"type":"integer","minimum":0,"maximum":9007199254740991},"scheduled":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["pct","completed","scheduled"],"additionalProperties":false},"nutrition":{"type":"object","properties":{"pct":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"null when nothing was planned"},"completed":{"type":"integer","minimum":0,"maximum":9007199254740991},"scheduled":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["pct","completed","scheduled"],"additionalProperties":false},"habits":{"type":"object","properties":{"pct":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"null when nothing was planned"},"completed":{"type":"integer","minimum":0,"maximum":9007199254740991},"scheduled":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["pct","completed","scheduled"],"additionalProperties":false}},"required":["training"],"additionalProperties":false}},"required":["pct","completed","scheduled","parts"],"additionalProperties":false}},"required":["d7","d30","d90"],"additionalProperties":false,"description":"Each window ends yesterday"},"previous":{"type":"object","properties":{"d7":{"type":"object","properties":{"pct":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"null when nothing was planned"},"completed":{"type":"integer","minimum":0,"maximum":9007199254740991},"scheduled":{"type":"integer","minimum":0,"maximum":9007199254740991},"parts":{"type":"object","properties":{"training":{"type":"object","properties":{"pct":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"null when nothing was planned"},"completed":{"type":"integer","minimum":0,"maximum":9007199254740991},"scheduled":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["pct","completed","scheduled"],"additionalProperties":false},"nutrition":{"type":"object","properties":{"pct":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"null when nothing was planned"},"completed":{"type":"integer","minimum":0,"maximum":9007199254740991},"scheduled":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["pct","completed","scheduled"],"additionalProperties":false},"habits":{"type":"object","properties":{"pct":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"null when nothing was planned"},"completed":{"type":"integer","minimum":0,"maximum":9007199254740991},"scheduled":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["pct","completed","scheduled"],"additionalProperties":false}},"required":["training"],"additionalProperties":false}},"required":["pct","completed","scheduled","parts"],"additionalProperties":false},"d30":{"type":"object","properties":{"pct":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"null when nothing was planned"},"completed":{"type":"integer","minimum":0,"maximum":9007199254740991},"scheduled":{"type":"integer","minimum":0,"maximum":9007199254740991},"parts":{"type":"object","properties":{"training":{"type":"object","properties":{"pct":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"null when nothing was planned"},"completed":{"type":"integer","minimum":0,"maximum":9007199254740991},"scheduled":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["pct","completed","scheduled"],"additionalProperties":false},"nutrition":{"type":"object","properties":{"pct":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"null when nothing was planned"},"completed":{"type":"integer","minimum":0,"maximum":9007199254740991},"scheduled":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["pct","completed","scheduled"],"additionalProperties":false},"habits":{"type":"object","properties":{"pct":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"null when nothing was planned"},"completed":{"type":"integer","minimum":0,"maximum":9007199254740991},"scheduled":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["pct","completed","scheduled"],"additionalProperties":false}},"required":["training"],"additionalProperties":false}},"required":["pct","completed","scheduled","parts"],"additionalProperties":false},"d90":{"type":"object","properties":{"pct":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"null when nothing was planned"},"completed":{"type":"integer","minimum":0,"maximum":9007199254740991},"scheduled":{"type":"integer","minimum":0,"maximum":9007199254740991},"parts":{"type":"object","properties":{"training":{"type":"object","properties":{"pct":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"null when nothing was planned"},"completed":{"type":"integer","minimum":0,"maximum":9007199254740991},"scheduled":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["pct","completed","scheduled"],"additionalProperties":false},"nutrition":{"type":"object","properties":{"pct":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"null when nothing was planned"},"completed":{"type":"integer","minimum":0,"maximum":9007199254740991},"scheduled":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["pct","completed","scheduled"],"additionalProperties":false},"habits":{"type":"object","properties":{"pct":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"null when nothing was planned"},"completed":{"type":"integer","minimum":0,"maximum":9007199254740991},"scheduled":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["pct","completed","scheduled"],"additionalProperties":false}},"required":["training"],"additionalProperties":false}},"required":["pct","completed","scheduled","parts"],"additionalProperties":false}},"required":["d7","d30","d90"],"additionalProperties":false,"description":"The same windows, shifted back by their length"},"dropFlag":{"type":"boolean","description":"The 30-day figure fell 20 points or more"},"dropPct":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Points the 30-day figure fell by; 0 when it held"}},"required":["windows","previous","dropFlag","dropPct"],"additionalProperties":false},"DietaryProfile":{"type":"object","properties":{"allergens":{"maxItems":14,"type":"array","items":{"type":"string","enum":["gluten","milk","eggs","nuts","peanuts","sesame-seeds","soybeans","fish","crustaceans","molluscs","celery","mustard","lupin","sulphur-dioxide-and-sulphites"]}},"diet":{"maxItems":9,"type":"array","items":{"type":"string","enum":["vegetarian","vegan","pescatarian","halal","kosher","gluten_free","lactose_free","low_carb","keto"]}}},"required":["allergens","diet"],"additionalProperties":false},"FoodFavouriteCreate":{"type":"object","properties":{"offProductId":{"anyOf":[{"type":"string","pattern":"^[cC][^\\s-]{8,}$"},{"type":"null"}]},"customFoodId":{"anyOf":[{"type":"string","pattern":"^[cC][^\\s-]{8,}$"},{"type":"null"}]}},"additionalProperties":false},"FoodRecognise":{"type":"object","properties":{"photoUrl":{"type":"string","minLength":1,"maxLength":2048},"lang":{"type":"string","pattern":"^[a-z]{2}$"}},"required":["photoUrl"],"additionalProperties":false},"FormResponseListResponse":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"formId":{"type":"string"},"clientId":{"type":"string"},"answers":{"type":"string","description":"JSON-encoded answers, keyed by question"},"submittedAt":{"type":"string","description":"ISO-8601 timestamp"},"form":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"}},"required":["id","title"],"additionalProperties":{}},"client":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"avatar":{"type":["string","null"]}},"required":["id","name","avatar"],"additionalProperties":{}}},"required":["id","formId","clientId","answers","submittedAt","form","client"],"additionalProperties":{}}},"FormSign":{"type":"object","properties":{"responseId":{"type":"string","pattern":"^[cC][^\\s-]{8,}$"},"signerName":{"type":"string","minLength":1,"maxLength":200},"waiverAccepted":{"type":"boolean","const":true},"signatureImage":{"type":"string","maxLength":400000,"pattern":"^data:image\\/png;base64,[A-Za-z0-9+/=]+$"}},"required":["responseId","signerName","waiverAccepted"],"additionalProperties":false},"HabitEntryListResponse":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"clientId":{"type":"string"},"habitId":{"type":"string"},"date":{"type":"string","description":"Calendar day, YYYY-MM-DD"},"completed":{"type":"boolean"},"notes":{"type":["string","null"]},"createdAt":{"type":"string","description":"ISO-8601 timestamp"},"habit":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"category":{"type":"string"},"frequency":{"type":"string"},"assigned":{"type":"boolean","description":"False when the coach switched it off for this client"}},"required":["id","name","category","frequency","assigned"],"additionalProperties":false}},"required":["id","clientId","habitId","date","completed","notes","createdAt","habit"],"additionalProperties":{}}},"HabitListResponse":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"trainerId":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"frequency":{"type":"string"},"category":{"type":"string"},"createdAt":{"type":"string","description":"ISO-8601 timestamp"},"updatedAt":{"type":"string","description":"ISO-8601 timestamp"},"entries":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"clientId":{"type":"string"},"habitId":{"type":"string"},"date":{"type":"string","description":"Calendar day, YYYY-MM-DD"},"completed":{"type":"boolean"},"notes":{"type":["string","null"]},"createdAt":{"type":"string","description":"ISO-8601 timestamp"}},"required":["id","clientId","habitId","date","completed","notes","createdAt"],"additionalProperties":{}},"description":"Within `?days=` (default window)"},"unassignments":{"description":"Coach only: clients this habit is switched off for","type":"array","items":{"type":"object","properties":{"clientId":{"type":"string"}},"required":["clientId"],"additionalProperties":false}}},"required":["id","trainerId","name","description","frequency","category","createdAt","updatedAt","entries"],"additionalProperties":{}}},"HabitPackApplyResponse":{"type":"object","properties":{"packSlug":{"type":"string"},"clientIds":{"type":"array","items":{"type":"string"}},"habits":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"packItem":{"type":"string"},"created":{"type":"boolean"}},"required":["id","name","packItem","created"],"additionalProperties":false}}},"required":["packSlug","clientIds","habits"],"additionalProperties":false},"HabitPackApply":{"type":"object","properties":{"clientIds":{"minItems":1,"maxItems":200,"type":"array","items":{"type":"string"}}},"required":["clientIds"],"additionalProperties":false},"MessagePage":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"senderId":{"type":"string"},"receiverId":{"type":"string"},"content":{"type":"string"},"messageType":{"type":"string","enum":["text","image","video","file","encouragement","audio"]},"isRead":{"type":"boolean"},"readAt":{"anyOf":[{"type":"string","description":"ISO-8601 timestamp"},{"type":"null"}],"description":"When the receiver read it (WP-05-03); null while unread, or read before receipts existed"},"badgeCleared":{"type":"boolean","description":"The receiver cleared the unread badge without opening it (mark all read, dismissing the summary, blocking): isRead is true but it was not read. Show a read receipt only for readAt, or isRead without badgeCleared"},"createdAt":{"type":"string","description":"ISO-8601 timestamp"},"conversationId":{"type":["string","null"]},"clientMessageId":{"type":["string","null"]},"durationMs":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Voice note (`audio`) only: its length in milliseconds, at most 420000"},"waveform":{"type":"array","items":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"Voice note only: loudness peaks 0-100, at most 64; empty otherwise"}},"required":["id","senderId","receiverId","content","messageType","isRead","readAt","badgeCleared","createdAt","conversationId","clientMessageId","durationMs","waveform"],"additionalProperties":{}}},"nextCursor":{"description":"Pass as `?cursor=` for the next page; null on the last","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false},"Message":{"type":"object","properties":{"id":{"type":"string"},"senderId":{"type":"string"},"receiverId":{"type":"string"},"content":{"type":"string"},"messageType":{"type":"string","enum":["text","image","video","file","encouragement","audio"]},"isRead":{"type":"boolean"},"readAt":{"anyOf":[{"type":"string","description":"ISO-8601 timestamp"},{"type":"null"}],"description":"When the receiver read it (WP-05-03); null while unread, or read before receipts existed"},"badgeCleared":{"type":"boolean","description":"The receiver cleared the unread badge without opening it (mark all read, dismissing the summary, blocking): isRead is true but it was not read. Show a read receipt only for readAt, or isRead without badgeCleared"},"createdAt":{"type":"string","description":"ISO-8601 timestamp"},"conversationId":{"type":["string","null"]},"clientMessageId":{"type":["string","null"]},"durationMs":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Voice note (`audio`) only: its length in milliseconds, at most 420000"},"waveform":{"type":"array","items":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"Voice note only: loudness peaks 0-100, at most 64; empty otherwise"}},"required":["id","senderId","receiverId","content","messageType","isRead","readAt","badgeCleared","createdAt","conversationId","clientMessageId","durationMs","waveform"],"additionalProperties":{}},"MetricDefinitionPage":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"trainerId":{"type":"string"},"name":{"type":"string"},"unit":{"type":"string"},"archivedAt":{"anyOf":[{"type":"string","description":"ISO-8601 timestamp"},{"type":"null"}]},"createdAt":{"type":"string","description":"ISO-8601 timestamp"},"updatedAt":{"type":"string","description":"ISO-8601 timestamp"}},"required":["id","trainerId","name","unit","archivedAt","createdAt","updatedAt"],"additionalProperties":false}},"nextCursor":{"description":"Pass as `?cursor=` for the next page; null on the last","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false},"MetricEntryDetail":{"type":"object","properties":{"id":{"type":"string"},"clientId":{"type":"string"},"date":{"type":"string","description":"Calendar day, YYYY-MM-DD"},"metricType":{"type":"string"},"value":{"type":"number"},"unit":{"type":"string"},"notes":{"type":["string","null"]},"definitionId":{"type":["string","null"]},"createdAt":{"type":"string","description":"ISO-8601 timestamp"},"updatedAt":{"type":"string","description":"ISO-8601 timestamp"},"client":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"avatar":{"type":["string","null"]}},"required":["id","name","avatar"],"additionalProperties":{}}},"required":["id","clientId","date","metricType","value","unit","notes","definitionId","createdAt","updatedAt","client"],"additionalProperties":{}},"MetricEntryPage":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"clientId":{"type":"string"},"date":{"type":"string","description":"Calendar day, YYYY-MM-DD"},"metricType":{"type":"string"},"value":{"type":"number"},"unit":{"type":"string"},"notes":{"type":["string","null"]},"definitionId":{"type":["string","null"]},"createdAt":{"type":"string","description":"ISO-8601 timestamp"},"updatedAt":{"type":"string","description":"ISO-8601 timestamp"},"definition":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"unit":{"type":"string"},"archivedAt":{"anyOf":[{"type":"string","description":"ISO-8601 timestamp"},{"type":"null"}]}},"required":["id","name","unit","archivedAt"],"additionalProperties":false},{"type":"null"}]}},"required":["id","clientId","date","metricType","value","unit","notes","definitionId","createdAt","updatedAt","definition"],"additionalProperties":{}}},"nextCursor":{"description":"Pass as `?cursor=` for the next page; null on the last","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false},"NpsResponseCreated":{"type":"object","properties":{"id":{"type":"string"},"score":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"null for a dismissal"},"createdAt":{"type":"string","description":"ISO-8601 timestamp"}},"required":["id","score","createdAt"],"additionalProperties":{}},"NpsState":{"type":"object","properties":{"enabled":{"type":"boolean","description":"NPS_ENABLED is on"},"eligible":{"type":"boolean","description":"The caller is due the prompt now"}},"required":["enabled","eligible"],"additionalProperties":false},"NpsSubmit":{"anyOf":[{"type":"object","properties":{"score":{"type":"integer","minimum":0,"maximum":10},"comment":{"type":"string","maxLength":1000}},"required":["score"],"additionalProperties":false},{"type":"object","properties":{"dismissed":{"type":"boolean","const":true}},"required":["dismissed"],"additionalProperties":false}]},"NutritionComplianceResponse":{"type":"object","properties":{"clientId":{"type":"string"},"endDate":{"type":"string","description":"Calendar day, YYYY-MM-DD"},"days":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","description":"Calendar day, YYYY-MM-DD"},"status":{"type":"string","enum":["on_track","over","under","not_logged"]},"calories":{"type":"number"},"targetCalories":{"type":"number"},"loggedMeals":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["date","status","calories","targetCalories","loggedMeals"],"additionalProperties":false}},"compliancePct":{"type":"integer","minimum":0,"maximum":100},"thresholdPct":{"type":"number"},"daysLogged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"avgCalories":{"type":["number","null"]},"avgProtein":{"type":["number","null"]},"avgCarbs":{"type":["number","null"]},"avgFat":{"type":["number","null"]}},"required":["clientId","endDate","days","compliancePct","thresholdPct","daysLogged","avgCalories","avgProtein","avgCarbs","avgFat"],"additionalProperties":false},"NutritionCopy":{"type":"object","properties":{"clientId":{"type":"string"},"from":{"type":"object","properties":{"date":{"type":"string"},"mealType":{"type":"string","enum":["breakfast","lunch","dinner","snack"]}},"required":["date"],"additionalProperties":false},"to":{"type":"object","properties":{"date":{"type":"string"},"mealType":{"type":"string","enum":["breakfast","lunch","dinner","snack"]}},"required":["date"],"additionalProperties":false},"mode":{"type":"string","enum":["append","replace"]}},"required":["from","to"],"additionalProperties":false},"NutritionDaySummaryResponse":{"type":"object","properties":{"clientId":{"type":"string"},"date":{"type":"string","description":"Calendar day, YYYY-MM-DD"},"calories":{"type":"number"},"protein":{"type":"number"},"carbs":{"type":"number"},"fat":{"type":"number"},"fiber":{"type":"number"},"entryCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"goals":{"type":"object","properties":{"calories":{"type":"number"},"protein":{"type":"number"},"carbs":{"type":"number"},"fat":{"type":"number"}},"required":["calories","protein","carbs","fat"],"additionalProperties":{}},"targetSource":{"type":"string","enum":["override","dayType","set","onboarding","default"],"description":"Where the goals come from; treat an unknown value as \"set\""},"dayType":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]},"meals":{"type":"object","properties":{"breakfast":{"type":"object","properties":{"calories":{"type":"number"},"protein":{"type":"number"},"carbs":{"type":"number"},"fat":{"type":"number"},"fiber":{"type":"number"},"sugar":{"type":"number"},"saturatedFat":{"type":"number"},"sodiumMg":{"type":"number"},"entryCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"partial":{"type":"boolean","description":"An entry in the meal leaves sugar, saturated fat or sodium unknown"}},"required":["calories","protein","carbs","fat","fiber","sugar","saturatedFat","sodiumMg","entryCount","partial"],"additionalProperties":false},"lunch":{"type":"object","properties":{"calories":{"type":"number"},"protein":{"type":"number"},"carbs":{"type":"number"},"fat":{"type":"number"},"fiber":{"type":"number"},"sugar":{"type":"number"},"saturatedFat":{"type":"number"},"sodiumMg":{"type":"number"},"entryCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"partial":{"type":"boolean","description":"An entry in the meal leaves sugar, saturated fat or sodium unknown"}},"required":["calories","protein","carbs","fat","fiber","sugar","saturatedFat","sodiumMg","entryCount","partial"],"additionalProperties":false},"dinner":{"type":"object","properties":{"calories":{"type":"number"},"protein":{"type":"number"},"carbs":{"type":"number"},"fat":{"type":"number"},"fiber":{"type":"number"},"sugar":{"type":"number"},"saturatedFat":{"type":"number"},"sodiumMg":{"type":"number"},"entryCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"partial":{"type":"boolean","description":"An entry in the meal leaves sugar, saturated fat or sodium unknown"}},"required":["calories","protein","carbs","fat","fiber","sugar","saturatedFat","sodiumMg","entryCount","partial"],"additionalProperties":false},"snack":{"type":"object","properties":{"calories":{"type":"number"},"protein":{"type":"number"},"carbs":{"type":"number"},"fat":{"type":"number"},"fiber":{"type":"number"},"sugar":{"type":"number"},"saturatedFat":{"type":"number"},"sodiumMg":{"type":"number"},"entryCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"partial":{"type":"boolean","description":"An entry in the meal leaves sugar, saturated fat or sodium unknown"}},"required":["calories","protein","carbs","fat","fiber","sugar","saturatedFat","sodiumMg","entryCount","partial"],"additionalProperties":false}},"required":["breakfast","lunch","dinner","snack"],"additionalProperties":false},"extras":{"type":"object","properties":{"sugar":{"type":"number"},"saturatedFat":{"type":"number"},"sodiumMg":{"type":"number"},"partialNutrients":{"type":"array","items":{"type":"string","enum":["sugar","sodium","saturatedFat"]}}},"required":["sugar","saturatedFat","sodiumMg","partialNutrients"],"additionalProperties":false},"remaining":{"type":"object","properties":{"calories":{"type":"number"},"protein":{"type":"number"},"carbs":{"type":"number"},"fat":{"type":"number"}},"required":["calories","protein","carbs","fat"],"additionalProperties":false,"description":"Goal minus eaten; negative when over"},"water":{"type":"object","properties":{"ml":{"type":"number"},"goalMl":{"type":"number"}},"required":["ml","goalMl"],"additionalProperties":false}},"required":["clientId","date","calories","protein","carbs","fat","fiber","entryCount","goals","targetSource","dayType","meals","extras","remaining","water"],"additionalProperties":false},"NutritionFromPlan":{"type":"object","properties":{"clientId":{"type":"string"},"planId":{"type":"string","pattern":"^[cC][^\\s-]{8,}$"},"mealPlanMealId":{"type":"string","pattern":"^[cC][^\\s-]{8,}$"},"date":{"type":"string"},"servings":{"type":"number","minimum":0.25,"maximum":50},"loggedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},{"type":"null"}]},"force":{"type":"boolean"}},"required":["planId","mealPlanMealId","date"],"additionalProperties":false},"NutritionTargetOverride":{"type":"object","properties":{"date":{"type":"string"},"dayTypeId":{"anyOf":[{"type":"string","pattern":"^[cC][^\\s-]{8,}$"},{"type":"null"}]},"calories":{"anyOf":[{"type":"integer","minimum":500,"maximum":10000},{"type":"null"}]}},"required":["date","dayTypeId"],"additionalProperties":false},"NutritionWeeklyReportResponse":{"type":"object","properties":{"clientId":{"type":"string"},"weekStart":{"type":"string","description":"Calendar day, YYYY-MM-DD"},"weekEnd":{"type":"string","description":"Calendar day, YYYY-MM-DD"},"daysLogged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"compliancePct":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"averages":{"type":"object","properties":{"calories":{"type":["number","null"]},"protein":{"type":["number","null"]},"carbs":{"type":["number","null"]},"fat":{"type":["number","null"]},"fiber":{"type":["number","null"]},"sugar":{"type":["number","null"]},"saturatedFat":{"type":["number","null"]},"sodiumMg":{"type":["number","null"]},"waterMl":{"type":["number","null"]}},"required":["calories","protein","carbs","fat","fiber","sugar","saturatedFat","sodiumMg","waterMl"],"additionalProperties":false},"targets":{"type":"object","properties":{"calories":{"type":"number"},"protein":{"type":"number"},"carbs":{"type":"number"},"fat":{"type":"number"}},"required":["calories","protein","carbs","fat"],"additionalProperties":false},"bestDay":{"anyOf":[{"type":"object","properties":{"date":{"type":"string","description":"Calendar day, YYYY-MM-DD"},"calories":{"type":"number"}},"required":["date","calories"],"additionalProperties":false},{"type":"null"}]},"worstDay":{"anyOf":[{"type":"object","properties":{"date":{"type":"string","description":"Calendar day, YYYY-MM-DD"},"calories":{"type":"number"}},"required":["date","calories"],"additionalProperties":false},{"type":"null"}]},"topFoods":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"calories":{"type":"number"},"source":{"type":"string"}},"required":["name","count","calories","source"],"additionalProperties":false}},"photosLogged":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"comments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"body":{"type":"string"},"createdAt":{"type":"string","description":"ISO-8601 timestamp"}},"required":["id","body","createdAt"],"additionalProperties":{}}},"partialNutrients":{"type":"array","items":{"type":"string"}},"attribution":{"anyOf":[{"type":"object","properties":{"text":{"type":"string"},"url":{"type":"string"}},"required":["text","url"],"additionalProperties":{}},{"type":"null"}]}},"required":["clientId","weekStart","weekEnd","daysLogged","compliancePct","averages","targets","bestDay","worstDay","topFoods","photosLogged","comments","partialNutrients","attribution"],"additionalProperties":false},"ParqFormCreate":{"type":"object","properties":{"assignOnJoin":{"type":"boolean"}},"additionalProperties":false},"ParqFormSummary":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"assignOnJoin":{"type":"boolean"}},"required":["id","title","assignOnJoin"],"additionalProperties":false},"PublicBookingPageSettings":{"type":"object","properties":{"enabled":{"type":"boolean"},"slug":{"type":["string","null"]}},"required":["enabled","slug"],"additionalProperties":false},"PublicBookingPageUpdate":{"type":"object","properties":{"enabled":{"type":"boolean"},"slug":{"type":"string","minLength":3,"maxLength":40,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$"}},"additionalProperties":false},"ReadinessResponse":{"type":"object","properties":{"date":{"type":"string"},"score":{"anyOf":[{"type":"integer","minimum":0,"maximum":100},{"type":"null"}],"description":"null without sleep or a check-in"},"band":{"anyOf":[{"type":"string","enum":["low","medium","high"]},{"type":"null"}]},"inputs":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","enum":["sleep","wellbeing","load","hrv"]},"value":{"type":"number"},"contribution":{"type":"number","description":"Points of the score; the contributions add up to it"}},"required":["key","value","contribution"],"additionalProperties":false}},"missing":{"type":"array","items":{"type":"string","enum":["sleep","wellbeing","load","hrv"]}}},"required":["date","score","band","inputs","missing"],"additionalProperties":false},"RecipeLog":{"type":"object","properties":{"clientId":{"type":"string"},"date":{"type":"string"},"mealType":{"type":"string","enum":["breakfast","lunch","dinner","snack"]},"servings":{"type":"number","minimum":0.25,"maximum":50},"loggedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},{"type":"null"}]},"photoUrl":{"anyOf":[{"type":"string","minLength":1,"maxLength":2048},{"type":"null"}]}},"required":["date","mealType"],"additionalProperties":false},"ReferralSummary":{"type":"object","properties":{"code":{"type":"string","description":"The coach referral code, 8 characters"},"link":{"type":"string","description":"Sign-up link carrying the code"},"referred":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Coaches who signed up with it"},"rewards":{"type":"array","items":{"type":"object","properties":{"amountMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"currency":{"type":"string"}},"required":["amountMinor","currency"],"additionalProperties":false},"description":"Ledger totals per currency; 0 unless a reward is configured"}},"required":["code","link","referred","rewards"],"additionalProperties":false},"SignedDocumentCreated":{"type":"object","properties":{"id":{"type":"string"},"formId":{"type":["string","null"]},"responseId":{"type":["string","null"]},"userId":{"type":"string"},"signerName":{"type":"string"},"signedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"sha256":{"type":"string","pattern":"^[0-9a-f]{64}$"},"pdfUrl":{"type":"string"},"textUrl":{"type":"string"}},"required":["id","formId","responseId","userId","signerName","signedAt","sha256","pdfUrl","textUrl"],"additionalProperties":false},"SignedDocumentView":{"type":"object","properties":{"id":{"type":"string"},"formId":{"type":["string","null"]},"responseId":{"type":["string","null"]},"userId":{"type":"string"},"signerName":{"type":"string"},"signedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"sha256":{"type":"string","pattern":"^[0-9a-f]{64}$"},"intact":{"type":"boolean"},"hasDrawnSignature":{"type":"boolean"},"pdfUrl":{"type":"string"},"textUrl":{"type":"string"}},"required":["id","formId","responseId","userId","signerName","signedAt","sha256","intact","hasDrawnSignature","pdfUrl","textUrl"],"additionalProperties":false},"StudioAuditPage":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"action":{"type":"string"},"actor":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]},"targetType":{"type":["string","null"]},"targetId":{"type":["string","null"]},"metadata":{},"createdAt":{"type":"string","description":"ISO-8601 timestamp"}},"required":["id","action","actor","targetType","targetId","metadata","createdAt"],"additionalProperties":{}}},"nextCursor":{"description":"Pass as `?cursor=` for the next page","type":["string","null"]},"staff":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},"description":"The studio's coaches, for the actor filter"}},"required":["items","nextCursor","staff"],"additionalProperties":false},"VoiceNotesConfig":{"type":"object","properties":{"enabled":{"type":"boolean","description":"`VOICE_NOTES_ENABLED` on this deployment"},"maxDurationMs":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"maxBytes":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"mimeTypes":{"type":"array","items":{"type":"string"}},"waveformPoints":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["enabled","maxDurationMs","maxBytes","mimeTypes","waveformPoints"],"additionalProperties":false},"WaterUpsert":{"type":"object","properties":{"clientId":{"type":"string"},"date":{"type":"string"},"glasses":{"type":"integer","minimum":0,"maximum":32},"ml":{"type":"integer","minimum":0,"maximum":20000},"addMl":{"type":"integer","minimum":-5000,"maximum":5000}},"required":["date"],"additionalProperties":false},"WebhookDeleteResponse":{"type":"object","properties":{"deleted":{"type":"boolean","const":true}},"required":["deleted"],"additionalProperties":false},"WebhookDeliveryList":{"maxItems":50,"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"event":{"type":"string"},"status":{"type":"string","enum":["pending","delivered","failed"]},"attempts":{"type":"integer","minimum":0,"maximum":9007199254740991},"lastStatusCode":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"lastError":{"type":["string","null"]},"createdAt":{"type":"string"},"deliveredAt":{"type":["string","null"]},"nextAttemptAt":{"type":"string"},"replayOfId":{"description":"The delivery this one replays","type":["string","null"]}},"required":["id","event","status","attempts","lastStatusCode","lastError","createdAt","deliveredAt","nextAttemptAt","replayOfId"],"additionalProperties":false}},"WebhookEndpointCreate":{"type":"object","properties":{"url":{"type":"string","minLength":1,"maxLength":2048},"events":{"minItems":1,"maxItems":5,"type":"array","items":{"type":"string","enum":["workout.completed","checkin.submitted","booking.created","booking.cancelled","client.joined"]}}},"required":["url","events"],"additionalProperties":false},"WebhookEndpointCreated":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"events":{"type":"array","items":{"type":"string"}},"active":{"type":"boolean"},"consecutiveFailures":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Final failed deliveries in a row since the last success"},"disabledAt":{"description":"When NetFit switched the endpoint off after repeated failures","type":["string","null"]},"disabledReason":{"anyOf":[{"type":"string","enum":["consecutive_failures"]},{"type":"null"}]},"secretRotatedAt":{"type":["string","null"]},"previousSecretExpiresAt":{"description":"Until when deliveries also carry a v1 signed with the previous secret","type":["string","null"]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"secret":{"type":"string","format":"starts_with","pattern":"^whsec_.*"}},"required":["id","url","events","active","consecutiveFailures","disabledAt","disabledReason","secretRotatedAt","previousSecretExpiresAt","createdAt","updatedAt","secret"],"additionalProperties":false},"WebhookEndpointList":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"events":{"type":"array","items":{"type":"string"}},"active":{"type":"boolean"},"consecutiveFailures":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Final failed deliveries in a row since the last success"},"disabledAt":{"description":"When NetFit switched the endpoint off after repeated failures","type":["string","null"]},"disabledReason":{"anyOf":[{"type":"string","enum":["consecutive_failures"]},{"type":"null"}]},"secretRotatedAt":{"type":["string","null"]},"previousSecretExpiresAt":{"description":"Until when deliveries also carry a v1 signed with the previous secret","type":["string","null"]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","url","events","active","consecutiveFailures","disabledAt","disabledReason","secretRotatedAt","previousSecretExpiresAt","createdAt","updatedAt"],"additionalProperties":false}},"WebhookEndpoint":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"events":{"type":"array","items":{"type":"string"}},"active":{"type":"boolean"},"consecutiveFailures":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Final failed deliveries in a row since the last success"},"disabledAt":{"description":"When NetFit switched the endpoint off after repeated failures","type":["string","null"]},"disabledReason":{"anyOf":[{"type":"string","enum":["consecutive_failures"]},{"type":"null"}]},"secretRotatedAt":{"type":["string","null"]},"previousSecretExpiresAt":{"description":"Until when deliveries also carry a v1 signed with the previous secret","type":["string","null"]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","url","events","active","consecutiveFailures","disabledAt","disabledReason","secretRotatedAt","previousSecretExpiresAt","createdAt","updatedAt"],"additionalProperties":false},"WebhookEndpointUpdate":{"type":"object","properties":{"url":{"type":"string","minLength":1,"maxLength":2048},"events":{"minItems":1,"maxItems":5,"type":"array","items":{"type":"string","enum":["workout.completed","checkin.submitted","booking.created","booking.cancelled","client.joined"]}},"active":{"type":"boolean"}},"additionalProperties":false},"WebhookReplayResponse":{"type":"object","properties":{"id":{"type":"string"},"event":{"type":"string"},"status":{"type":"string","const":"pending"},"createdAt":{"type":"string"},"replayOfId":{"type":"string"}},"required":["id","event","status","createdAt","replayOfId"],"additionalProperties":false},"WebhookSecretRotate":{"type":"object","properties":{"revokePrevious":{"type":"boolean"}},"additionalProperties":false},"WebhookSecretRotated":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"events":{"type":"array","items":{"type":"string"}},"active":{"type":"boolean"},"consecutiveFailures":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Final failed deliveries in a row since the last success"},"disabledAt":{"description":"When NetFit switched the endpoint off after repeated failures","type":["string","null"]},"disabledReason":{"anyOf":[{"type":"string","enum":["consecutive_failures"]},{"type":"null"}]},"secretRotatedAt":{"type":["string","null"]},"previousSecretExpiresAt":{"description":"Until when deliveries also carry a v1 signed with the previous secret","type":["string","null"]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"secret":{"type":"string","format":"starts_with","pattern":"^whsec_.*"}},"required":["id","url","events","active","consecutiveFailures","disabledAt","disabledReason","secretRotatedAt","previousSecretExpiresAt","createdAt","updatedAt","secret"],"additionalProperties":false},"WebhookTestResponse":{"type":"object","properties":{"id":{"type":"string"},"event":{"type":"string","const":"ping"},"status":{"type":"string","const":"pending"},"createdAt":{"type":"string"}},"required":["id","event","status","createdAt"],"additionalProperties":false},"WorkoutListResponse":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"trainerId":{"type":["string","null"]},"name":{"type":"string"},"description":{"type":["string","null"]},"category":{"type":["string","null"]},"difficulty":{"type":"string"},"estimatedDuration":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Minutes"},"isTemplate":{"type":"boolean"},"createdAt":{"type":"string","description":"ISO-8601 timestamp"},"updatedAt":{"type":"string","description":"ISO-8601 timestamp"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"workoutId":{"type":"string"},"exerciseId":{"type":"string"},"sets":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"reps":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"weight":{"type":["number","null"]},"restTime":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"duration":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"notes":{"type":["string","null"]},"exercise":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"category":{"type":["string","null"]}},"required":["id","name","category"],"additionalProperties":{}}},"required":["id","workoutId","exerciseId","sets","reps","weight","restTime","duration","order","notes","exercise"],"additionalProperties":{}}}},"required":["id","trainerId","name","description","category","difficulty","estimatedDuration","isTemplate","createdAt","updatedAt","items"],"additionalProperties":{}}},"WorkoutLogPage":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"clientId":{"type":"string"},"workoutId":{"type":["string","null"]},"name":{"type":"string"},"date":{"type":"string","description":"Calendar day, YYYY-MM-DD"},"duration":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"notes":{"type":["string","null"]},"calories":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"createdAt":{"type":"string","description":"ISO-8601 timestamp"},"updatedAt":{"type":"string","description":"ISO-8601 timestamp"},"exercises":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"exerciseId":{"type":["string","null"]},"exerciseName":{"type":"string"},"sets":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"reps":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"weight":{"type":["number","null"]},"duration":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"setLog":{"description":"With `?include=setLog`","type":["string","null"]}},"required":["id","exerciseId","exerciseName","sets","reps","weight","duration","order"],"additionalProperties":{}}}},"required":["id","clientId","workoutId","name","date","duration","notes","calories","createdAt","updatedAt","exercises"],"additionalProperties":{}}},"nextCursor":{"description":"Pass as `?cursor=` for the next page; null on the last","type":["string","null"]}},"required":["items","nextCursor"],"additionalProperties":false},"WorkoutLog":{"type":"object","properties":{"id":{"type":"string"},"clientId":{"type":"string"},"workoutId":{"type":["string","null"]},"name":{"type":"string"},"date":{"type":"string","description":"Calendar day, YYYY-MM-DD"},"duration":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"notes":{"type":["string","null"]},"calories":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"createdAt":{"type":"string","description":"ISO-8601 timestamp"},"updatedAt":{"type":"string","description":"ISO-8601 timestamp"},"exercises":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"exerciseId":{"type":["string","null"]},"exerciseName":{"type":"string"},"sets":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"reps":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"weight":{"type":["number","null"]},"duration":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"setLog":{"description":"With `?include=setLog`","type":["string","null"]}},"required":["id","exerciseId","exerciseName","sets","reps","weight","duration","order"],"additionalProperties":{}}}},"required":["id","clientId","workoutId","name","date","duration","notes","calories","createdAt","updatedAt","exercises"],"additionalProperties":{}},"Workout":{"type":"object","properties":{"id":{"type":"string"},"trainerId":{"type":["string","null"]},"name":{"type":"string"},"description":{"type":["string","null"]},"category":{"type":["string","null"]},"difficulty":{"type":"string"},"estimatedDuration":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Minutes"},"isTemplate":{"type":"boolean"},"createdAt":{"type":"string","description":"ISO-8601 timestamp"},"updatedAt":{"type":"string","description":"ISO-8601 timestamp"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"workoutId":{"type":"string"},"exerciseId":{"type":"string"},"sets":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"reps":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"weight":{"type":["number","null"]},"restTime":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"duration":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"notes":{"type":["string","null"]},"exercise":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"category":{"type":["string","null"]}},"required":["id","name","category"],"additionalProperties":{}}},"required":["id","workoutId","exerciseId","sets","reps","weight","restTime","duration","order","notes","exercise"],"additionalProperties":{}}}},"required":["id","trainerId","name","description","category","difficulty","estimatedDuration","isTemplate","createdAt","updatedAt","items"],"additionalProperties":{}}}}}