{"openapi":"3.1.0","info":{"title":"Athly API","description":"Backend API for the Athly fitness coaching platform","version":"0.1.0"},"paths":{"/auth/login":{"post":{"tags":["auth"],"summary":"Login","description":"Sign in with email and password. Returns a Supabase session.\n\nThrottled from the same password-attempt budget as ``/onboarding/signup``,\nspent only by wrong credentials, so a correct sign-in is never slowed. A\nvalid ``device_token`` (issued with every successful sign-in) moves the\nattempt onto that device's own budget, so guesses from elsewhere cannot\nlock the owner out.","operationId":"login_auth_login_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/refresh":{"post":{"tags":["auth"],"summary":"Refresh","description":"Refresh an access token using a refresh token.","operationId":"refresh_auth_refresh_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/dev/recovery-link":{"post":{"tags":["auth"],"summary":"Development Password Recovery Link","description":"Generate a recovery URL locally without sending an email.","operationId":"development_password_recovery_link_auth_dev_recovery_link_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DevelopmentPasswordRecoveryRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DevelopmentPasswordRecoveryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/dev/signup-link":{"post":{"tags":["auth"],"summary":"Development Signup Link","description":"Generate a signup confirmation URL locally without sending an email.","operationId":"development_signup_link_auth_dev_signup_link_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DevelopmentSignupRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DevelopmentSignupResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/subscription":{"get":{"tags":["billing"],"summary":"Get Subscription","description":"This pair's subscription, or ``null``.\n\n``null`` is a real answer rather than a 404: it is the state a\nfully-cancelled athlete lands in, and the screen has something to say about\nit.","operationId":"get_subscription_billing_subscription_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"athlete_slug","in":"query","required":true,"schema":{"type":"string","title":"Athlete Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/pause":{"post":{"tags":["billing"],"summary":"Pause Subscription","description":"Pause now, banking the days already paid for.","operationId":"pause_subscription_billing_pause_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionActionRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/billing/cancel":{"post":{"tags":["billing"],"summary":"Cancel Subscription","description":"Cancel at the end of the paid period. The request is immediate; the\ncancellation is not.","operationId":"cancel_subscription_billing_cancel_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionActionRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/billing/resume":{"post":{"tags":["billing"],"summary":"Resume Subscription","description":"Un-pause, or take back a pending cancellation.","operationId":"resume_subscription_billing_resume_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionActionRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionRead"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/billing/checkout-url":{"get":{"tags":["billing"],"summary":"Get Checkout Url","description":"Where to start paying again once a cancellation has elapsed.\n\nResolved server-side so the onboarding origin and shared secret stay out of\nthe bundle. What comes back is a link for the screen to render, not a\nredirect to follow.","operationId":"get_checkout_url_billing_checkout_url_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"athlete_slug","in":"query","required":true,"schema":{"type":"string","title":"Athlete Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutUrlResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/athletes/":{"get":{"tags":["athletes"],"summary":"List Athletes","operationId":"list_athletes_athletes__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/AthleteListItem"},"type":"array","title":"Response List Athletes Athletes  Get"}}}}}}},"/athletes/mine":{"get":{"tags":["athletes"],"summary":"List My Athletes","description":"The athletes this user actually trains with.\n\nA separate endpoint rather than a filter on the list above, deliberately.\nThat one is the public marketplace; filtering it per user would put a\nper-user body on a public endpoint, which the next person to re-add\nresponse caching there would serve to the wrong person. So this one is\n``private, no-store`` and that one stays anonymous.\n\nNever gated, and it lists locked athletes too: a paused athlete missing from\nthe roster would leave no route to the screen that resumes them.","operationId":"list_my_athletes_athletes_mine_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/SubscribedAthlete"},"type":"array","title":"Response List My Athletes Athletes Mine Get"}}}}},"security":[{"HTTPBearer":[]}]}},"/athletes/resolve/{slug}":{"get":{"tags":["athletes"],"summary":"Resolve Athlete Slug","operationId":"resolve_athlete_slug_athletes_resolve__slug__get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AthleteResolveResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/analysis/videos":{"get":{"tags":["analysis"],"summary":"List Videos","operationId":"list_videos_analysis_videos_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"athlete_slug","in":"query","required":true,"schema":{"type":"string","title":"Athlete Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AnalysisVideoResponse"},"title":"Response List Videos Analysis Videos Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["analysis"],"summary":"Create Video Upload","operationId":"create_video_upload_analysis_videos_post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalysisVideoCreateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalysisVideoResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/analysis/videos/{video_id}/complete":{"post":{"tags":["analysis"],"summary":"Complete Video Upload","operationId":"complete_video_upload_analysis_videos__video_id__complete_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"video_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Video Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalysisVideoUploadCompleteRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalysisVideoResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/analysis/videos/{video_id}":{"get":{"tags":["analysis"],"summary":"Get Video","operationId":"get_video_analysis_videos__video_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"video_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Video Id"}},{"name":"athlete_slug","in":"query","required":true,"schema":{"type":"string","title":"Athlete Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalysisVideoResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/analysis/videos/{video_id}/runs":{"get":{"tags":["analysis"],"summary":"List Runs","operationId":"list_runs_analysis_videos__video_id__runs_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"video_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Video Id"}},{"name":"athlete_slug","in":"query","required":true,"schema":{"type":"string","title":"Athlete Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AnalysisRunResponse"},"title":"Response List Runs Analysis Videos  Video Id  Runs Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/analysis/runs":{"post":{"tags":["analysis"],"summary":"Create Run","operationId":"create_run_analysis_runs_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalysisRunCreateRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalysisRunResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/analysis/runs/{run_id}":{"get":{"tags":["analysis"],"summary":"Get Run","operationId":"get_run_analysis_runs__run_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Run Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalysisRunResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/freeplay/chat":{"post":{"tags":["freeplay"],"summary":"Freeplay Chat","operationId":"freeplay_chat_freeplay_chat_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"diagnostics","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Diagnostics"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FreeplayChatRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FreeplayChatResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/freeplay/readiness":{"get":{"tags":["freeplay"],"summary":"Freeplay Readiness Check","operationId":"freeplay_readiness_check_freeplay_readiness_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"athlete_slug","in":"query","required":true,"schema":{"type":"string","title":"Athlete Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FreeplayReadinessResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/harness/thread":{"get":{"tags":["harness"],"summary":"Get Thread","operationId":"get_thread_harness_thread_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"since_seq","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Since Seq"}},{"name":"athlete_slug","in":"query","required":true,"schema":{"type":"string","title":"Athlete Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarnessThreadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/harness/calls/{call_id}":{"get":{"tags":["harness"],"summary":"Get Call","description":"A voice call's transcript, read when its card is opened (ATH-531).","operationId":"get_call_harness_calls__call_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"call_id","in":"path","required":true,"schema":{"type":"string","title":"Call Id"}},{"name":"athlete_slug","in":"query","required":true,"schema":{"type":"string","title":"Athlete Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarnessCallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/harness/send":{"post":{"tags":["harness"],"summary":"Send","operationId":"send_harness_send_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarnessSendRequest"}}},"required":true},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarnessSendResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/harness/unread":{"get":{"tags":["harness"],"summary":"Get Unread","operationId":"get_unread_harness_unread_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"athlete_slug","in":"query","required":true,"schema":{"type":"string","title":"Athlete Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarnessUnreadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/harness/read":{"post":{"tags":["harness"],"summary":"Mark Read","operationId":"mark_read_harness_read_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarnessReadRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarnessUnreadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/harness/checkin-ask/dismiss":{"post":{"tags":["harness"],"summary":"Dismiss Checkin Ask","operationId":"dismiss_checkin_ask_harness_checkin_ask_dismiss_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarnessCheckinAskDismissRequest"}}},"required":true},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/harness/enroll":{"post":{"tags":["harness"],"summary":"Enroll","operationId":"enroll_harness_enroll_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarnessEnrollRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarnessEnrollResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/harness/profile":{"get":{"tags":["harness"],"summary":"Get Profile","operationId":"get_profile_harness_profile_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"athlete_slug","in":"query","required":true,"schema":{"type":"string","title":"Athlete Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarnessProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["harness"],"summary":"Patch Profile","operationId":"patch_profile_harness_profile_patch","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarnessProfilePatchRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarnessPlanProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/harness/plan":{"get":{"tags":["harness"],"summary":"Get Plan","operationId":"get_plan_harness_plan_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"athlete_slug","in":"query","required":true,"schema":{"type":"string","title":"Athlete Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarnessPlanStateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/harness/plan/open":{"post":{"tags":["harness"],"summary":"Open Plan","operationId":"open_plan_harness_plan_open_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarnessPlanOpenRequest"}}},"required":true},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarnessPlanStateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/harness/week":{"get":{"tags":["harness"],"summary":"Get Week","operationId":"get_week_harness_week_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"week_start","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Week Start"}},{"name":"athlete_slug","in":"query","required":true,"schema":{"type":"string","title":"Athlete Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarnessWeekResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/harness/session":{"get":{"tags":["harness"],"summary":"Get Session Entry","operationId":"get_session_entry_harness_session_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"entry","in":"query","required":true,"schema":{"type":"string","title":"Entry"}},{"name":"athlete_slug","in":"query","required":true,"schema":{"type":"string","title":"Athlete Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarnessSessionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/harness/sessions/start":{"post":{"tags":["harness"],"summary":"Start Session","operationId":"start_session_harness_sessions_start_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarnessStartRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarnessSessionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/harness/sessions/{log_id}/sets/{exercise_key}/{set_index}":{"put":{"tags":["harness"],"summary":"Rate Set","operationId":"rate_set_harness_sessions__log_id__sets__exercise_key___set_index__put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"log_id","in":"path","required":true,"schema":{"type":"string","title":"Log Id"}},{"name":"exercise_key","in":"path","required":true,"schema":{"type":"string","title":"Exercise Key"}},{"name":"set_index","in":"path","required":true,"schema":{"type":"integer","title":"Set Index"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarnessSetWriteRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarnessSessionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["harness"],"summary":"Void Set","operationId":"void_set_harness_sessions__log_id__sets__exercise_key___set_index__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"log_id","in":"path","required":true,"schema":{"type":"string","title":"Log Id"}},{"name":"exercise_key","in":"path","required":true,"schema":{"type":"string","title":"Exercise Key"}},{"name":"set_index","in":"path","required":true,"schema":{"type":"integer","title":"Set Index"}},{"name":"athlete_slug","in":"query","required":true,"schema":{"type":"string","title":"Athlete Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarnessSessionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/harness/sessions/{log_id}":{"patch":{"tags":["harness"],"summary":"Set Session Felt","operationId":"set_session_felt_harness_sessions__log_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"log_id","in":"path","required":true,"schema":{"type":"string","title":"Log Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarnessFeltRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarnessSessionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/harness/push/public-key":{"get":{"tags":["harness"],"summary":"Push Public Key","operationId":"push_public_key_harness_push_public_key_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"athlete_slug","in":"query","required":true,"schema":{"type":"string","title":"Athlete Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushPublicKeyResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/harness/push/subscription":{"put":{"tags":["harness"],"summary":"Save Push Subscription","operationId":"save_push_subscription_harness_push_subscription_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushSubscriptionRequest"}}},"required":true},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]},"delete":{"tags":["harness"],"summary":"Delete Push Subscription","operationId":"delete_push_subscription_harness_push_subscription_delete","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushSubscriptionDeleteRequest"}}},"required":true},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/harness/admin/diagnostics":{"get":{"tags":["harness"],"summary":"Get Turn Diagnostics","operationId":"get_turn_diagnostics_harness_admin_diagnostics_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":100,"title":"Limit"}},{"name":"athlete_slug","in":"query","required":true,"schema":{"type":"string","title":"Athlete Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarnessTurnDiagnosticsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/harness/admin/trace":{"get":{"tags":["harness"],"summary":"Get Trace Status","operationId":"get_trace_status_harness_admin_trace_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"athlete_slug","in":"query","required":true,"schema":{"type":"string","title":"Athlete Slug"}},{"name":"source","in":"query","required":true,"schema":{"const":"athly","type":"string","title":"Source"}},{"name":"trace_uuid","in":"query","required":true,"schema":{"type":"string","title":"Trace Uuid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarnessTraceStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/livekit/token":{"post":{"tags":["livekit"],"summary":"Create Livekit Token","operationId":"create_livekit_token_livekit_token_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LiveKitTokenRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LiveKitTokenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/onboarding/claim":{"get":{"tags":["onboarding"],"summary":"Preview Claim","description":"What to show someone arriving from the onboarding hand-off.\n\nDeliberately unauthenticated: the visitor has just paid on another property\nand has no session yet -- the token is the whole of their proof. It is\nresolved here rather than in the browser because the shared secret cannot\nreach a bundle, and the response carries neither the token nor the\nonboarding answers back out.\n\n``athlete_slug`` is the athlete in the browser's path, and is used for one\nthing only: furnishing a dead token's 404 with a link back into onboarding,\nwhich the browser cannot build itself.","operationId":"preview_claim_onboarding_claim_get","parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string","minLength":1,"title":"Token"}},{"name":"athlete_slug","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Athlete Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClaimPreview"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["onboarding"],"summary":"Claim","description":"Create the account this token paid for and return a real session.\n\nAlso unauthenticated, and idempotent in the way that matters: a second\nattempt on a token whose email already has a login is refused with 409\nrather than resetting the password.","operationId":"claim_onboarding_claim_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClaimRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClaimSessionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/onboarding/signup":{"post":{"tags":["onboarding"],"summary":"Signup","description":"A create-account submission with no token: work out who this is.\n\nUnauthenticated of necessity -- nobody arriving here has a session -- and so\nthrottled, since an unauthenticated endpoint that answers questions about an\naddress is one an attacker will ask repeatedly. What it can be made to admit\nis bounded rather than eliminated: the paid-vs-not bit, and the same bit any\nsign-in screen gives up about whether a login exists. Wording is uniform\nwithin a branch so nothing finer than that gets out.","operationId":"signup_onboarding_signup_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignupRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignupResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/onboarding/dev/test-account":{"post":{"tags":["onboarding"],"summary":"Development Test Account","description":"Mint a disposable, fully onboarded account and sign it in.\n\nThe fast path to \"a new user's first open\" for testing the coach: no\nonboarding app, no Stripe, no hand-off token. 404 outside ``DEV_MODE``,\nlike the ``/auth/dev/*`` link generators.","operationId":"development_test_account_onboarding_dev_test_account_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DevTestAccountRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DevTestAccountResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/onboarding/attach":{"post":{"tags":["onboarding"],"summary":"Attach","description":"Attach onboarding answers to the signed-in user's intake.\n\nAuthenticated, which is what lets it have no password of its own: by the\ntime anyone reaches it the session already exists, either because they signed\nin through ``/signup`` or because they never left.","operationId":"attach_onboarding_attach_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/talk/accounts":{"get":{"tags":["talk"],"summary":"Get Talk Accounts","description":"The pairs the signed-in admin may call Talk as: their own, then their test accounts'.","operationId":"get_talk_accounts_talk_accounts_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TalkAccountsResponse"}}}}},"security":[{"HTTPBearer":[]}]}},"/test-accounts":{"get":{"tags":["test-accounts"],"summary":"List Test Accounts","description":"The caller's owner's test accounts, newest first.","operationId":"list_test_accounts_test_accounts_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestAccountList"}}}}},"security":[{"HTTPBearer":[]}]},"post":{"tags":["test-accounts"],"summary":"Create Test Account","description":"Create a test account for the caller's owner and sign it in.","operationId":"create_test_account_test_accounts_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestAccountCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestAccountSession"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/test-accounts/options":{"get":{"tags":["test-accounts"],"summary":"Test Account Options","description":"What the create page offers: athletes, their field wording, presets.","operationId":"test_account_options_test_accounts_options_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestAccountOptions"}}}}},"security":[{"HTTPBearer":[]}]}},"/test-accounts/{user_id}/session":{"post":{"tags":["test-accounts"],"summary":"Switch Test Account","description":"A session for one of the caller's owner's test accounts.","operationId":"switch_test_account_test_accounts__user_id__session_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestAccountSession"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/health":{"get":{"summary":"Health Check","operationId":"health_check_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"AnalysisRunCreateRequest":{"properties":{"athlete_slug":{"type":"string","title":"Athlete Slug"},"user_id":{"type":"string","title":"User Id","default":""},"video_id":{"type":"string","format":"uuid","title":"Video Id"},"prompt":{"type":"string","maxLength":4000,"minLength":1,"title":"Prompt"}},"type":"object","required":["athlete_slug","video_id","prompt"],"title":"AnalysisRunCreateRequest"},"AnalysisRunResponse":{"properties":{"id":{"type":"string","title":"Id"},"video_id":{"type":"string","title":"Video Id"},"user_id":{"type":"string","title":"User Id"},"athlete_id":{"type":"string","title":"Athlete Id"},"status":{"type":"string","title":"Status"},"provider":{"type":"string","title":"Provider"},"model":{"type":"string","title":"Model"},"prompt":{"type":"string","title":"Prompt"},"output_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Output Text"},"output_json":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Output Json"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"retryable":{"type":"boolean","title":"Retryable","default":false},"provider_file_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Provider File Name"},"provider_latency_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Provider Latency Ms"},"created_at":{"type":"string","title":"Created At"},"updated_at":{"type":"string","title":"Updated At"}},"type":"object","required":["id","video_id","user_id","athlete_id","status","provider","model","prompt","created_at","updated_at"],"title":"AnalysisRunResponse"},"AnalysisVideoCreateRequest":{"properties":{"athlete_slug":{"type":"string","title":"Athlete Slug"},"user_id":{"type":"string","title":"User Id","default":""},"filename":{"type":"string","title":"Filename"},"mime_type":{"type":"string","title":"Mime Type"},"size_bytes":{"type":"integer","title":"Size Bytes"}},"type":"object","required":["athlete_slug","filename","mime_type","size_bytes"],"title":"AnalysisVideoCreateRequest"},"AnalysisVideoResponse":{"properties":{"id":{"type":"string","title":"Id"},"user_id":{"type":"string","title":"User Id"},"athlete_id":{"type":"string","title":"Athlete Id"},"storage_bucket":{"type":"string","title":"Storage Bucket"},"storage_path":{"type":"string","title":"Storage Path"},"original_filename":{"type":"string","title":"Original Filename"},"mime_type":{"type":"string","title":"Mime Type"},"size_bytes":{"type":"integer","title":"Size Bytes"},"upload_status":{"type":"string","title":"Upload Status"},"upload_error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Upload Error"},"metadata":{"additionalProperties":true,"type":"object","title":"Metadata"},"created_at":{"type":"string","title":"Created At"},"updated_at":{"type":"string","title":"Updated At"},"playback_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Playback Url"},"signed_upload_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Signed Upload Url"},"upload_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Upload Token"}},"type":"object","required":["id","user_id","athlete_id","storage_bucket","storage_path","original_filename","mime_type","size_bytes","upload_status","created_at","updated_at"],"title":"AnalysisVideoResponse"},"AnalysisVideoUploadCompleteRequest":{"properties":{"athlete_slug":{"type":"string","title":"Athlete Slug"}},"type":"object","required":["athlete_slug"],"title":"AnalysisVideoUploadCompleteRequest"},"AthleteListItem":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"slug":{"type":"string","title":"Slug"},"name":{"type":"string","title":"Name"},"sport":{"type":"string","title":"Sport"},"sport_name":{"type":"string","title":"Sport Name"},"sports":{"additionalProperties":{"type":"string"},"type":"object","title":"Sports","default":{}},"tagline":{"type":"string","title":"Tagline"},"focus_areas":{"items":{"type":"string"},"type":"array","title":"Focus Areas"},"image":{"type":"string","title":"Image"},"banner_image":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Banner Image"}},"type":"object","required":["id","slug","name","sport","sport_name","tagline","focus_areas","image"],"title":"AthleteListItem"},"AthleteRead":{"properties":{"slug":{"type":"string","title":"Slug"},"name":{"type":"string","title":"Name"},"sport":{"type":"string","title":"Sport"},"tagline":{"type":"string","title":"Tagline"},"coaching_promise":{"type":"string","title":"Coaching Promise"},"focus_areas":{"items":{"type":"string"},"type":"array","title":"Focus Areas"},"image":{"type":"string","title":"Image"},"banner_image":{"type":"string","title":"Banner Image"},"id":{"type":"string","format":"uuid","title":"Id"},"sport_name":{"type":"string","title":"Sport Name"},"sports":{"additionalProperties":{"type":"string"},"type":"object","title":"Sports","default":{}},"slang_locale":{"type":"string","title":"Slang Locale"},"has_elevenlabs_voice":{"type":"boolean","title":"Has Elevenlabs Voice","default":false},"voice_enabled":{"type":"boolean","title":"Voice Enabled","default":false},"greeting_template":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Greeting Template"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["slug","name","sport","tagline","coaching_promise","focus_areas","image","banner_image","id","sport_name","slang_locale","created_at"],"title":"AthleteRead"},"AthleteResolveResponse":{"properties":{"athlete":{"anyOf":[{"$ref":"#/components/schemas/AthleteRead"},{"type":"null"}]},"canonical_slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Canonical Slug"},"is_canonical":{"type":"boolean","title":"Is Canonical"},"suggestions":{"items":{"$ref":"#/components/schemas/AthleteRead"},"type":"array","title":"Suggestions"}},"type":"object","required":["athlete","canonical_slug","is_canonical","suggestions"],"title":"AthleteResolveResponse"},"AttachRequest":{"properties":{"token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Token"},"athlete_slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Athlete Slug"},"replace":{"type":"boolean","title":"Replace","default":false},"timezone":{"anyOf":[{"type":"string","maxLength":64,"minLength":1},{"type":"null"}],"title":"Timezone"}},"type":"object","title":"AttachRequest","description":"Attach onboarding answers to the signed-in user's intake.\n\nTwo shapes, one endpoint. ``token`` is the return leg -- someone arriving\nback at the app with ``?t=`` and a session they already had -- and the pair\nis taken from the token. ``athlete_slug`` with ``replace`` backs the \"use my\nnewer answers\" button, where the account is found by the session's email."},"AttachResponse":{"properties":{"result":{"type":"string","enum":["attached","conflict","unchanged"],"title":"Result"},"athlete_slug":{"type":"string","title":"Athlete Slug"}},"type":"object","required":["result","athlete_slug"],"title":"AttachResponse"},"CheckoutUrlResponse":{"properties":{"url":{"type":"string","title":"Url"}},"type":"object","required":["url"],"title":"CheckoutUrlResponse","description":"Where to start paying again, once a cancellation has actually elapsed.\n\nBuilt server-side: ``ONBOARDING_BASE_URL`` and the shared secret are\ndeliberately not in the bundle, and the token this URL carries is the pair's\nonboarding ``access_token``, which a browser has no way to resolve."},"ClaimPreview":{"properties":{"action":{"type":"string","enum":["create_account","sign_in","pay"],"title":"Action"},"email":{"type":"string","format":"email","title":"Email"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"athlete_slug":{"type":"string","title":"Athlete Slug"},"plan":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Plan"},"subscription_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subscription Status"},"pay_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pay Url"}},"type":"object","required":["action","email","athlete_slug"],"title":"ClaimPreview","description":"What the create-account screen needs to render, and nothing more.\n\nNotably absent: the token, and the onboarding answers. The answers are\nwritten to the pair's harness row (``onboarding_data``) server-side at\nclaim time, so there is no reason to hand a browser a copy."},"ClaimRequest":{"properties":{"token":{"type":"string","minLength":1,"title":"Token"},"password":{"type":"string","minLength":8,"title":"Password"},"athlete_slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Athlete Slug"},"timezone":{"anyOf":[{"type":"string","maxLength":64,"minLength":1},{"type":"null"}],"title":"Timezone"}},"type":"object","required":["token","password"],"title":"ClaimRequest"},"ClaimSessionResponse":{"properties":{"access_token":{"type":"string","title":"Access Token"},"refresh_token":{"type":"string","title":"Refresh Token"},"expires_at":{"type":"integer","title":"Expires At"},"user_id":{"type":"string","title":"User Id"},"athlete_slug":{"type":"string","title":"Athlete Slug"}},"type":"object","required":["access_token","refresh_token","expires_at","user_id","athlete_slug"],"title":"ClaimSessionResponse","description":"A real session, so a paid signup goes straight into the app."},"DevTestAccountRequest":{"properties":{"athlete_slug":{"type":"string","minLength":1,"title":"Athlete Slug"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"timezone":{"type":"string","maxLength":64,"minLength":1,"title":"Timezone"}},"type":"object","required":["athlete_slug","timezone"],"title":"DevTestAccountRequest","description":"Mint a disposable, fully onboarded account for this athlete (DEV_MODE only)."},"DevTestAccountResponse":{"properties":{"access_token":{"type":"string","title":"Access Token"},"refresh_token":{"type":"string","title":"Refresh Token"},"expires_at":{"type":"integer","title":"Expires At"},"user_id":{"type":"string","title":"User Id"},"athlete_slug":{"type":"string","title":"Athlete Slug"},"email":{"type":"string","title":"Email"},"password":{"type":"string","title":"Password"}},"type":"object","required":["access_token","refresh_token","expires_at","user_id","athlete_slug","email","password"],"title":"DevTestAccountResponse","description":"The claim session plus the credentials, so the account can be re-entered\nlater. Only ever returned by the DEV_MODE route."},"DevelopmentPasswordRecoveryRequest":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"next":{"type":"string","title":"Next","default":"/athletes"}},"type":"object","required":["email"],"title":"DevelopmentPasswordRecoveryRequest"},"DevelopmentPasswordRecoveryResponse":{"properties":{"recovery_url":{"type":"string","title":"Recovery Url"}},"type":"object","required":["recovery_url"],"title":"DevelopmentPasswordRecoveryResponse"},"DevelopmentSignupRequest":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"password":{"type":"string","minLength":1,"title":"Password"},"next":{"type":"string","title":"Next","default":"/athletes"}},"type":"object","required":["email","password"],"title":"DevelopmentSignupRequest"},"DevelopmentSignupResponse":{"properties":{"signup_url":{"type":"string","title":"Signup Url"}},"type":"object","required":["signup_url"],"title":"DevelopmentSignupResponse"},"FreeplayChatRequest":{"properties":{"athlete_slug":{"type":"string","title":"Athlete Slug"},"content":{"type":"string","title":"Content"},"history":{"items":{"$ref":"#/components/schemas/FreeplayHistoryMessage"},"type":"array","title":"History"},"user_info":{"additionalProperties":true,"type":"object","title":"User Info"}},"type":"object","required":["athlete_slug","content"],"title":"FreeplayChatRequest"},"FreeplayChatResponse":{"properties":{"content":{"type":"string","title":"Content"},"metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metadata"}},"type":"object","required":["content"],"title":"FreeplayChatResponse"},"FreeplayHistoryMessage":{"properties":{"role":{"type":"string","enum":["user","assistant"],"title":"Role"},"content":{"type":"string","minLength":1,"title":"Content"}},"type":"object","required":["role","content"],"title":"FreeplayHistoryMessage"},"FreeplayReadinessResponse":{"properties":{"status":{"type":"string","title":"Status"},"athlete_slug":{"type":"string","title":"Athlete Slug"},"dependencies":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Dependencies"}},"type":"object","required":["status","athlete_slug","dependencies"],"title":"FreeplayReadinessResponse"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HarnessCall":{"properties":{"id":{"type":"string","title":"Id"},"status":{"type":"string","enum":["live","ended"],"title":"Status"},"started_at":{"type":"string","format":"date-time","title":"Started At"},"ended_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Ended At"},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary"},"athlete_summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Athlete Summary"},"summary_status":{"type":"string","enum":["pending","done","failed"],"title":"Summary Status"}},"type":"object","required":["id","status","started_at","summary_status"],"title":"HarnessCall","description":"A voice call as the app shows it (ATH-531): its card's state. Real,\ntz-aware time. ``summary_status`` says where the summary stands\n(``pending``, ``done`` with ``summary`` set, or ``failed``);\n``athlete_summary`` is what the card shows, written with it. The app\nfollows it over the Realtime UPDATE on ``harness.calls``."},"HarnessCallResponse":{"properties":{"call":{"$ref":"#/components/schemas/HarnessCall"},"turns":{"items":{"$ref":"#/components/schemas/HarnessCallTurn"},"type":"array","title":"Turns"}},"type":"object","required":["call","turns"],"title":"HarnessCallResponse","description":"``GET /harness/calls/{call_id}``: the call and its transcript, read\nwhen its card is opened."},"HarnessCallTurn":{"properties":{"id":{"type":"string","title":"Id"},"role":{"type":"string","enum":["user","assistant"],"title":"Role"},"content":{"type":"string","title":"Content"},"interrupted":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Interrupted"},"recorded_at":{"type":"string","format":"date-time","title":"Recorded At"}},"type":"object","required":["id","role","content","recorded_at"],"title":"HarnessCallTurn","description":"One turn of a call's transcript (ATH-531): what the athlete said, or\nwhat they heard of the coach (``interrupted`` when they cut it off)."},"HarnessCheckinAskDismissRequest":{"properties":{"athlete_slug":{"type":"string","title":"Athlete Slug"}},"type":"object","required":["athlete_slug"],"title":"HarnessCheckinAskDismissRequest","description":"\"Not now\" on the check-in ask card (ATH-523)."},"HarnessCursor":{"properties":{"exercise_key":{"type":"string","title":"Exercise Key"},"order":{"type":"integer","title":"Order"},"set_index":{"type":"integer","title":"Set Index"},"sets_done":{"type":"integer","title":"Sets Done"},"unit_count":{"type":"integer","title":"Unit Count"}},"type":"object","required":["exercise_key","order","set_index","sets_done","unit_count"],"title":"HarnessCursor","description":"The first set not yet logged: first exercise (by ``order``) short of\nits ``unit_count``, at its lowest unlogged index."},"HarnessEnrollRequest":{"properties":{"athlete_slug":{"type":"string","minLength":1,"title":"Athlete Slug"},"timezone":{"type":"string","maxLength":64,"minLength":1,"title":"Timezone"}},"type":"object","required":["athlete_slug","timezone"],"title":"HarnessEnrollRequest"},"HarnessEnrollResponse":{"properties":{"timezone_settled":{"type":"boolean","title":"Timezone Settled"}},"type":"object","required":["timezone_settled"],"title":"HarnessEnrollResponse"},"HarnessExerciseRead":{"properties":{"key":{"type":"string","title":"Key"},"name":{"type":"string","title":"Name"},"order":{"type":"integer","title":"Order"},"cues":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cues"},"prescription":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Prescription"},"unit_count":{"type":"integer","title":"Unit Count"},"logged_sets":{"items":{"$ref":"#/components/schemas/HarnessSetRatingRead"},"type":"array","title":"Logged Sets"},"complete":{"type":"boolean","title":"Complete"}},"type":"object","required":["key","name","order","unit_count","complete"],"title":"HarnessExerciseRead","description":"One exercise with derived tracking state. ``prescription`` is the\nstored kind-discriminated document, passed through for the client to\nrender; ``unit_count`` is how many rated efforts it asks for (1 for an\nunprescribed exercise, so everything stays trackable)."},"HarnessFeltRequest":{"properties":{"athlete_slug":{"type":"string","title":"Athlete Slug"},"felt":{"anyOf":[{"type":"integer","maximum":5.0,"minimum":1.0},{"type":"null"}],"title":"Felt"}},"type":"object","required":["athlete_slug"],"title":"HarnessFeltRequest"},"HarnessMessage":{"properties":{"seq":{"type":"integer","title":"Seq"},"id":{"type":"string","title":"Id"},"role":{"type":"string","title":"Role"},"content":{"type":"string","title":"Content"},"origin":{"anyOf":[{"type":"string","const":"cli"},{"type":"null"}],"title":"Origin"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"session_ref":{"anyOf":[{"$ref":"#/components/schemas/SessionRef"},{"type":"null"}]},"call":{"anyOf":[{"$ref":"#/components/schemas/HarnessCall"},{"type":"null"}]}},"type":"object","required":["seq","id","role","content","created_at"],"title":"HarnessMessage"},"HarnessPlanOpenRequest":{"properties":{"athlete_slug":{"type":"string","title":"Athlete Slug"}},"type":"object","required":["athlete_slug"],"title":"HarnessPlanOpenRequest"},"HarnessPlanProfileResponse":{"properties":{"plan_profile":{"$ref":"#/components/schemas/PlanProfile"}},"type":"object","required":["plan_profile"],"title":"HarnessPlanProfileResponse","description":"``PATCH /harness/profile``'s answer: the profile as merged, and only\nthat. The raw answers were not in the request and did not change; the\neditor keeps the copy it already has."},"HarnessPlanStateResponse":{"properties":{"status":{"type":"string","enum":["not_started","in_progress","done"],"title":"Status"},"has_planned_sessions":{"type":"boolean","title":"Has Planned Sessions"}},"type":"object","required":["status","has_planned_sessions"],"title":"HarnessPlanStateResponse","description":"The pair's plan state (ATH-460 Phase 2), derived from its most recent\n``generate_plan`` job: ``not_started`` is plan mode (the home card reads\n\"Generate My Plan\" and the opener fires on app entry), ``in_progress``\n(the card reads \"In Progress\") and ``done`` are not. The one plan\nsignal the frontend reads; the same words the harness package uses.\n``has_planned_sessions`` is whether the pair has any live planned\nseries, in any week: in plan mode the coach often plans sessions\nmid-interview, so the empty-week copy reads \"partially built\" rather\nthan \"nothing planned\"."},"HarnessProfilePatchRequest":{"properties":{"athlete_slug":{"type":"string","title":"Athlete Slug"},"plan_profile":{"$ref":"#/components/schemas/PlanProfilePatch"}},"type":"object","required":["athlete_slug","plan_profile"],"title":"HarnessProfilePatchRequest"},"HarnessProfileResponse":{"properties":{"plan_profile":{"$ref":"#/components/schemas/PlanProfile"},"onboarding_data":{"additionalProperties":true,"type":"object","title":"Onboarding Data"},"field_copy":{"additionalProperties":{"$ref":"#/components/schemas/ProfileFieldCopy"},"type":"object","title":"Field Copy"}},"type":"object","title":"HarnessProfileResponse","description":"The pair's profile as the settings editor reads it: the structured\nprofile and, beside it, the raw onboarding answers the editor reads\nthrough to for a field the profile has no value for. Nothing in the\nbrowser writes ``onboarding_data``. ``field_copy`` is the sport seed's\nwording for the fields it relabels (ATH-521) — overrides only; a field\nnot in it keeps the editor's default question."},"HarnessReadRequest":{"properties":{"athlete_slug":{"type":"string","title":"Athlete Slug"},"seq":{"type":"integer","minimum":0.0,"title":"Seq"}},"type":"object","required":["athlete_slug","seq"],"title":"HarnessReadRequest","description":"Mark the thread read through ``seq``. A request, not a value: the\nserver keeps the watermark monotonic and clamps it to a row that exists,\nso re-sending an old visit's seq, or a seq from the future, is safe."},"HarnessSendRequest":{"properties":{"athlete_slug":{"type":"string","title":"Athlete Slug"},"content":{"type":"string","maxLength":4000,"minLength":1,"title":"Content"},"client_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Client Id"},"entry":{"anyOf":[{"type":"string","maxLength":200,"minLength":1},{"type":"null"}],"title":"Entry"},"exercise_key":{"anyOf":[{"type":"string","maxLength":64,"minLength":1},{"type":"null"}],"title":"Exercise Key"},"week":{"type":"boolean","title":"Week","default":false},"week_start":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Week Start"}},"type":"object","required":["athlete_slug","content"],"title":"HarnessSendRequest"},"HarnessSendResponse":{"properties":{"message":{"$ref":"#/components/schemas/HarnessMessage"}},"type":"object","required":["message"],"title":"HarnessSendResponse","description":"The fire-and-forget 202 (ATH-454): the *persisted user message* alone,\nwith its real ``seq``/``id``/``created_at`` so the client reconciles its\noptimistic bubble without waiting for Realtime. The reply arrives over\nRealtime like every other message."},"HarnessSessionResponse":{"properties":{"entry":{"type":"string","title":"Entry"},"title":{"type":"string","title":"Title"},"cue":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cue"},"kind":{"type":"string","enum":["planned","log"],"title":"Kind"},"status":{"anyOf":[{"type":"string","enum":["upcoming","in_progress","done","missed","before_plan"]},{"type":"null"}],"title":"Status"},"start":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Start"},"all_day":{"type":"boolean","title":"All Day","default":false},"plannable":{"type":"boolean","title":"Plannable","default":true},"session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Session Id"},"planned_session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Planned Session Id"},"occurrence":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Occurrence"},"exercises":{"items":{"$ref":"#/components/schemas/HarnessExerciseRead"},"type":"array","title":"Exercises"},"felt":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Felt"},"complete":{"type":"boolean","title":"Complete","default":false},"cursor":{"anyOf":[{"$ref":"#/components/schemas/HarnessCursor"},{"type":"null"}]}},"type":"object","required":["entry","title","kind"],"title":"HarnessSessionResponse","description":"One entry in full: exercises with per-set tracking and the flow\ncursor. Before a start the content is the plan's; after, the log's\nsnapshot. ``session_id`` is None until the entry has a log."},"HarnessSetRatingRead":{"properties":{"set_index":{"type":"integer","title":"Set Index"},"felt":{"type":"integer","title":"Felt"},"completed_at":{"type":"string","format":"date-time","title":"Completed At"}},"type":"object","required":["set_index","felt","completed_at"],"title":"HarnessSetRatingRead","description":"One non-voided set rating; ``set_index`` is the position in the\nexercise's rating list (voided entries hold their slots)."},"HarnessSetWriteRequest":{"properties":{"athlete_slug":{"type":"string","title":"Athlete Slug"},"felt":{"type":"integer","maximum":5.0,"minimum":1.0,"title":"Felt"}},"type":"object","required":["athlete_slug","felt"],"title":"HarnessSetWriteRequest"},"HarnessStartRequest":{"properties":{"athlete_slug":{"type":"string","title":"Athlete Slug"},"planned_session_id":{"type":"string","title":"Planned Session Id"},"occurrence":{"type":"string","format":"date-time","title":"Occurrence"}},"type":"object","required":["athlete_slug","planned_session_id","occurrence"],"title":"HarnessStartRequest"},"HarnessThreadResponse":{"properties":{"messages":{"items":{"$ref":"#/components/schemas/HarnessMessage"},"type":"array","title":"Messages"},"composing_since":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Composing Since"},"last_read_seq":{"type":"integer","title":"Last Read Seq","default":0},"checkin_ask_dismissed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Checkin Ask Dismissed At"}},"type":"object","required":["messages"],"title":"HarnessThreadResponse","description":"Messages after the cursor, plus the pair's turn-owed marker — the\ncomposing indicator's page-load seed (timestamptz UTC, unlike message\n``created_at``); Realtime UPDATEs on ``harness.user_profiles`` keep it\nlive afterward. ``None`` means the coach is not composing."},"HarnessTraceStatusResponse":{"properties":{"ready":{"type":"boolean","title":"Ready"},"url":{"type":"string","title":"Url"}},"type":"object","required":["ready","url"],"title":"HarnessTraceStatusResponse","description":"``GET /harness/admin/trace``: whether Confident shows the trace yet."},"HarnessTurnDiagnosticsResponse":{"properties":{"turns":{"items":{"$ref":"#/components/schemas/TurnDiagnostics"},"type":"array","title":"Turns"},"confident_enabled":{"type":"boolean","title":"Confident Enabled"}},"type":"object","required":["turns","confident_enabled"],"title":"HarnessTurnDiagnosticsResponse","description":"``GET /harness/admin/diagnostics``: the pair's recent turns, oldest\nfirst, and whether this service's Confident trace links can open."},"HarnessUnreadResponse":{"properties":{"unread_count":{"type":"integer","title":"Unread Count"},"last_read_seq":{"type":"integer","title":"Last Read Seq"}},"type":"object","required":["unread_count","last_read_seq"],"title":"HarnessUnreadResponse","description":"``GET /harness/unread`` and ``POST /harness/read``'s answer: how many\ncoach-side rows (``assistant`` / ``error`` / ``checkin_ask`` — never\n``user`` or ``routine``) sit past the pair's read watermark, and the\nwatermark."},"HarnessWeekDay":{"properties":{"date":{"type":"string","format":"date","title":"Date"},"entries":{"items":{"$ref":"#/components/schemas/HarnessWeekEntry"},"type":"array","title":"Entries"}},"type":"object","required":["date","entries"],"title":"HarnessWeekDay"},"HarnessWeekEntry":{"properties":{"entry":{"type":"string","title":"Entry"},"kind":{"type":"string","enum":["planned","log"],"title":"Kind"},"title":{"type":"string","title":"Title"},"cue":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cue"},"start":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Start"},"all_day":{"type":"boolean","title":"All Day","default":false},"status":{"anyOf":[{"type":"string","enum":["upcoming","in_progress","done","missed","before_plan"]},{"type":"null"}],"title":"Status"},"plannable":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Plannable"},"session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Session Id"},"exercise_names":{"items":{"type":"string"},"type":"array","title":"Exercise Names"},"sets_done":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sets Done"},"sets_total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sets Total"},"felt":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Felt"},"complete":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Complete"}},"type":"object","required":["entry","kind","title"],"title":"HarnessWeekEntry","description":"One timeline entry: a planned occurrence (``kind=\"planned\"``) or an\nunlinked logged session (``kind=\"log\"``). A linked occurrence carries the\n*log's* content — snapshot names and ratings — never the plan's."},"HarnessWeekResponse":{"properties":{"today":{"type":"string","format":"date","title":"Today"},"week_start":{"type":"string","format":"date","title":"Week Start"},"days":{"items":{"$ref":"#/components/schemas/HarnessWeekDay"},"type":"array","title":"Days"},"next_week_start":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Next Week Start"},"prev_week_start":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Prev Week Start"}},"type":"object","required":["today","week_start","days"],"title":"HarnessWeekResponse"},"LiveKitTokenRequest":{"properties":{"athlete_slug":{"type":"string","minLength":1,"title":"Athlete Slug"},"room_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Room Name"},"participant_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Participant Name"},"participant_identity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Participant Identity"},"participant_metadata":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Participant Metadata"},"participant_attributes":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Participant Attributes"}},"type":"object","required":["athlete_slug"],"title":"LiveKitTokenRequest"},"LiveKitTokenResponse":{"properties":{"server_url":{"type":"string","title":"Server Url"},"participant_token":{"type":"string","title":"Participant Token"}},"type":"object","required":["server_url","participant_token"],"title":"LiveKitTokenResponse"},"LoginRequest":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"password":{"type":"string","minLength":1,"title":"Password"},"device_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Device Token"}},"type":"object","required":["email","password"],"title":"LoginRequest"},"LoginResponse":{"properties":{"access_token":{"type":"string","title":"Access Token"},"refresh_token":{"type":"string","title":"Refresh Token"},"expires_at":{"type":"integer","title":"Expires At"},"user_id":{"type":"string","title":"User Id"},"device_token":{"type":"string","title":"Device Token"}},"type":"object","required":["access_token","refresh_token","expires_at","user_id","device_token"],"title":"LoginResponse"},"ModelCall":{"properties":{"type":{"type":"string","const":"model","title":"Type","default":"model"},"stage":{"type":"string","enum":["operator","voice"],"title":"Stage"},"step":{"type":"integer","title":"Step"},"model":{"type":"string","title":"Model"},"duration_ms":{"type":"number","title":"Duration Ms"},"input_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Input Tokens"},"cached_input_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Cached Input Tokens"},"output_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Output Tokens"},"reasoning_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Reasoning Tokens"},"response_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Response Id"},"tool_calls":{"items":{"$ref":"#/components/schemas/ToolCallChoice"},"type":"array","title":"Tool Calls"},"output":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Output"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"}},"type":"object","required":["stage","step","model","duration_ms"],"title":"ModelCall"},"PlanProfile":{"properties":{"sport_position":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sport Position"},"competitive_level":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Competitive Level"},"primary_focus":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Primary Focus"},"training_days":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Training Days"},"training_setup":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Training Setup"},"age":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Age"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","title":"PlanProfile","description":"Structured planning context for the pair — the successor to the\nplanner's ``PROFILE_KEYS``, and since ATH-460 Phase 1 the pair's *only*\nprofile (the public ``user_athlete_profiles`` table is archived). Every\nfield is optional: it fills in over time (the settings editor, ATH-460's\nintake interview, or opportunistically from chat), and an absent field\nis simply not yet known.\n\nThe column is written only through the ``merge_plan_profile`` RPC\n(server-side ``jsonb ||``), never through ``save_user``, so two writers\ntouching different fields both land.\n\nThe value shapes are the editor's: every field is a string.\n``training_days`` is the joined label string the editor stores\n(``\"Mon, Wed\"``), deliberately — the athlete's own words, not a parsed\nset. Nothing has ever written another shape, so a row that carries one\nis a bug to surface, not a legacy to absorb.\n\nThe sport is not a field: it is fixed by the athlete the pair is\nenrolled with (the harness sport seed), so there is nothing to ask. A\n``sports`` key on an older row is ignored on read.\n\nThe profile is not a field of :class:`UserProfile`: ``Store.save_user``\nwrites the user record from an in-memory copy, and a profile riding on\nthat copy could clobber a merge. It is read through\n``Store.get_plan_profile`` instead."},"PlanProfilePatch":{"properties":{"sport_position":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Sport Position"},"competitive_level":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Competitive Level"},"primary_focus":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Primary Focus"},"training_days":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Training Days"},"training_setup":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Training Setup"},"age":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Age"},"notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Notes"}},"additionalProperties":false,"type":"object","title":"PlanProfilePatch","description":"A partial ``plan_profile`` as ``PATCH /harness/profile`` carries it.\n\nPATCH semantics on the field set of :class:`PlanProfile`, with the\nwrite limits of :class:`PlanProfileWrite`: a key that is\nabsent leaves the field alone, a key set to ``null`` clears it, and the\nmerge is the ``merge_plan_profile`` RPC's server-side ``jsonb ||``. The\nkey set is closed (``extra=\"forbid\"``) — the profile has one owner now,\nand an unknown key is a typo or an old client, not a new question."},"ProfileFieldCopy":{"properties":{"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"question":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Question"}},"type":"object","title":"ProfileFieldCopy","description":"A sport's wording for one ``PlanProfile`` field (ATH-521): ``label``\nis the row label model context renders, ``question`` is what the settings\neditor asks. Absent means the default wording. The field's key, and\nwhether the plan needs it, never vary by sport."},"PushPublicKeyResponse":{"properties":{"public_key":{"type":"string","title":"Public Key"}},"type":"object","required":["public_key"],"title":"PushPublicKeyResponse"},"PushSubscriptionDeleteRequest":{"properties":{"athlete_slug":{"type":"string","title":"Athlete Slug"},"endpoint":{"type":"string","maxLength":2048,"minLength":1,"title":"Endpoint"}},"type":"object","required":["athlete_slug","endpoint"],"title":"PushSubscriptionDeleteRequest"},"PushSubscriptionKeys":{"properties":{"p256dh":{"type":"string","minLength":1,"title":"P256Dh"},"auth":{"type":"string","minLength":1,"title":"Auth"}},"type":"object","required":["p256dh","auth"],"title":"PushSubscriptionKeys"},"PushSubscriptionRequest":{"properties":{"athlete_slug":{"type":"string","title":"Athlete Slug"},"endpoint":{"type":"string","maxLength":2048,"minLength":1,"title":"Endpoint"},"keys":{"$ref":"#/components/schemas/PushSubscriptionKeys"}},"type":"object","required":["athlete_slug","endpoint","keys"],"title":"PushSubscriptionRequest"},"RefreshRequest":{"properties":{"refresh_token":{"type":"string","minLength":1,"title":"Refresh Token"}},"type":"object","required":["refresh_token"],"title":"RefreshRequest"},"RetrievalCall":{"properties":{"type":{"type":"string","const":"retrieval","title":"Type","default":"retrieval"},"duration_ms":{"type":"number","title":"Duration Ms"},"brains":{"items":{"type":"string"},"type":"array","title":"Brains"},"candidates":{"type":"integer","title":"Candidates","default":0},"chunks":{"type":"integer","title":"Chunks","default":0},"rerank":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Rerank"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"}},"type":"object","required":["duration_ms"],"title":"RetrievalCall"},"SessionRef":{"properties":{"entry":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Entry"},"exercise_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Exercise Key"},"session_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Session Title"},"exercise_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Exercise Name"},"entry_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Entry Date"},"week_start":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Week Start"},"week_offset":{"type":"integer","minimum":0.0,"title":"Week Offset","default":0}},"type":"object","title":"SessionRef","description":"A user message's structured link to one training surface.\n\nSession refs carry a timeline entry and optional exercise (ATH-466);\nweek refs carry that week's Monday and how many weeks after the send's\nown week it was (``week_offset``: 0 this week, 1 next). Display names,\ndates and the offset are frozen at send time, and them going stale after\na rename, a replan or the week passing is fine."},"SessionResponse":{"properties":{"access_token":{"type":"string","title":"Access Token"},"refresh_token":{"type":"string","title":"Refresh Token"},"expires_at":{"type":"integer","title":"Expires At"},"user_id":{"type":"string","title":"User Id"}},"type":"object","required":["access_token","refresh_token","expires_at","user_id"],"title":"SessionResponse"},"SignupOffer":{"properties":{"kind":{"type":"string","enum":["finish_checkout","start_onboarding"],"title":"Kind"},"url":{"type":"string","title":"Url"}},"type":"object","required":["kind","url"],"title":"SignupOffer","description":"The one button offered alongside a session. Never a redirect.\n\nBouncing between domains is always a button press, so this is data for the\nscreen to render rather than a location to follow."},"SignupRequest":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"password":{"type":"string","minLength":8,"title":"Password"},"athlete_slug":{"type":"string","minLength":1,"title":"Athlete Slug"},"timezone":{"anyOf":[{"type":"string","maxLength":64,"minLength":1},{"type":"null"}],"title":"Timezone"}},"type":"object","required":["email","password","athlete_slug"],"title":"SignupRequest","description":"A tokenless create-account submission, scoped to the athlete in the URL.\n\nThe slug comes from the path rather than remembered client state: one email\ncan be paid for one athlete and unknown for another, so the pair is the\nidentity and guessing it wrong would route someone to the wrong answer."},"SignupResponse":{"properties":{"action":{"type":"string","enum":["signed_in","check_inbox","start_onboarding"],"title":"Action"},"session":{"anyOf":[{"$ref":"#/components/schemas/ClaimSessionResponse"},{"type":"null"}]},"offer":{"anyOf":[{"$ref":"#/components/schemas/SignupOffer"},{"type":"null"}]},"intake_conflict":{"type":"boolean","title":"Intake Conflict","default":false}},"type":"object","required":["action"],"title":"SignupResponse"},"SubscribedAthlete":{"properties":{"slug":{"type":"string","title":"Slug"},"name":{"type":"string","title":"Name"},"sport":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sport"},"image":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image"},"banner_image":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Banner Image"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"entitled":{"type":"boolean","title":"Entitled"},"access_source":{"anyOf":[{"type":"string","enum":["admin","subscription"]},{"type":"null"}],"title":"Access Source"}},"type":"object","required":["slug","name","status","entitled"],"title":"SubscribedAthlete"},"SubscriptionActionRequest":{"properties":{"athlete_slug":{"type":"string","minLength":1,"title":"Athlete Slug"}},"type":"object","required":["athlete_slug"],"title":"SubscriptionActionRequest"},"SubscriptionRead":{"properties":{"athlete_slug":{"type":"string","title":"Athlete Slug"},"status":{"type":"string","title":"Status"},"entitled":{"type":"boolean","title":"Entitled"},"cancel_at_period_end":{"type":"boolean","title":"Cancel At Period End","default":false},"current_period_end":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Current Period End"},"paused_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Paused At"},"banked_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Banked Days"},"price_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Price Cents"},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency"},"billing_interval":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Billing Interval"},"billing_interval_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Billing Interval Count"},"card_brand":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Card Brand"},"card_last4":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Card Last4"}},"type":"object","required":["athlete_slug","status","entitled"],"title":"SubscriptionRead","description":"One mirror row, as the manage screen needs it.\n\nDeliberately absent: ``stripe_customer_id``. The screen never needs it, and\nhanding a browser a Stripe customer handle invites a client that thinks it\ncan talk to Stripe directly."},"SubscriptionResponse":{"properties":{"subscription":{"anyOf":[{"$ref":"#/components/schemas/SubscriptionRead"},{"type":"null"}]},"access_source":{"anyOf":[{"type":"string","enum":["admin","subscription"]},{"type":"null"}],"title":"Access Source"}},"type":"object","title":"SubscriptionResponse","description":"``null`` is a real answer, not a 404.\n\nA pair with no subscription is the roster's upsell state and the\nfully-cancelled athlete's landing place, so the screen renders it rather\nthan erroring on it."},"TalkAccount":{"properties":{"user_id":{"type":"string","title":"User Id"},"athlete_slug":{"type":"string","title":"Athlete Slug"},"label":{"type":"string","title":"Label"},"kind":{"type":"string","enum":["admin","sandbox"],"title":"Kind"}},"type":"object","required":["user_id","athlete_slug","label","kind"],"title":"TalkAccount","description":"A pair Talk may call as: an admin's own, or one of the admin's test accounts."},"TalkAccountsResponse":{"properties":{"accounts":{"items":{"$ref":"#/components/schemas/TalkAccount"},"type":"array","title":"Accounts"}},"type":"object","required":["accounts"],"title":"TalkAccountsResponse"},"TestAccountAthleteOption":{"properties":{"slug":{"type":"string","title":"Slug"},"name":{"type":"string","title":"Name"},"field_copy":{"additionalProperties":{"$ref":"#/components/schemas/ProfileFieldCopy"},"type":"object","title":"Field Copy"},"presets":{"items":{"$ref":"#/components/schemas/TestAccountPresetRead"},"type":"array","title":"Presets"}},"type":"object","required":["slug","name"],"title":"TestAccountAthleteOption"},"TestAccountCreate":{"properties":{"name":{"type":"string","maxLength":80,"minLength":1,"title":"Name"},"athlete_slug":{"type":"string","minLength":1,"title":"Athlete Slug"},"preset_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Preset Id"},"timezone":{"type":"string","maxLength":64,"minLength":1,"title":"Timezone"}},"additionalProperties":false,"type":"object","required":["name","athlete_slug","timezone"],"title":"TestAccountCreate"},"TestAccountList":{"properties":{"accounts":{"items":{"$ref":"#/components/schemas/TestAccountRead"},"type":"array","title":"Accounts"}},"type":"object","required":["accounts"],"title":"TestAccountList"},"TestAccountOptions":{"properties":{"athletes":{"items":{"$ref":"#/components/schemas/TestAccountAthleteOption"},"type":"array","title":"Athletes"}},"type":"object","required":["athletes"],"title":"TestAccountOptions"},"TestAccountPresetRead":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"seed_profile":{"additionalProperties":true,"type":"object","title":"Seed Profile"}},"type":"object","required":["id","name","seed_profile"],"title":"TestAccountPresetRead"},"TestAccountRead":{"properties":{"user_id":{"type":"string","title":"User Id"},"email":{"type":"string","title":"Email"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"athlete_slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Athlete Slug"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["user_id","email","created_at"],"title":"TestAccountRead","description":"One row of ``list_sandbox_accounts``."},"TestAccountSession":{"properties":{"access_token":{"type":"string","title":"Access Token"},"refresh_token":{"type":"string","title":"Refresh Token"},"expires_at":{"type":"integer","title":"Expires At"},"user_id":{"type":"string","title":"User Id"},"athlete_slug":{"type":"string","title":"Athlete Slug"},"email":{"type":"string","title":"Email"}},"type":"object","required":["access_token","refresh_token","expires_at","user_id","athlete_slug","email"],"title":"TestAccountSession","description":"A session for the test account, for the browser to adopt."},"ToolCall":{"properties":{"type":{"type":"string","const":"tool","title":"Type","default":"tool"},"name":{"type":"string","title":"Name"},"arguments":{"type":"string","title":"Arguments"},"result":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Result"},"status":{"type":"string","enum":["ok","error"],"title":"Status","default":"ok"},"duration_ms":{"type":"number","title":"Duration Ms"}},"type":"object","required":["name","arguments","duration_ms"],"title":"ToolCall"},"ToolCallChoice":{"properties":{"name":{"type":"string","title":"Name"},"arguments":{"type":"string","title":"Arguments"}},"type":"object","required":["name","arguments"],"title":"ToolCallChoice"},"TurnDiagnostics":{"properties":{"id":{"type":"string","title":"Id"},"turn_id":{"type":"string","title":"Turn Id"},"kind":{"type":"string","title":"Kind"},"outcome":{"type":"string","title":"Outcome"},"started_at":{"type":"string","format":"date-time","title":"Started At"},"total_ms":{"type":"number","title":"Total Ms"},"reply_message_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reply Message Id"},"after_message_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"After Message Id"},"confident_trace_uuid":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Confident Trace Uuid"},"otel_trace_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Otel Trace Id"},"calls":{"items":{"oneOf":[{"$ref":"#/components/schemas/RetrievalCall"},{"$ref":"#/components/schemas/ModelCall"},{"$ref":"#/components/schemas/ToolCall"}],"discriminator":{"propertyName":"type","mapping":{"model":"#/components/schemas/ModelCall","retrieval":"#/components/schemas/RetrievalCall","tool":"#/components/schemas/ToolCall"}}},"type":"array","title":"Calls"}},"type":"object","required":["id","turn_id","kind","outcome","started_at","total_ms"],"title":"TurnDiagnostics"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}},"securitySchemes":{"HTTPBearer":{"type":"http","scheme":"bearer"}}}}