{"openapi":"3.0.0","paths":{"/healthcheck":{"get":{"operationId":"AppController_healthcheck","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"string"}}}}},"tags":["healthcheck"]}},"/auth/security":{"get":{"operationId":"AccountSecurityController_getSecurity","parameters":[],"responses":{"503":{"description":"Account profile unavailable"}},"security":[{"Auth0AccessToken":[]}],"summary":"Get current account security capabilities","tags":["auth"]}},"/auth/security/challenge":{"post":{"operationId":"AccountSecurityController_challenge","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecurityChallengeDto"}}}},"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Create a one-use reauthentication nonce for a security action","tags":["auth"]}},"/auth/security/change-password":{"post":{"operationId":"AccountSecurityController_changePassword","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecurityChangePasswordDto"}}}},"responses":{"400":{"description":"Fresh challenge proof required"},"403":{"description":"Credentials belong to a sign-in provider"},"503":{"description":"Provider or replay store unavailable"}},"security":[{"Auth0AccessToken":[]}],"summary":"Change a database password after action-bound reauthentication","tags":["auth"]}},"/auth/security/mfa-enrollment":{"post":{"operationId":"AccountSecurityController_enrollMfa","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecurityReauthenticationDto"}}}},"responses":{"400":{"description":"Fresh challenge proof required"},"403":{"description":"Team administrator required"},"409":{"description":"MFA already enrolled"},"503":{"description":"Provider, enrollment, or replay store unavailable"}},"security":[{"Auth0AccessToken":[]}],"summary":"Create a hosted MFA enrollment ticket for a team administrator","tags":["auth"]}},"/pusher/user-auth":{"post":{"operationId":"PusherAuthController_pusherAuth","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PusherAuthDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["pusher"]}},"/pusher/channel-auth":{"post":{"operationId":"PusherAuthController_channelAuth","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PusherChannelAuthDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Presence-channel auth (`presence-class-<teamId>`) — verifies team membership/adminship.","tags":["pusher"]}},"/pusher/beams-auth":{"get":{"operationId":"PusherAuthController_getPusherBeamsToken","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PusherBeamsAuthResponse"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["pusher"]}},"/pusher/beams-unsubscribe":{"get":{"operationId":"PusherAuthController_unsubscribeFromBeams","parameters":[],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["pusher"]}},"/auth/reset-password":{"post":{"operationId":"AuthController_requestPasswordReset","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordDto"}}}},"responses":{"201":{"description":""}},"tags":["auth"]}},"/auth/change-password":{"post":{"operationId":"AuthController_changePassword","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePasswordDto"}}}},"responses":{"201":{"description":""}},"tags":["auth"]}},"/auth/email-confirmation":{"post":{"operationId":"AuthController_resendEmailVerification","parameters":[],"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["auth"]}},"/auth/{platform}":{"get":{"operationId":"AuthController_login","parameters":[{"name":"platform","required":true,"in":"path","schema":{"type":"string","enum":["zoho","clickup","trello","jira","asana","monday","google","microsoft"]}},{"name":"is_development","required":false,"in":"query","schema":{"default":false,"allOf":[{"$ref":"#/components/schemas/Object"}]}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["auth"]}},"/auth/{platform}/callback":{"get":{"operationId":"AuthController_callback","parameters":[{"name":"platform","required":true,"in":"path","schema":{"type":"string","enum":["zoho","clickup","trello","jira","asana","monday","google","microsoft"]}},{"name":"code","required":false,"in":"query","schema":{"type":"string"}},{"name":"location","required":false,"in":"query","schema":{"type":"string"}},{"name":"is_development","required":false,"in":"query","schema":{"default":false,"allOf":[{"$ref":"#/components/schemas/Object"}]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["auth"]}},"/auth/email-confirmation-guest":{"post":{"operationId":"AuthController_emailConfirmationForGuest","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailConfirmationForGuestDto"}}}},"responses":{"201":{"description":""}},"tags":["auth"]}},"/auth/convert-guest":{"post":{"operationId":"AuthController_convertGuest","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConvertGuestDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Converts the authenticated guest/anonymous account into a registered one (#1850).\nThe account is taken from the auth token, so a guest can only convert their own account.","tags":["auth"]}},"/auth/link-social-to-guest":{"post":{"operationId":"AuthController_linkSocialToGuest","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkSocialToGuestDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Links a just-completed social login (Google/Apple) into the authenticated\nguest/anonymous account (#2208). The primary account is taken from the auth\ntoken, so a guest can only link social identities into their own account.","tags":["auth"]}},"/auth/send-email-verification":{"post":{"operationId":"AuthController_sendEmailVerification","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailVerificationDto"}}}},"responses":{"201":{"description":""}},"tags":["auth"]}},"/auth/verify-email":{"get":{"operationId":"AuthController_verifyEmail","parameters":[{"name":"token","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["auth"]}},"/calendar/{platform}/events":{"get":{"operationId":"CalendarController_getEvents","parameters":[{"name":"platform","required":true,"in":"path","schema":{"type":"string","enum":["zoho","clickup","trello","jira","asana","monday","google","microsoft"]}},{"name":"days","required":false,"in":"query","schema":{"minimum":1,"maximum":90,"type":"number"}},{"name":"account","required":true,"in":"query","schema":{"type":"string"}},{"name":"day","required":false,"in":"query","schema":{"pattern":"^\\d{4}-\\d{2}-\\d{2}$","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["calendar"]}},"/calendar/{platform}/calendar-datas":{"get":{"operationId":"CalendarController_getCalendarDatas","parameters":[{"name":"platform","required":true,"in":"path","schema":{"type":"string","enum":["google","microsoft"]}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["calendar"]}},"/calendar/calendar-update":{"put":{"operationId":"CalendarController_updateCalendarStatus","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCalendarStatusDto"}}}},"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["calendar"]}},"/calendar/{platform}/keywords":{"get":{"operationId":"CalendarController_getExcludedCalendarKeywords","parameters":[{"name":"platform","required":true,"in":"path","schema":{"type":"string","enum":["google","microsoft"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CalendarExcludedKeyword"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["calendar"]}},"/calendar/keyword-create":{"put":{"operationId":"CalendarController_createKeyword","parameters":[],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["calendar"]}},"/calendar/keyword-update":{"put":{"operationId":"CalendarController_updateExcludedKeyword","parameters":[],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["calendar"]}},"/calendar/keyword-delete":{"delete":{"operationId":"CalendarController_deleteExcludedKeyword","parameters":[{"name":"id","required":true,"in":"query","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["calendar"]}},"/user/fast-safety-check":{"post":{"description":"Send the same body as /user/is-url-safe-to-use (target \"url\") or /user/is-app-safe-to-use (target \"app\"). allow=true: let the user through without the full check. allow=false: blur and call the full check, which decides and gives the reason. Any failure here returns allow=false, so the full check stays the fallback.","operationId":"FastSafetyGateController_check","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FastSafetyCheckDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FastSafetyCheckResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Fast (~250 ms) first pass of the website and app safety checks","tags":["user"]}},"/user-settings":{"get":{"operationId":"UserSettingsController_getSettings","parameters":[{"name":"language","required":false,"in":"query","schema":{"type":"string","enum":["en","es","de","ja","vi","pt-BR","pt-PT","zh-CN","zh-TW","nl","tl","fr","it","pl","ru","ar","ro"]}},{"name":"timezone","required":false,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserSettingsDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["user-settings"]},"put":{"operationId":"UserSettingsController_updateSettings","parameters":[{"name":"is_onboarding","required":false,"in":"query","schema":{"type":"boolean"}},{"name":"device_id","required":false,"in":"query","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserSettingsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserSettingsDto"}}}},"409":{"description":"Submitted settings contain activity or custom routine identifiers owned by another account"}},"security":[{"Auth0AccessToken":[]}],"tags":["user-settings"]}},"/user/account-sync":{"put":{"operationId":"UserController_syncUserAccount","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncUserAccountDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserAuthContext"}}}}},"security":[{"Auth0ActionSecret":[]}],"summary":"DO NOT USE IT FROM THE FRONT_END! This route should be used only by the Auth0s \"post-login\" hook.","tags":["user"]}},"/user/details":{"get":{"operationId":"UserController_getUserDetails","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["user"]}},"/user/details/summary":{"get":{"operationId":"UserController_getUserSummary","parameters":[{"name":"from","required":false,"in":"query","description":"Optional source identifier for the request (e.g. dashboard).","schema":{"example":"dashboard","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserSummaryResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["user"]}},"/user/details/current-activity-props":{"get":{"operationId":"UserController_getUserCurrentActivity","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurrentActivityProps"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["user"]}},"/user/list":{"get":{"operationId":"UserController_getUsersList","parameters":[{"name":"search","required":false,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/User"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["user"]}},"/user/weekly-focus-block-summary":{"get":{"operationId":"UserController_getUserFocusBlockSummary","parameters":[{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":200,"type":"number"}},{"name":"offset","required":false,"in":"query","schema":{"minimum":0,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CompletedFocusBlock"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Focus-session history (newest first, paginated via limit/offset)","tags":["user"]},"post":{"operationId":"UserController_createManualUserFocusBlock","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFocusBlockDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompletedFocusBlock"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Create a manual focus session (uses or creates a \"Manual Entry\" focus mode)","tags":["user"]}},"/user/weekly-focus-block-summary/{id}":{"patch":{"operationId":"UserController_updateUserFocusBlock","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFocusBlockDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompletedFocusBlock"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Edit a focus session (non-destructive — preserves original values in metadata)","tags":["user"]},"delete":{"operationId":"UserController_deleteUserFocusBlock","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Delete a focus session","tags":["user"]}},"/user/weekly-completed-activity-summary":{"get":{"operationId":"UserController_getUserCompletedActivitySummary","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CompletedActivity"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["user"]}},"/user/focus-modes":{"get":{"operationId":"UserController_getUserFocusModes","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["user"]}},"/user/user-list":{"get":{"operationId":"UserController_getListOfUsers","parameters":[{"name":"order_by","required":false,"in":"query","schema":{"type":"string","enum":["last_completed_sequence_started_at","last_completed_focus_mode_at","morning_routines_streak","evening_routines_streak","focus_modes_streak"]}},{"name":"take","required":false,"in":"query","schema":{"type":"number"}},{"name":"skip","required":false,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/User"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["user"]}},"/user":{"get":{"operationId":"UserController_getUserById","parameters":[{"name":"stripe_customer_id","required":false,"in":"query","schema":{"type":"string"}},{"name":"email","required":false,"in":"query","schema":{"format":"email","type":"string"}},{"name":"id","required":false,"in":"query","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["user"]}},"/user/sign-up-template":{"put":{"operationId":"UserController_updateUserSignUpTemplate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserSignUpFieldDto"}}}},"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["user"]}},"/user/metadata":{"put":{"operationId":"UserController_updateUserMetadata","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserMetadataDto"}}}},"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["user"]}},"/user/consent-status":{"get":{"operationId":"UserController_getConsentStatus","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsentStatusResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Which privacy-policy and terms versions the user accepted, and whether they must (re-)consent first","tags":["user"]}},"/user/consent":{"put":{"operationId":"UserController_upsertUserConsent","parameters":[],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["user"]}},"/user/stats/onboarding":{"get":{"operationId":"UserController_getUserStats","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingStatsResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["user"]}},"/user/onboarding/re-engagement-email":{"post":{"operationId":"UserController_sendOnboardingReEngagementEmail","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingReEngagementEmailResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Triggers the \"continue your setup\" re-engagement email for the current user. No-ops (still 200) when onboarding is already complete or the account has no email on file.","tags":["user"]}},"/user/access-request":{"post":{"operationId":"UserController_saveAdminAccessRequest","parameters":[],"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["user"]}},"/user/subscription":{"get":{"operationId":"UserController_getUserSubscription","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionStatus"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["user"]}},"/user/motivational-summary":{"get":{"operationId":"UserController_getMotivationalSummary","parameters":[{"name":"tone","required":true,"in":"query","schema":{"type":"string","enum":["humorous","court jester","pirate","future self in twenty years","scientist","cheerleader","upbeat","factual","sassy"]}},{"name":"routine","required":false,"in":"query","schema":{"type":"string","enum":["morning_routine","evening_routine"]}},{"name":"device_type","required":false,"in":"query","schema":{"type":"string","enum":["mobile","desktop"]}},{"name":"struggling_habits","required":false,"in":"query","description":"Names of the habits the user completes least consistently; the pep talk encourages them","schema":{"type":"array","items":{"type":"string"}}},{"name":"language","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["user"]}},"/user/is-url-safe-to-use":{"post":{"operationId":"UserController_checkIfURLIsSafe","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IsUrlSafeDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/URLSafeProbabilityResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["user"]}},"/user/is-app-safe-to-use":{"post":{"operationId":"UserController_checkIfAppIsSafe","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IsAppSafeDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/URLSafeProbabilityResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["user"]}},"/user/task-intention-check":{"post":{"operationId":"UserController_checkTaskIntentionAlignment","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskIntentionCheckDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskIntentionCheckResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Leniently check whether a to-do task supports the focus intention. Only flags clear conflicts so the client can prompt the user to reconcile (backend#2340); fails open to aligns=true on any AI error.","tags":["user"]}},"/user/evaluate-focus-postponement":{"post":{"operationId":"UserController_evaluateFocusPostponement","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EvaluateFocusPostponementDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EvaluateFocusPostponementResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Evaluate a focus postponement conversation using the accountability buddy","tags":["user"]}},"/user/generate-occupation-specific-relevant-sites":{"post":{"operationId":"UserController_generateOccupationSites","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateOccupationSitesDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OccupationSitesResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Generate occupation-specific relevant sites and typical distractions using AI","tags":["user"]}},"/user/long-term-goals":{"patch":{"operationId":"UserController_updateUserLongTermGoals","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLongTermGoalsDto"}}}},"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["user"]},"put":{"operationId":"UserController_updateLongTermGoals","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLongTermGoalsDto"}}}},"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["user"]},"get":{"operationId":"UserController_getLongTermGoals","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["user"]}},"/user/timezone":{"get":{"operationId":"UserController_getUserTimezone","parameters":[],"responses":{"200":{"description":"Declared timezone, or null when not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserTimezoneResponseDto"}}}},"404":{"description":"No user row exists for the authenticated identity"}},"security":[{"Auth0AccessToken":[]}],"summary":"The user's declared IANA timezone; null when they have never set one","tags":["user"]},"patch":{"operationId":"UserController_updateUserTimezone","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserTimezoneDto"}}}},"responses":{"200":{"description":"Updated timezone","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserTimezoneResponseDto"}}}},"400":{"description":"Not a named IANA timezone"},"404":{"description":"No user row exists for the authenticated identity"}},"security":[{"Auth0AccessToken":[]}],"summary":"Set the declared IANA timezone. Does not affect routine notifications or daily stats, which follow the device-synced timezone.","tags":["user"]}},"/user/username":{"put":{"operationId":"UserController_updateUsername","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUsernameDto"}}}},"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["user"]}},"/user/synced-external-platforms":{"get":{"operationId":"UserController_getSyncedExternalPlatforms","parameters":[],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["user"]}},"/user/uninstall":{"post":{"operationId":"UserController_uninstallApplication","parameters":[{"name":"app_platform","required":true,"in":"query","schema":{"type":"string"}},{"name":"app_version","required":true,"in":"query","schema":{"type":"string"}},{"name":"feedback_message","required":true,"in":"query","schema":{"type":"string"}},{"name":"log_url","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["user"]}},"/user/email-preferences":{"get":{"operationId":"UserController_getEmailPreferences","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailPreferencesResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Get user email preferences","tags":["user"]},"put":{"operationId":"UserController_updateEmailPreferences","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEmailPreferencesDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailPreferencesResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Update user email preferences","tags":["user"]}},"/user/email-preferences/unsubscribe":{"get":{"operationId":"UserController_getUnsubscribePage","parameters":[{"name":"token","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"summary":"Unsubscribe confirmation page","tags":["user"]},"post":{"operationId":"UserController_unsubscribeFromEmails","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnsubscribeEmailDto"}}}},"responses":{"201":{"description":""}},"summary":"Unsubscribe from emails using token","tags":["user"]}},"/user/email-preferences/manage":{"get":{"operationId":"UserController_getEmailPreferencesManagePage","parameters":[{"name":"token","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"summary":"Email preferences management page","tags":["user"]},"post":{"operationId":"UserController_updateEmailPreferencesWithToken","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEmailPreferencesWithTokenDto"}}}},"responses":{"201":{"description":""}},"summary":"Update email preferences using token","tags":["user"]}},"/user/email-preferences/request-link":{"post":{"operationId":"UserController_requestEmailPreferencesLink","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestEmailPreferencesLinkDto"}}}},"responses":{"201":{"description":""}},"summary":"Request email preferences link via email","tags":["user"]}},"/user/profile-image-upload-url":{"get":{"operationId":"UserController_getProfileImageUploadUrl","parameters":[{"name":"filename","required":true,"in":"query","schema":{"maxLength":200,"pattern":"^[a-zA-Z0-9_-][a-zA-Z0-9_. -]{0,198}\\.[a-zA-Z0-9]{1,10}$","type":"string"}},{"name":"content_type","required":true,"in":"query","schema":{"type":"string","enum":["image/jpeg","image/png","image/gif","image/webp"]}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Get a presigned URL for uploading a profile image to R2","tags":["user"]}},"/user/confirm-profile-image-upload":{"post":{"description":"After uploading a file to the presigned R2 URL, call this endpoint with the public URL to validate the upload (size, MIME type) and atomically save it as the profile image.","operationId":"UserController_confirmProfileImageUpload","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmProfileImageUploadDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Confirm a completed R2 profile image upload and save to user metadata","tags":["user"]}},"/user-local-device-settings":{"get":{"operationId":"UserLocalDeviceSettingsController_getLocalDeviceSettings","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLocalDeviceSettingsDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["user-local-device-settings"]},"put":{"operationId":"UserLocalDeviceSettingsController_updateLocalDeviceSettings","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLocalDeviceSettingsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLocalDeviceSettingsDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["user-local-device-settings"]}},"/user-data":{"get":{"operationId":"UserDataController_getUserPersonalData","parameters":[{"name":"language","required":true,"in":"query","schema":{"type":"string","enum":["en","es","de","ja","vi","pt-BR","pt-PT","zh-CN","zh-TW","nl","tl","fr","it","pl","ru","ar","ro"]}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["user-data"]},"delete":{"operationId":"UserDataController_deleteAllUserData","parameters":[{"name":"message","required":false,"in":"query","schema":{"type":"string"}},{"name":"can_contact","required":false,"in":"query","schema":{"type":"boolean"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"This endpoint deletes all user data from Auth0, RevenueCat, Stripe, and from the DB. DATA IS NOT RECOVERABLE","tags":["user-data"]}},"/user-stats/leaderboard":{"get":{"operationId":"UserStatsController_getStreaksLeaderBoard","parameters":[{"name":"streak_type","required":false,"in":"query","schema":{"type":"string","enum":["morning_routines_streak","evening_routines_streak","focus_modes_streak","micro_breaks_streak"]}},{"name":"limit","required":false,"in":"query","schema":{"type":"number"}},{"name":"active_within_days","required":false,"in":"query","description":"Only include users active within this many days (e.g. 30). Defaults to 30. Pass 0 to disable the filter.","schema":{"minimum":0,"maximum":365,"default":30,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["user-stats"]}},"/user-stats/daily-summary":{"get":{"operationId":"UserStatsController_getWeeklyStats","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DailyStatSummary"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["user-stats"]}},"/user-stats/admin":{"get":{"operationId":"UserStatsController_getUserStatsForAdminDashboard","parameters":[{"name":"user_id","required":true,"in":"query","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUserStatsResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Fetches aggregated usage statistics for a specific user. Used by the admin support\ndashboard to display user metrics in the \"User Stats\" tab.","tags":["user-stats"]}},"/user-feedback":{"post":{"operationId":"UserFeedbackController_saveUserFeedback","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserFeedbackDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["user-feedback"]}},"/study-participants/link-user-to-participant-code":{"post":{"operationId":"StudyParticipantController_linkUserToParticipantCode","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkUserToParticipantCodeDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["study-participants"]}},"/study-participants/get-code-activation-status":{"get":{"operationId":"StudyParticipantController_getCodeActivationStatus","parameters":[{"name":"participantCode","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Returns the activation status of the participant code, i.e. whether they are still in data collection mode or whether they should have access to the app","content":{"application/json":{"schema":{"type":"string"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["study-participants"]}},"/study-participants/get-participant-last-received-data":{"get":{"operationId":"StudyParticipantController_getParticipantLastReceivedData","parameters":[],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["study-participants"]}},"/study-participants/mark-complete-questionnaire":{"post":{"operationId":"StudyParticipantController_markCompleteQuestionnaire","parameters":[],"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["study-participants"]}},"/study-participants/mark-eos-questionnaire-completed":{"post":{"operationId":"StudyParticipantController_markEndOfStudyQuestionnaireCompleted","parameters":[],"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["study-participants"]}},"/study-participants/save-flanker-test-result":{"post":{"operationId":"StudyParticipantController_saveFlankerTestResult","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveFlankerTestResultDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["study-participants"]}},"/study-participants/group-statistics":{"get":{"operationId":"StudyParticipantController_getGroupStatistics","parameters":[],"responses":{"200":{"description":"Returns statistics about participant distribution across groups and characteristics"}},"security":[{"Auth0AccessToken":[]}],"tags":["study-participants"]}},"/usage-data/sync":{"post":{"operationId":"UsageDataController_syncUsageData","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncUsageDataDto"}}}},"responses":{"201":{"description":""}},"tags":["UsageData"]}},"/usage-data/generate-upload-image-url":{"post":{"operationId":"UsageDataController_generateUploadImageUrl","parameters":[],"responses":{"201":{"description":""}},"tags":["UsageData"]}},"/usage-data/usage-image-uploaded":{"post":{"operationId":"UsageDataController_uploadUsageImage","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadUsageImageDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadUsageImageResponseDto"}}}}},"tags":["UsageData"]}},"/health-metrics/sync":{"post":{"operationId":"HealthMetricsController_syncHealthMetrics","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncHealthMetricsDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["health-metrics"]}},"/service-account/user/weekly-focus-hours-summary":{"get":{"operationId":"UserServiceAccountController_getWeeklyFocusHoursSummary","parameters":[{"name":"user_id","required":true,"in":"query","description":"The UUID of the team member to retrieve weekly focus hours for","schema":{"format":"uuid","example":"b9f1bce9-c130-4141-80d6-3bde32a66542","type":"string"}},{"name":"from","required":false,"in":"query","description":"Optional ISO8601 start date. Defaults to 3 months ago.","schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved weekly focus hours","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WeeklyFocusHoursResponseDto"}}}},"401":{"description":"Unauthorized - Invalid token or insufficient service account permissions"},"403":{"description":"Forbidden - Service account cannot access the requested user"}},"security":[{"Auth0AccessToken":[]}],"summary":"Returns focus hours logged per week for the last 3 months. Used for timesheet/payroll systems.","tags":["service-account/user"]}},"/service-account/user/focus-session-logs":{"get":{"operationId":"UserServiceAccountController_getFocusSessionLogs","parameters":[{"name":"user_id","required":false,"in":"query","description":"The UUID of the team member to retrieve focus session logs for. Omit for admin all-users mode.","schema":{"format":"uuid","example":"b9f1bce9-c130-4141-80d6-3bde32a66542","type":"string"}},{"name":"from","required":false,"in":"query","description":"Optional ISO8601 start date. Defaults to 3 months ago. Hard-capped at 6 months ago.","schema":{"type":"string"}},{"name":"to","required":false,"in":"query","description":"Optional ISO8601 end date. Defaults to now.","schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved focus session logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FocusSessionLogsResponseDto"}}}},"401":{"description":"Unauthorized - Invalid token or insufficient service account permissions"},"403":{"description":"Forbidden - Service account cannot access the requested user(s)"}},"security":[{"Auth0AccessToken":[]}],"summary":"Returns individual focus session logs. Omit user_id (admin-only) to return every team member's sessions.","tags":["service-account/user"]}},"/completed-activity":{"post":{"operationId":"CompletedActivityController_createCompletedActivity","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCompletedActivityDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompletedActivityResponse"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["completed-activity"]}},"/completed-activity/sync":{"post":{"operationId":"CompletedActivityController_completedMultipleActivities","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OfflineSyncActivitiesDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["completed-activity"]}},"/completed-activity/skip":{"post":{"operationId":"CompletedActivityController_skipActivity","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSkippedActivityDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompletedActivityResponse"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["completed-activity"]}},"/completed-activity/{activity_id}/stats":{"get":{"operationId":"CompletedActivityController_getStatsByActivityPerDay","parameters":[{"name":"activity_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"days_number","required":true,"in":"query","schema":{"minimum":1,"maximum":180,"default":30,"type":"number"}},{"name":"timezone","required":true,"in":"query","schema":{"default":"UTC","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompletedActivityStats"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["completed-activity"]}},"/completed-activity/consistency-stats":{"post":{"description":"Returns, for each owned habit in the request, the number of distinct local days with at least one completion in the last `days_number` days. Replaces one single-habit stats GET per habit. Ids that are unknown or not owned by the caller are omitted. `timezone` is presentation-only and never updates user settings.","operationId":"CompletedActivityController_getBulkConsistencyStats","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetBulkConsistencyStatsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkConsistencyStats"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Bulk habit consistency stats","tags":["completed-activity"]}},"/completed-activity/log-question/{question_id}/stats":{"get":{"operationId":"CompletedActivityController_getStatsByQuestionPerDay","parameters":[{"name":"question_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"days_number","required":true,"in":"query","schema":{"minimum":1,"maximum":180,"default":30,"type":"number"}},{"name":"timezone","required":true,"in":"query","schema":{"default":"UTC","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogQuantityAnswersStats"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["completed-activity"]}},"/completed-activity/{activity_id}":{"get":{"operationId":"CompletedActivityController_getCompletedLogsByActivityInTimeRange","parameters":[{"name":"activity_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"from_time","required":false,"in":"query","description":"If no value provided the default is Date.now() - 24h","schema":{"format":"date-time","type":"string"}},{"name":"to_time","required":false,"in":"query","description":"If no value provided the default is Date.now()","schema":{"format":"date-time","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CompletedActivity"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["completed-activity"]}},"/completed-activity/answer-logs":{"post":{"operationId":"CompletedActivityController_getLogQuantityAnswerLogs","parameters":[{"name":"from_time","required":false,"in":"query","description":"If no value provided the default is Date.now() - 24h","schema":{"format":"date-time","type":"string"}},{"name":"to_time","required":false,"in":"query","description":"If no value provided the default is Date.now()","schema":{"format":"date-time","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetLogQuantityAnswerLogsDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["completed-activity"]}},"/completed-activity/revise/{completed_activity_id}":{"patch":{"operationId":"CompletedActivityController_reviseCompletedActivity","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseCompletedActivityDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompletedActivity"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["completed-activity"]}},"/completed-activity/{activity_id}/undo":{"post":{"description":"Deletes the habit's log in today's routine and rebuilds routine state from the logs left. A routine that was completed normally is reopened and the user is pointed back at the undone habit (409 if another routine is active). A force-completed routine stays completed. Sent webhooks, push notifications and competency level changes are not reversed. Clients must also drop the entry from their offline sync queue, otherwise a later sync re-creates the log.","operationId":"CompletedActivityController_undoActivity","parameters":[{"name":"activity_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UndoCompletedActivityResponse"}}}},"404":{"description":"The habit has no log in today's routine."},"409":{"description":"Another routine is active, or the routine has nothing left to resume."}},"security":[{"Auth0AccessToken":[]}],"summary":"Undo a habit's Done or Skip in today's routine","tags":["completed-activity"]}},"/completed-activity/{activity_id}/unskip":{"post":{"description":"Removes the habit's skip from today's routine so the habit is pending again, then sends the activity-completed Pusher event so the other devices re-pull the routine. Unlike undo, it only ever removes a skip: a habit done after its skip keeps its Done. Idempotent: when there is no skip to remove, nothing changes and `unskipped` is false. List today's skipped habit ids with GET /completed-activity-sequence/routine-progress?date=<today> (`skipped_habit_ids`, which carries them for every routine status). A completed routine is reopened as undo reopens it. Clients must also drop the skip from their offline sync queue, otherwise a later sync re-creates it.","operationId":"CompletedActivityController_unskipActivity","parameters":[{"name":"activity_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnskipActivityDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnskipActivityResponse"}}}},"409":{"description":"Another routine is active, or the routine has nothing left to resume."}},"security":[{"Auth0AccessToken":[]}],"summary":"Unskip a habit skipped in today's routine","tags":["completed-activity"]}},"/completed-activity/day-summary":{"get":{"operationId":"CompletedActivityController_getdaySummary","parameters":[{"name":"timezone","required":true,"in":"query","description":"Presentation-only: used to resolve the day window for the summary. Must never be\npersisted to user settings — the default below fires whenever a client omits the\nparameter, so writing it would turn a read into a settings mutation and overwrite a\nreal timezone with 'UTC'. The canonical sync path is GET /user-settings?timezone=.","schema":{"default":"UTC","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DaySummary"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["completed-activity"]}},"/completed-activity/notes":{"get":{"operationId":"CompletedActivityController_getCompletedActivityNotes","parameters":[{"name":"activity_id","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"from_date","required":false,"in":"query","schema":{"format":"date-time","type":"string"}},{"name":"to_date","required":false,"in":"query","schema":{"format":"date-time","type":"string"}},{"name":"page_num","required":false,"in":"query","schema":{"type":"number"}},{"name":"per_page","required":false,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["completed-activity"]}},"/completed-activity/notes/delete":{"put":{"operationId":"CompletedActivityController_deleteCompletedActivityNotes","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteCompletedActivityNotesDto"}}}},"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["completed-activity"]}},"/completed-activity-sequence/routine-progress":{"get":{"operationId":"CompletedActivitySequenceController_getRoutineProgressForDate","parameters":[{"name":"date","required":false,"in":"query","description":"User's local calendar date, YYYY-MM-DD (e.g. '2025-03-08'). Defaults to today.","schema":{"pattern":"^\\d{4}-\\d{2}-\\d{2}$","example":"2025-03-08","type":"string"}},{"name":"timezone","required":false,"in":"query","description":"IANA timezone (e.g. 'Australia/Melbourne'). Defaults to UTC.","schema":{"example":"Australia/Melbourne","type":"string"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Routine progress (completed_habit_ids etc.) for a given local date (YYYY-MM-DD; defaults to today). Same top-level shape as current-activity-props' today_routine_progress, but when a date is supplied it is a HISTORICAL view: no in-progress status, and COMPLETED routines keep their completed_habit_ids. For live today status use current-activity-props; pass a date here only for past-day lookups.","tags":["completed-activity-sequence"]}},"/completed-activity-sequence/{activity_sequence_id}/stats":{"get":{"operationId":"CompletedActivitySequenceController_getStatsByActivityPerDay","parameters":[{"name":"activity_sequence_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"days_number","required":true,"in":"query","schema":{"minimum":1,"maximum":180,"default":30,"type":"number"}},{"name":"timezone","required":true,"in":"query","schema":{"default":"UTC","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompletedActivitySequenceStats"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["completed-activity-sequence"]}},"/completed-activity-sequence/{activity_sequence_id}/force-complete-current-sequence":{"post":{"operationId":"CompletedActivitySequenceController_forceCompleteCurrentSequence","parameters":[{"name":"activity_sequence_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"cancel_habits_for_today","required":false,"in":"query","schema":{"type":"boolean"}}],"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["completed-activity-sequence"]}},"/completed-activity-sequence/{activity_sequence_id}/uncomplete":{"post":{"operationId":"CompletedActivitySequenceController_uncompleteActivitySequence","parameters":[{"name":"activity_sequence_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"date","required":false,"in":"query","description":"ISO date string (user's local date, e.g. '2025-03-08'). Defaults to today.","schema":{"example":"2025-03-08","type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompletedActivitySequence"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["completed-activity-sequence"]}},"/activity/images":{"delete":{"description":"Activity-scoped keys (activity_images/{activityId}/…) are enqueued for hard deletion once no activity references them. User-scoped keys (activity_images/user/{userId}/…) may back several habits, so they are NOT hard-deleted here — the object is reclaimed by the activity-image-cleanup cron once unreferenced, and the request returns success.","operationId":"ActivityController_deleteActivityImage","parameters":[{"name":"file_path","required":true,"in":"query","description":"Activity image storage path/key to delete","schema":{"maxLength":1024,"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Remove an activity image reference","tags":["activity"]}},"/activity/images/generate-upload-url":{"post":{"description":"Not tied to an existing activity, so it can back habits that are not persisted yet (new habits, habits inside a pack). The image is stored under the caller’s own namespace.","operationId":"ActivityController_generateUserImageUploadUrl","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateActivityImageUploadUrlDto"}}}},"responses":{"201":{"description":"Presigned upload URL generated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateActivityImageUploadUrlResponseDto"}}}},"404":{"description":"User not found"}},"security":[{"Auth0AccessToken":[]}],"summary":"Generate a presigned upload URL for a user-scoped image","tags":["activity"]}},"/activity/images/read-url":{"get":{"description":"Requires query parameter `file_key` (URL-encoded R2 object key under the caller’s namespace).","operationId":"ActivityController_getUserImageReadUrl","parameters":[{"name":"file_key","required":true,"in":"query","description":"R2 object key for the image (URL-encoded in the request), e.g. activity_images/{activityId}/... or the user-scoped activity_images/user/{userId}/... form.","schema":{"maxLength":1024,"type":"string"}}],"responses":{"200":{"description":"Presigned read URL generated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivityImageReadUrlResponseDto"}}}},"400":{"description":"Invalid or missing file_key"},"403":{"description":"User is not authorized to read this image"}},"security":[{"Auth0AccessToken":[]}],"summary":"Generate a presigned GET URL to display a user-scoped image from R2","tags":["activity"]}},"/activity/{activityId}/images/generate-upload-url":{"post":{"operationId":"ActivityController_generateActivityImageUploadUrl","parameters":[{"name":"activityId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateActivityImageUploadUrlDto"}}}},"responses":{"201":{"description":"Presigned upload URL generated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateActivityImageUploadUrlResponseDto"}}}},"403":{"description":"User is not authorized to upload images for this activity"},"404":{"description":"Activity or user not found"}},"security":[{"Auth0AccessToken":[]}],"summary":"Generate a presigned upload URL for an activity image","tags":["activity"]}},"/activity/{activityId}/images":{"get":{"description":"Requires query parameter `file_key` (URL-encoded R2 object key under this activity).","operationId":"ActivityController_getActivityImageReadUrl","parameters":[{"name":"activityId","required":true,"in":"path","description":"Activity ID","schema":{"format":"uuid","type":"string"}},{"name":"file_key","required":true,"in":"query","description":"R2 object key for the image (URL-encoded in the request), e.g. activity_images/{activityId}/... or the user-scoped activity_images/user/{userId}/... form.","schema":{"maxLength":1024,"type":"string"}}],"responses":{"200":{"description":"Presigned read URL generated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivityImageReadUrlResponseDto"}}}},"400":{"description":"Invalid or missing file_key"},"403":{"description":"User is not authorized to read images for this activity"},"404":{"description":"Activity or user not found"}},"security":[{"Auth0AccessToken":[]}],"summary":"Generate a presigned GET URL to display an activity image from R2","tags":["activity"]}},"/activity":{"get":{"operationId":"ActivityController_getActivitiesForAdmin","parameters":[{"name":"activity_type","required":false,"in":"query","schema":{"type":"string","enum":["breaking","morning","evening","standalone","library"]}},{"name":"user_id","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"stripe_customer_id","required":false,"in":"query","schema":{"type":"string"}},{"name":"email","required":false,"in":"query","schema":{"format":"email","type":"string"}},{"name":"page_num","required":false,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Activity"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["activity"]}},"/device/push-registration":{"put":{"operationId":"DeviceController_upsertPushRegistration","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertPushNotificationRegistrationDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushNotificationRegistration"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["device"]},"delete":{"operationId":"DeviceController_deletePushRegistration","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletePushNotificationRegistrationDto"}}}},"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["device"]}},"/device":{"post":{"operationId":"DeviceController_createOrUpdateDevice","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDeviceDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Device"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["device"]}},"/device/{device_id}":{"patch":{"operationId":"DeviceController_updateDevice","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDeviceDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Device"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["device"]}},"/device/admin":{"get":{"operationId":"DeviceController_getDevicesForAdmin","parameters":[{"name":"user_id","required":true,"in":"query","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Device"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["device"]}},"/device/search":{"get":{"operationId":"DeviceController_searchUserDevice","parameters":[{"name":"operating_system","required":false,"in":"query","schema":{"type":"string","enum":["MacOS","Windows","Android","iOS","Web","Unknown"]}},{"name":"device_id","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"is_leader","required":false,"in":"query","schema":{"type":"boolean"}},{"name":"app_version","required":false,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Device"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["device"]}},"/announcements":{"get":{"description":"Retrieve active, unread announcements for the authenticated user filtered by operating system","operationId":"AnnouncementsController_getAnnouncements","parameters":[{"name":"os_name","required":true,"in":"query","description":"Operating system name (case-insensitive)","schema":{"example":"ios","type":"string","enum":["ios","android","mac","windows","web","unknown"]}}],"responses":{"200":{"description":"Successfully retrieved announcements","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetAnnouncementsResponseDto"}}}},"400":{"description":"Invalid operating system parameter"},"401":{"description":"Unauthorized - invalid or missing authentication token"}},"security":[{"Auth0AccessToken":[]}],"summary":"Get active announcements","tags":["announcements"]},"post":{"description":"Create a new in-app announcement for one platform or all platforms","operationId":"AnnouncementsController_createAnnouncement","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAnnouncementDto"}}}},"responses":{"201":{"description":"Announcement created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnnouncementEntity"}}}},"400":{"description":"Invalid announcement payload"},"401":{"description":"Unauthorized - invalid or missing authentication token"}},"security":[{"Auth0AccessToken":[]}],"summary":"Create announcement","tags":["announcements"]}},"/announcements/admin":{"get":{"description":"Paginated list of every announcement (including expired) for the admin dashboard, with optional filters","operationId":"AnnouncementsController_listAnnouncements","parameters":[{"name":"order","required":false,"in":"query","description":"Sort order by creation date (newest first by default)","schema":{"default":"DESC","type":"string","enum":["ASC","DESC"]}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"take","required":false,"in":"query","schema":{"minimum":1,"maximum":50,"default":10,"type":"number"}},{"name":"type","required":false,"in":"query","description":"Filter by announcement type","schema":{"type":"string","enum":["release","event","survey","maintenance"]}},{"name":"priority","required":false,"in":"query","description":"Filter by priority","schema":{"type":"string","enum":["low","medium","high","critical"]}},{"name":"operating_system","required":false,"in":"query","description":"Filter by target operating system","schema":{"type":"string","enum":["all","ios","android","mac","windows","web","unknown"]}},{"name":"include_expired","required":false,"in":"query","description":"Whether to include expired announcements (default true)","schema":{"default":true,"type":"boolean"}},{"name":"search","required":false,"in":"query","description":"Case-insensitive substring match on the heading","schema":{"maxLength":255,"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved announcements","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAnnouncementsResponseDto"}}}},"401":{"description":"Unauthorized - invalid or missing authentication token"}},"security":[{"Auth0AccessToken":[]}],"summary":"List all announcements (admin)","tags":["announcements"]}},"/announcements/admin/{id}":{"get":{"description":"Retrieve a single announcement by ID, including expired ones","operationId":"AnnouncementsController_getAnnouncementById","parameters":[{"name":"id","required":true,"in":"path","description":"Announcement ID","schema":{"maxLength":100,"pattern":"^[a-z0-9_]+$","example":"ann_2026_06_quarterly_webinar","type":"string"}}],"responses":{"200":{"description":"Successfully retrieved announcement","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnnouncementEntity"}}}},"404":{"description":"Announcement not found"}},"security":[{"Auth0AccessToken":[]}],"summary":"Get a single announcement (admin)","tags":["announcements"]}},"/announcements/admin/{id}/views":{"get":{"description":"Aggregated viewed/dismissed counts for a single announcement","operationId":"AnnouncementsController_getAnnouncementViewStats","parameters":[{"name":"id","required":true,"in":"path","description":"Announcement ID","schema":{"maxLength":100,"pattern":"^[a-z0-9_]+$","example":"ann_2026_06_quarterly_webinar","type":"string"}}],"responses":{"200":{"description":"Successfully retrieved view stats","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnnouncementViewStatsResponseDto"}}}},"404":{"description":"Announcement not found"}},"security":[{"Auth0AccessToken":[]}],"summary":"Get announcement view stats (admin)","tags":["announcements"]}},"/announcements/{id}":{"put":{"description":"Update editable fields of an existing announcement. The ID is immutable.","operationId":"AnnouncementsController_updateAnnouncement","parameters":[{"name":"id","required":true,"in":"path","description":"Announcement ID","schema":{"maxLength":100,"pattern":"^[a-z0-9_]+$","example":"ann_2026_06_quarterly_webinar","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAnnouncementDto"}}}},"responses":{"200":{"description":"Announcement updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnnouncementEntity"}}}},"400":{"description":"Invalid announcement payload"},"404":{"description":"Announcement not found"}},"security":[{"Auth0AccessToken":[]}],"summary":"Update an announcement (admin)","tags":["announcements"]},"delete":{"description":"Permanently delete an announcement and its associated view records","operationId":"AnnouncementsController_deleteAnnouncement","parameters":[{"name":"id","required":true,"in":"path","description":"Announcement ID","schema":{"maxLength":100,"pattern":"^[a-z0-9_]+$","example":"ann_2026_06_quarterly_webinar","type":"string"}}],"responses":{"204":{"description":"Announcement deleted successfully"},"404":{"description":"Announcement not found"}},"security":[{"Auth0AccessToken":[]}],"summary":"Delete an announcement (admin)","tags":["announcements"]}},"/announcements/{id}/view":{"post":{"description":"Record that a user has viewed or dismissed an announcement. This operation is idempotent.","operationId":"AnnouncementViewsController_viewAnnouncement","parameters":[{"name":"id","required":true,"in":"path","description":"Announcement ID following the format: ann_YYYY_MM_<title>","schema":{"maxLength":100,"example":"ann_2025_11_release_ios_2_0_0","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ViewAnnouncementDto"}}}},"responses":{"204":{"description":"Announcement successfully marked as viewed"},"400":{"description":"Invalid request parameters"},"401":{"description":"Unauthorized - invalid or missing authentication token"},"404":{"description":"Announcement not found"}},"security":[{"Auth0AccessToken":[]}],"summary":"Mark announcement as viewed","tags":["announcements"]}},"/subscription/webhooks":{"post":{"operationId":"WebhooksController_handleRevenueCatWebhooks","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["Webhooks"]}},"/subscription/webhooks/stripe":{"post":{"operationId":"WebhooksController_handleStripeWebhooks","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["Webhooks"]}},"/subscription/stripe/create-checkout-session":{"post":{"operationId":"StripeController_createCheckoutSession","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateStripeCheckoutSessionDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["subscription/stripe"]}},"/subscription/stripe/create-portal-session":{"post":{"operationId":"StripeController_createPortalSession","parameters":[],"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["subscription/stripe"]}},"/subscription/stripe/products":{"get":{"operationId":"StripeController_getProductsList","parameters":[{"name":"ending_before","required":false,"in":"query","schema":{"type":"string"}},{"name":"starting_after","required":false,"in":"query","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"default":10,"type":"number"}},{"name":"active","required":false,"in":"query","schema":{"default":true,"type":"boolean"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["subscription/stripe"]}},"/subscription/stripe/prices":{"get":{"operationId":"StripeController_getPrices","parameters":[{"name":"ending_before","required":false,"in":"query","schema":{"type":"string"}},{"name":"starting_after","required":false,"in":"query","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"default":10,"type":"number"}},{"name":"active","required":false,"in":"query","schema":{"default":true,"type":"boolean"}},{"name":"product","required":false,"in":"query","schema":{"type":"string"}},{"name":"currency","required":false,"in":"query","schema":{"type":"string"}},{"name":"lookup_keys","required":false,"in":"query","schema":{"type":"array","items":{"type":"string"}}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["subscription/stripe"]}},"/subscription/stripe/prices/{price_id}":{"get":{"operationId":"StripeController_getPriceDetails","parameters":[{"name":"price_id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["subscription/stripe"]}},"/subscription/stripe/cancel-subscription-session":{"post":{"operationId":"StripeController_cancelSubscriptionSession","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelSubscriptionSessionDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["subscription/stripe"]}},"/team-management/bulk-delete-members":{"delete":{"operationId":"TeamManagementController_bulkDeleteTeamMembers","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkDeleteDto"}}}},"responses":{"204":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["team-management"]}},"/team-management/bulk-remove-members":{"post":{"operationId":"TeamManagementController_bulkRemoveMembers","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkDeleteDto"}}}},"responses":{"204":{"description":"Members removed successfully"},"401":{"description":"Caller is not a team admin"},"404":{"description":"Team not found"}},"security":[{"Auth0AccessToken":[]}],"summary":"Remove multiple team members by IDs or emails (team admin)","tags":["team-management"]}},"/team-management/remove-member":{"post":{"operationId":"TeamManagementController_removeMember","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoveTeamMemberDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["team-management"]}},"/team-management/invite-member":{"post":{"operationId":"TeamManagementController_inviteTeamMember","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteTeamMemberDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["team-management"]}},"/team-management/accept-invitation":{"post":{"operationId":"TeamManagementController_acceptInvitation","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcceptInvitationDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["team-management"]}},"/team-management/join":{"post":{"operationId":"TeamManagementController_joinTeam","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinTeamDto"}}}},"responses":{"200":{"description":"User is already a member of this team"},"201":{"description":"Successfully joined team"},"400":{"description":"Invalid or expired join code, or team has reached its member limit"},"404":{"description":"Join code or team not found"}},"security":[{"Auth0AccessToken":[]}],"summary":"Self-enroll authenticated user into a team using a join code","tags":["team-management"]}},"/team-management/join-codes":{"post":{"operationId":"TeamManagementController_createJoinCode","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateJoinCodeDto"}}}},"responses":{"201":{"description":"Join code created"}},"security":[{"Auth0AccessToken":[]}],"summary":"Create a join code for a team (unlimited or limited redemptions)","tags":["team-management"]},"get":{"operationId":"TeamManagementController_getJoinCodes","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"List all join codes for a team","tags":["team-management"]},"delete":{"operationId":"TeamManagementController_deactivateJoinCode","parameters":[],"responses":{"204":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Deactivate a join code","tags":["team-management"]}},"/team-management/join-codes/batch":{"post":{"operationId":"TeamManagementController_createBatchJoinCodes","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBatchJoinCodesDto"}}}},"responses":{"201":{"description":"Batch join codes created"}},"security":[{"Auth0AccessToken":[]}],"summary":"Create multiple single-use join codes for a team","tags":["team-management"]}},"/team-management/assign-admin":{"post":{"operationId":"TeamManagementController_assignAdmin","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddTeamMemberDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["team-management"]}},"/team-management/remove-admin":{"post":{"operationId":"TeamManagementController_removeAdmin","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddTeamMemberDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["team-management"]}},"/team-management/assign-teacher":{"post":{"operationId":"TeamManagementController_assignTeacher","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddTeamMemberDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Team is not a school, or the target is not a registered member"}},"security":[{"Auth0AccessToken":[]}],"summary":"Assign an existing member of a school team as a teacher","tags":["team-management"]}},"/team-management/remove-teacher":{"post":{"operationId":"TeamManagementController_removeTeacher","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddTeamMemberDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Team is not a school, or the target is not a teacher"}},"security":[{"Auth0AccessToken":[]}],"summary":"Remove the teacher role from a school team member","tags":["team-management"]}},"/team-management/pending-member-role":{"put":{"operationId":"TeamManagementController_setPendingMemberRole","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPendingMemberRoleDto"}}}},"responses":{"200":{"description":"The stored invitation role"},"400":{"description":"Teacher role requested on a team that is not a school"},"404":{"description":"No pending or failed invitation for this team and email"},"409":{"description":"The invitation was accepted before the role could be changed"}},"security":[{"Auth0AccessToken":[]}],"summary":"Change a pending invitation role without resending the invitation","tags":["team-management"]}},"/team-management/member-role":{"put":{"operationId":"TeamManagementController_setMemberRole","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetSchoolMemberRoleDto"}}}},"responses":{"200":{"description":"The final stored school role"},"400":{"description":"Team is not a school (regular teams use assign-admin / remove-admin), or the target is not a registered member"}},"security":[{"Auth0AccessToken":[]}],"summary":"Atomically set an existing school member role","tags":["team-management"]}},"/team-management/update-team-size":{"post":{"operationId":"TeamManagementController_updateTeamSize","parameters":[],"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["team-management"]}},"/team-management/all-members":{"get":{"operationId":"TeamManagementController_getAllMembers","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetAllTeamMembersResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["team-management"]}},"/team-management/schools/{teamId}/staff-usage":{"get":{"operationId":"TeamManagementController_getSchoolStaffUsage","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"range_days","required":false,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetStaffUsageResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Per-staff Focus Bear usage across a school + roll-up (school admins/owner only)","tags":["team-management"]}},"/team-management/name":{"put":{"operationId":"TeamManagementController_updateTeamName","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTeamNameDto"}}}},"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["team-management"]}},"/team-management/class-session-window":{"put":{"operationId":"TeamManagementController_updateClassSessionWindow","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateClassSessionWindowDto"}}}},"responses":{"200":{"description":"Window updated"},"400":{"description":"Invalid window (bad HH:mm or start >= end), or team is not a school"},"401":{"description":"Caller is not an admin of the team"}},"security":[{"Auth0AccessToken":[]}],"summary":"Set the school-wide time-of-day window during which teachers may start a class session","tags":["team-management"]}},"/team-management/admin-teams":{"get":{"operationId":"TeamManagementController_getAdminUserTeams","parameters":[{"name":"include_teaching","required":false,"in":"query","schema":{"type":"boolean"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Teams the caller administers; include_teaching=true also returns teams they teach, flagged with access_role","tags":["team-management"]}},"/team-management":{"delete":{"operationId":"TeamManagementController_deleteTeam","parameters":[],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["team-management"]}},"/team-management/member-expiry":{"put":{"operationId":"TeamManagementController_updateMemberExpiryDate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMemberExpiryDateDto"}}}},"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["team-management"]}},"/team-management/add-member-manually":{"post":{"operationId":"TeamManagementController_addTeamMemberManually","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddTeamManuallyDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["team-management"]}},"/team-management/member-insights":{"get":{"operationId":"TeamManagementController_getMemberInsights","parameters":[{"name":"team_id","required":true,"in":"query","description":"The UUID of the team the member belongs to","schema":{"format":"uuid","example":"b9f1bce9-c130-4141-80d6-3bde32a66542","type":"string"}},{"name":"member_id","required":true,"in":"query","description":"The UUID of the member to fetch insights for","schema":{"format":"uuid","example":"550e8400-e29b-41d4-a716-446655440001","type":"string"}}],"responses":{"200":{"description":"Member insights with devices","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetMemberInsightsResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["team-management"]}},"/service-account/team-management/all-members":{"get":{"operationId":"ServiceAccountTeamManagementController_getAllMembers","parameters":[{"name":"team_id","required":true,"in":"query","description":"The UUID of the team to retrieve members for","schema":{"example":"b9f1bce9-c130-4141-80d6-3bde32a66542","type":"string"}}],"responses":{"200":{"description":"Successfully retrieved all team members","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAccountTeamMembersResponseDto"}}}},"401":{"description":"Unauthorized - Invalid or missing service account token"},"403":{"description":"Forbidden - Insufficient permissions or team ID mismatch"}},"security":[{"Auth0AccessToken":[]}],"tags":["service-account-team-management"]}},"/team-management/admin/teams":{"get":{"operationId":"AdminTeamManagementController_listTeams","parameters":[{"name":"search","required":false,"in":"query","description":"Matches on team name (partial, case-insensitive), exact team id, or exact owner email.","schema":{"maxLength":255,"type":"string"}},{"name":"take","required":false,"in":"query","schema":{"minimum":1,"type":"number"}},{"name":"skip","required":false,"in":"query","schema":{"minimum":0,"type":"number"}},{"name":"include_classes","required":false,"in":"query","description":"Classes (is_class) are excluded by default — they are managed via class-management.","schema":{"type":"boolean"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Paginated team list (search by name/id/owner email; classes excluded unless include_classes=true)","tags":["team-management"]},"post":{"operationId":"AdminTeamManagementController_createTeam","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminCreateTeamDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Create a team (typically an offline license); owner resolved by email, entitlements granted","tags":["team-management"]}},"/team-management/admin/teams/{id}":{"patch":{"operationId":"AdminTeamManagementController_updateTeam","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUpdateTeamDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Partial team update; expiry changes propagate to entitlements, payment-type change guarded","tags":["team-management"]}},"/habit-packs/{pack_id}":{"get":{"operationId":"HabitPackController_getHabitPackById","parameters":[{"name":"pack_id","required":false,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HabitPack"}}}}},"tags":["habit-packs"]},"delete":{"operationId":"HabitPackController_deleteHabitPack","parameters":[{"name":"pack_id","required":false,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseMessage"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["habit-packs"]}},"/habit-packs":{"get":{"operationId":"HabitPackController_getHabitPacks","parameters":[{"name":"marketplace_approval_status","required":false,"in":"query","schema":{"type":"boolean"}},{"name":"is_featured","required":false,"in":"query","schema":{"type":"boolean"}},{"name":"featured_for_onboarding","required":false,"in":"query","schema":{"type":"boolean"}},{"name":"pack_type","required":false,"in":"query","schema":{"type":"string"}},{"name":"language","required":false,"in":"query","schema":{"type":"string"}},{"name":"user_id","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"breaks_only","required":false,"in":"query","schema":{"type":"boolean"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/HabitPack"}}}}}},"tags":["habit-packs"]},"put":{"operationId":"HabitPackController_createOrUpdateHabitPack","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertHabitPackDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HabitPack"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["habit-packs"]}},"/habit-packs/user":{"get":{"operationId":"HabitPackController_getUserHabitPacks","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/HabitPack"}}}}}},"tags":["habit-packs"]}},"/habit-packs/{pack_id}/install":{"post":{"operationId":"HabitPackController_installHabitPack","parameters":[{"name":"pack_id","required":false,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseMessage"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["habit-packs"]}},"/habit-packs/{pack_id}/uninstall":{"delete":{"operationId":"HabitPackController_uninstallHabitPack","parameters":[{"name":"pack_id","required":false,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseMessage"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["habit-packs"]}},"/habit-packs/default":{"get":{"operationId":"HabitPackController_installPackAsDefaultSettings","parameters":[{"name":"pack_id","required":false,"in":"query","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserSettingsResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["habit-packs"]}},"/habit-packs/user-packs":{"get":{"operationId":"HabitPackController_getUserInstalledPacks","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/HabitPack"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["habit-packs"]}},"/habit-packs/installed-standalone-packs":{"get":{"operationId":"HabitPackController_getUserInstalledStandalonePacks","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/InstalledStandalonePackResponse"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["habit-packs"]}},"/focus-mode-template":{"put":{"operationId":"FocusModeTemplatesController_upsertFocusModeTemplate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertFocusModeTemplateDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FocusModeTemplate"}}}}},"tags":["focus-mode-template"]},"get":{"operationId":"FocusModeTemplatesController_getMultipleFocusModeTemplates","parameters":[{"name":"marketplace_approval_status","required":false,"in":"query","schema":{"type":"boolean"}},{"name":"is_featured","required":false,"in":"query","schema":{"type":"boolean"}},{"name":"featured_for_onboarding","required":false,"in":"query","schema":{"type":"boolean"}},{"name":"language","required":false,"in":"query","schema":{"type":"string"}},{"name":"author_id","required":false,"in":"query","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FocusModeTemplate"}}}}}},"tags":["focus-mode-template"]}},"/focus-mode-template/{template_id}/install":{"post":{"operationId":"FocusModeTemplatesController_installFocusModeForUser","parameters":[],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FocusMode"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["focus-mode-template"]}},"/focus-mode-template/{template_id}":{"get":{"operationId":"FocusModeTemplatesController_getFocusModeTemplateById","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FocusModeTemplate"}}}}},"tags":["focus-mode-template"]},"delete":{"operationId":"FocusModeTemplatesController_deleteFocusModeTemplate","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseMessage"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["focus-mode-template"]}},"/focus-mode-template/user":{"get":{"operationId":"FocusModeTemplatesController_getUserFocusModeTemplates","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FocusModeTemplate"}}}}}},"tags":["focus-mode-template"]}},"/focus-mode-template/user-installed":{"get":{"operationId":"FocusModeTemplatesController_getUserInstalledFocusModeTemplates","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FocusModeTemplate"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["focus-mode-template"]}},"/focus-mode/shared":{"get":{"operationId":"SharedFocusModeController_listSharedForMe","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Shared focus modes of every team the caller administers/owns (incl. school via parent team)","tags":["focus-mode"]},"post":{"operationId":"SharedFocusModeController_createSharedFocusMode","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSharedFocusModeDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Create a team-shared focus mode (team admin only)","tags":["focus-mode"]}},"/focus-mode/shared/{focus_mode_id}":{"patch":{"operationId":"SharedFocusModeController_updateSharedFocusMode","parameters":[{"name":"focus_mode_id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFocusModeDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Update a team-shared focus mode (admin of its team only)","tags":["focus-mode"]},"delete":{"operationId":"SharedFocusModeController_deleteSharedFocusMode","parameters":[{"name":"focus_mode_id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Delete a team-shared focus mode (admin of its team only)","tags":["focus-mode"]}},"/focus-mode":{"post":{"operationId":"FocusModeController_createFocusMode","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFocusModeDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["focus-mode"]},"put":{"operationId":"FocusModeController_updateFocusModes","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["focus-mode"]},"get":{"operationId":"FocusModeController_fetchFocusModes","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["focus-mode"]},"delete":{"operationId":"FocusModeController_bulkDeleteFocusModes","parameters":[{"name":"id","required":true,"in":"query","schema":{"type":"string"}},{"name":"team_id","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["focus-mode"]}},"/focus-mode/{focus_mode_id}":{"patch":{"operationId":"FocusModeController_updateFocusMode","parameters":[{"name":"focus_mode_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFocusModeDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["focus-mode"]}},"/focus-mode/current":{"get":{"operationId":"FocusModeController_getCurrentFocusSession","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["focus-mode"]}},"/focus-mode/current/to-dos":{"post":{"operationId":"FocusModeController_attachToDoToCurrentSession","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachToDoDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["focus-mode"]}},"/focus-mode/current/to-dos/{to_do_id}":{"delete":{"operationId":"FocusModeController_detachToDoFromCurrentSession","parameters":[{"name":"to_do_id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["focus-mode"]}},"/focus-mode/{focus_mode_id}/start":{"post":{"operationId":"FocusModeController_startCurrentFocusMode","parameters":[{"name":"focus_mode_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartFocusModeDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseMessage"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["focus-mode"]}},"/focus-mode/{focus_mode_id}/finish":{"post":{"operationId":"FocusModeController_finishCurrentFocusMode","parameters":[{"name":"focus_mode_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FinishFocusModeDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseMessage"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["focus-mode"]}},"/focus-mode/{focus_mode_id}/pause":{"post":{"operationId":"FocusModeController_pauseCurrentFocusMode","parameters":[{"name":"focus_mode_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseMessage"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["focus-mode"]}},"/focus-mode/{focus_mode_id}/resume":{"post":{"operationId":"FocusModeController_resumeCurrentFocusMode","parameters":[{"name":"focus_mode_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseMessage"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["focus-mode"]}},"/focus-mode/tags":{"get":{"operationId":"FocusModeController_getUserFocusTags","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["focus-mode"]},"put":{"operationId":"FocusModeController_upsertFocusModeTag","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFocusModeTagDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FocusModeTag"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["focus-mode"]},"delete":{"operationId":"FocusModeController_deleteFocusModeTag","parameters":[{"name":"tag_id","required":true,"in":"query","schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["focus-mode"]}},"/focus-mode/{focus_mode_id}/update_scheduled_finish":{"patch":{"operationId":"FocusModeController_updateScheduledFinish","parameters":[{"name":"focus_mode_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateScheduledFinishDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseMessage"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["focus-mode"]}},"/completed-focus-blocks":{"get":{"operationId":"CompletedFocusBlocksController_getFocusBlockStats","parameters":[{"name":"focus_mode_id","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"tag_id","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"project_id","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"from_time","required":false,"in":"query","schema":{"format":"date-time","type":"string"}},{"name":"to_time","required":false,"in":"query","schema":{"format":"date-time","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FocusModeDaySummaryItem"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["focus-mode"]}},"/blocking-schedules":{"get":{"operationId":"BlockingScheduleController_getBlockingSchedules","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BlockingSchedule"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["focus-mode"]},"post":{"operationId":"BlockingScheduleController_createBlockingSchedule","parameters":[{"name":"device_id","required":false,"in":"query","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertBlockingScheduleDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlockingSchedule"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["focus-mode"]}},"/blocking-schedules/{id}":{"put":{"operationId":"BlockingScheduleController_updateBlockingSchedule","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"device_id","required":false,"in":"query","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertBlockingScheduleDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlockingSchedule"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["focus-mode"]},"delete":{"operationId":"BlockingScheduleController_deleteBlockingSchedule","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"device_id","required":false,"in":"query","schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["focus-mode"]}},"/to-do/saved-views":{"get":{"operationId":"ToDoSavedViewController_listSavedViews","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToDoSavedViewListResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"List the caller's saved To-do filter views, oldest first","tags":["to-do-saved-views"]},"post":{"operationId":"ToDoSavedViewController_createSavedView","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateToDoSavedViewDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToDoSavedViewResponseDto"}}}},"409":{"description":"Body is { code, message }. code is \"to_do_saved_view_name_taken\" when the caller already has a view with this name (case-insensitive), or \"to_do_saved_view_limit_reached\" when they already have 100 views; the latter is not retryable with a different name"}},"security":[{"Auth0AccessToken":[]}],"summary":"Save the current To-do filters as a named view","tags":["to-do-saved-views"]}},"/to-do/saved-views/{id}":{"get":{"operationId":"ToDoSavedViewController_getSavedView","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToDoSavedViewResponseDto"}}}},"404":{"description":"No saved view with this id belongs to the caller"}},"security":[{"Auth0AccessToken":[]}],"summary":"Get one saved To-do filter view","tags":["to-do-saved-views"]},"patch":{"operationId":"ToDoSavedViewController_updateSavedView","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateToDoSavedViewDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToDoSavedViewResponseDto"}}}},"404":{"description":"No saved view with this id belongs to the caller"},"409":{"description":"The caller already has a view with this name (case-insensitive); body is { code: \"to_do_saved_view_name_taken\", message }"}},"security":[{"Auth0AccessToken":[]}],"summary":"Rename a saved view or replace its filters / sort mode","tags":["to-do-saved-views"]},"delete":{"operationId":"ToDoSavedViewController_deleteSavedView","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""},"404":{"description":"No saved view with this id belongs to the caller"}},"security":[{"Auth0AccessToken":[]}],"summary":"Delete a saved view","tags":["to-do-saved-views"]}},"/to-do":{"put":{"operationId":"TodoController_upsertToDo","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateToDoDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["to-do"]},"get":{"operationId":"TodoController_getUserToDos","parameters":[{"name":"order","required":false,"in":"query","schema":{"default":"ASC","type":"string","enum":["ASC","DESC"]}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"take","required":false,"in":"query","schema":{"minimum":1,"maximum":50,"default":10,"type":"number"}},{"name":"status","required":false,"in":"query","schema":{"type":"string","enum":["NOT_STARTED","IN_PROGRESS","COMPLETED"]}},{"name":"exclude_completed","required":false,"in":"query","description":"Exclude effectively completed tasks before pagination. Known native custom columns override raw status; other tasks use materialized COMPLETED status. Intersects the optional status filter. When applied, response meta.excludesCompleted is true.","schema":{"type":"boolean"}},{"name":"eisenhower_quadrant","required":false,"in":"query","schema":{"minimum":1,"maximum":4,"type":"number"}},{"name":"should_use_cache","required":false,"in":"query","description":"Deprecated. `GET /to-do` always serves cached data; integration freshness is driven by the off-thread sync worker. This field is ignored.","deprecated":true,"schema":{"default":true,"type":"boolean"}},{"name":"project_id","required":false,"in":"query","description":"Filter tasks belonging to a native Focus Bear project.","schema":{"format":"uuid","type":"string"}},{"name":"project_ids","required":false,"in":"query","description":"Tasks in any of these native projects (comma-separated, repeated, or both). Empty = no project filter. Intersects `project_id` when both are sent.","schema":{"type":"array","items":{"type":"string","format":"uuid"}}},{"name":"sort_mode","required":false,"in":"query","description":"Ordering strategy for the returned page. `SMART` ranks by the computed TOP score, `CHRONOLOGICAL` by creation time — both honour the `order` param. `DUE_DATE` sorts by task due date ascending (earliest and overdue first) with undated tasks last, tie-broken by `id`; it ignores `order`, which is always treated as ascending.","schema":{"default":"SMART","type":"string","enum":["SMART","CHRONOLOGICAL","DUE_DATE"]}},{"name":"scope","required":false,"in":"query","description":"`OWNED` (default) returns every to-do the caller owns, whoever it is assigned to. `MINE` returns the caller's own work: to-dos they own that are unassigned or assigned to themselves, plus native project to-dos a colleague owns and assigned to them in a project they still own or are an accepted member of. To-dos the caller owns but assigned to someone else are left out.","schema":{"default":"OWNED","type":"string","enum":["OWNED","MINE"]}},{"name":"include_comments","required":false,"in":"query","description":"Include comments (with reactions) for each task","schema":{"default":false,"type":"boolean"}},{"name":"include_reactions","required":false,"in":"query","description":"Include task-level reactions for each task","schema":{"default":false,"type":"boolean"}},{"name":"tag_id","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"perspiration_gte","required":false,"in":"query","schema":{"minimum":1,"maximum":10,"type":"number"}},{"name":"perspiration_lte","required":false,"in":"query","schema":{"minimum":1,"maximum":10,"type":"number"}},{"name":"synced_project_id","required":false,"in":"query","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["to-do"]},"delete":{"operationId":"TodoController_deleteToDo","parameters":[{"name":"scope","required":false,"in":"query","description":"How far the delete reaches for a repeating todo. Omitted or `occurrence`\ndeletes just this row (the pre-recurrence behaviour); `series` deletes every\noccurrence that shares its `recurrence_series_id`.","schema":{"default":"occurrence","type":"string","enum":["occurrence","series"]}},{"name":"todo_id","required":true,"in":"query","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Delete a todo, or every occurrence of a repeating one with scope=series","tags":["to-do"]}},"/to-do/bulk":{"patch":{"description":"Each item is a PUT /to-do body with a required id, saved with the same rules. Always 200: each result says whether its todo was saved.","operationId":"TodoController_bulkUpdateToDos","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkUpdateToDosDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkUpdateToDosResponse"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Update many existing todos at once","tags":["to-do"]}},"/to-do/{id}":{"patch":{"operationId":"TodoController_updateToDoPlanning","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateToDoPlanningDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToDoResponse"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Update Day Plan fields on an existing todo","tags":["to-do"]}},"/to-do/generate-subtasks":{"post":{"operationId":"TodoController_generateSubtasks","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateSubtasksDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubtasksDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["to-do"]}},"/to-do/search":{"get":{"operationId":"TodoController_searchToDos","parameters":[{"name":"take","required":false,"in":"query","schema":{"minimum":10,"maximum":20,"default":10,"type":"number"}},{"name":"scope","required":false,"in":"query","description":"`OWNED` (default) returns every to-do the caller owns, whoever it is assigned to. `MINE` returns the caller's own work: to-dos they own that are unassigned or assigned to themselves, plus native project to-dos a colleague owns and assigned to them in a project they still own or are an accepted member of. To-dos the caller owns but assigned to someone else are left out.","schema":{"default":"OWNED","type":"string","enum":["OWNED","MINE"]}},{"name":"title","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"List of matching tasks","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ToDoResponse"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["to-do"]}},"/to-do/recent":{"get":{"operationId":"TodoController_recentToDos","parameters":[{"name":"status","required":false,"in":"query","schema":{"minItems":1,"default":["NOT_STARTED","IN_PROGRESS"],"type":"array","items":{"type":"string","enum":["NOT_STARTED","IN_PROGRESS","COMPLETED"]}}},{"name":"take","required":false,"in":"query","schema":{"maximum":100,"default":50,"type":"number"}},{"name":"scope","required":false,"in":"query","description":"`OWNED` (default) returns every to-do the caller owns, whoever it is assigned to. `MINE` returns the caller's own work: to-dos they own that are unassigned or assigned to themselves, plus native project to-dos a colleague owns and assigned to them in a project they still own or are an accepted member of. To-dos the caller owns but assigned to someone else are left out.","schema":{"default":"OWNED","type":"string","enum":["OWNED","MINE"]}},{"name":"updated_at","required":false,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"List of recently updated tasks","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ToDoResponse"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["to-do"]}},"/to-do/admin":{"get":{"operationId":"TodoController_getTasksForAdminDashboard","parameters":[{"name":"user_id","required":true,"in":"query","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AdminTaskResponseDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Retrieves tasks for a specific user. Used by the admin dashboard to display\nuser task data for debugging and support purposes.","tags":["to-do"]}},"/to-do/by-ids":{"get":{"operationId":"TodoController_getToDosByIds","parameters":[{"name":"ids","required":true,"in":"query","description":"Comma-separated list of to-do IDs","schema":{"minItems":1,"example":"550e8400-e29b-41d4-a716-446655440000,550e8400-e29b-41d4-a716-446655440001","type":"array","items":{"type":"string","format":"uuid"}}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ToDo"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["to-do"]}},"/to-do/convert-brain-dump":{"post":{"operationId":"TodoController_convertBrainDump","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConvertBrainDump"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BraindumpTaskDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["to-do"]}},"/to-do/generate-upload-image-url":{"post":{"operationId":"TodoController_generateUploadImageUrl","parameters":[],"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["to-do"]}},"/to-do/todo-image-uploaded":{"post":{"operationId":"TodoController_todoImageUploaded","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TodoImageUploadedDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["to-do"]}},"/to-do/generate-upload-audio-url":{"post":{"operationId":"TodoController_generateUploadAudioUrl","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateUploadAudioUrlDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["to-do"]}},"/to-do/todo-audio-uploaded":{"post":{"operationId":"TodoController_todoAudioUploaded","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TodoAudioUploadedDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["to-do"]}},"/to-do/{task_id}/comments":{"post":{"operationId":"TaskCommentController_createComment","parameters":[{"name":"task_id","required":true,"in":"path","description":"Task ID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTaskCommentDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskCommentResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["task-comments"]},"get":{"operationId":"TaskCommentController_getComments","parameters":[{"name":"task_id","required":true,"in":"path","description":"Task ID","schema":{"format":"uuid","type":"string"}},{"name":"order","required":false,"in":"query","schema":{"default":"ASC","type":"string","enum":["ASC","DESC"]}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"take","required":false,"in":"query","schema":{"minimum":1,"maximum":50,"default":10,"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["task-comments"]}},"/to-do/{task_id}/comments/{comment_id}":{"put":{"operationId":"TaskCommentController_updateComment","parameters":[{"name":"task_id","required":true,"in":"path","description":"Task ID","schema":{"format":"uuid","type":"string"}},{"name":"comment_id","required":true,"in":"path","description":"Comment ID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTaskCommentDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskCommentResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["task-comments"]},"delete":{"operationId":"TaskCommentController_deleteComment","parameters":[{"name":"task_id","required":true,"in":"path","description":"Task ID","schema":{"format":"uuid","type":"string"}},{"name":"comment_id","required":true,"in":"path","description":"Comment ID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["task-comments"]}},"/to-do/{task_id}/comments/{comment_id}/reactions":{"post":{"operationId":"TaskCommentReactionController_addReaction","parameters":[{"name":"task_id","required":true,"in":"path","description":"Task ID","schema":{"format":"uuid","type":"string"}},{"name":"comment_id","required":true,"in":"path","description":"Comment ID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTaskCommentReactionDto"}}}},"responses":{"201":{"description":"Reaction added successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskCommentReactionResponseDto"}}}},"403":{"description":"User does not have access to this task"},"404":{"description":"Comment not found"},"409":{"description":"User already reacted with this emoji"}},"security":[{"Auth0AccessToken":[]}],"summary":"Add a reaction to a task comment","tags":["task-comment-reactions"]},"get":{"operationId":"TaskCommentReactionController_getReactions","parameters":[{"name":"task_id","required":true,"in":"path","description":"Task ID","schema":{"format":"uuid","type":"string"}},{"name":"comment_id","required":true,"in":"path","description":"Comment ID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"List of reactions","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TaskCommentReactionResponseDto"}}}}},"404":{"description":"Comment not found"}},"security":[{"Auth0AccessToken":[]}],"summary":"Get all reactions for a task comment","tags":["task-comment-reactions"]},"delete":{"operationId":"TaskCommentReactionController_deleteReaction","parameters":[{"name":"task_id","required":true,"in":"path","description":"Task ID","schema":{"format":"uuid","type":"string"}},{"name":"comment_id","required":true,"in":"path","description":"Comment ID","schema":{"format":"uuid","type":"string"}},{"name":"emoji","required":true,"in":"query","description":"Emoji for the reaction (single emoji character)","schema":{"maxLength":10,"example":"👍","type":"string"}}],"responses":{"204":{"description":"Reaction removed successfully"},"404":{"description":"Comment or reaction not found"}},"security":[{"Auth0AccessToken":[]}],"summary":"Remove a reaction from a task comment","tags":["task-comment-reactions"]}},"/to-do/{task_id}/attachments/generate-upload-url":{"post":{"operationId":"TaskAttachmentController_generateUploadUrl","parameters":[{"name":"task_id","required":true,"in":"path","description":"Task ID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateUploadAttachmentUrlDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["task-attachments"]}},"/to-do/{task_id}/attachments":{"post":{"operationId":"TaskAttachmentController_createAttachment","parameters":[{"name":"task_id","required":true,"in":"path","description":"Task ID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTaskAttachmentDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskAttachmentResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["task-attachments"]},"get":{"operationId":"TaskAttachmentController_getAttachments","parameters":[{"name":"task_id","required":true,"in":"path","description":"Task ID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TaskAttachmentResponseDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["task-attachments"]}},"/to-do/{task_id}/attachments/{attachment_id}/download-url":{"get":{"operationId":"TaskAttachmentController_getDownloadUrl","parameters":[{"name":"task_id","required":true,"in":"path","description":"Task ID","schema":{"format":"uuid","type":"string"}},{"name":"attachment_id","required":true,"in":"path","description":"Attachment ID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["task-attachments"]}},"/to-do/{task_id}/attachments/{attachment_id}":{"delete":{"operationId":"TaskAttachmentController_deleteAttachment","parameters":[{"name":"task_id","required":true,"in":"path","description":"Task ID","schema":{"format":"uuid","type":"string"}},{"name":"attachment_id","required":true,"in":"path","description":"Attachment ID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["task-attachments"]}},"/to-do/{task_id}/comments/{comment_id}/attachments/generate-upload-url":{"post":{"operationId":"CommentAttachmentController_generateUploadUrl","parameters":[{"name":"task_id","required":true,"in":"path","description":"Task ID","schema":{"format":"uuid","type":"string"}},{"name":"comment_id","required":true,"in":"path","description":"Comment ID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateUploadCommentAttachmentUrlDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["comment-attachments"]}},"/to-do/{task_id}/comments/{comment_id}/attachments":{"post":{"operationId":"CommentAttachmentController_createAttachment","parameters":[{"name":"task_id","required":true,"in":"path","description":"Task ID","schema":{"format":"uuid","type":"string"}},{"name":"comment_id","required":true,"in":"path","description":"Comment ID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCommentAttachmentDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentAttachmentResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["comment-attachments"]},"get":{"operationId":"CommentAttachmentController_getAttachments","parameters":[{"name":"task_id","required":true,"in":"path","description":"Task ID","schema":{"format":"uuid","type":"string"}},{"name":"comment_id","required":true,"in":"path","description":"Comment ID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CommentAttachmentResponseDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["comment-attachments"]}},"/to-do/{task_id}/comments/{comment_id}/attachments/{attachment_id}/download-url":{"get":{"operationId":"CommentAttachmentController_getDownloadUrl","parameters":[{"name":"task_id","required":true,"in":"path","description":"Task ID","schema":{"format":"uuid","type":"string"}},{"name":"comment_id","required":true,"in":"path","description":"Comment ID","schema":{"format":"uuid","type":"string"}},{"name":"attachment_id","required":true,"in":"path","description":"Attachment ID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["comment-attachments"]}},"/to-do/{task_id}/comments/{comment_id}/attachments/{attachment_id}":{"delete":{"operationId":"CommentAttachmentController_deleteAttachment","parameters":[{"name":"task_id","required":true,"in":"path","description":"Task ID","schema":{"format":"uuid","type":"string"}},{"name":"comment_id","required":true,"in":"path","description":"Comment ID","schema":{"format":"uuid","type":"string"}},{"name":"attachment_id","required":true,"in":"path","description":"Attachment ID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["comment-attachments"]}},"/to-do/{task_id}/reactions":{"post":{"operationId":"TaskReactionController_createReaction","parameters":[{"name":"task_id","required":true,"in":"path","description":"Task ID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTaskReactionDto"}}}},"responses":{"201":{"description":"Reaction created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskReactionResponseDto"}}}},"403":{"description":"User does not have access to this task"},"404":{"description":"Task not found"},"409":{"description":"User has already reacted with this emoji"}},"security":[{"Auth0AccessToken":[]}],"summary":"Add a reaction to a task","tags":["task-reactions"]},"get":{"operationId":"TaskReactionController_getReactions","parameters":[{"name":"task_id","required":true,"in":"path","description":"Task ID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"Returns all reactions for the task","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TaskReactionResponseDto"}}}}},"403":{"description":"User does not have access to this task"},"404":{"description":"Task not found"}},"security":[{"Auth0AccessToken":[]}],"summary":"Get all reactions for a task","tags":["task-reactions"]},"delete":{"operationId":"TaskReactionController_deleteReaction","parameters":[{"name":"task_id","required":true,"in":"path","description":"Task ID","schema":{"format":"uuid","type":"string"}},{"name":"emoji","required":true,"in":"query","description":"Emoji reaction to remove","schema":{"maxLength":10,"example":"👍","type":"string"}}],"responses":{"204":{"description":"Reaction deleted successfully"},"403":{"description":"User does not have access to this task"},"404":{"description":"Task or reaction not found"}},"security":[{"Auth0AccessToken":[]}],"summary":"Remove a reaction from a task","tags":["task-reactions"]}},"/synced-projects/external-statuses":{"put":{"operationId":"SyncedProjectsController_mapExternalStatusesToComplete","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MapExternalStatusToCompleteDto"}}}},"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["synced-projects"]}},"/synced-projects":{"get":{"operationId":"SyncedProjectsController_getUserSyncedProjectsByPlatform","parameters":[{"name":"platform","required":true,"in":"query","schema":{"type":"string","enum":["zoho","clickup","trello","jira","asana","monday","google","microsoft"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SyncedProjectDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["synced-projects"]},"post":{"operationId":"SyncedProjectsController_syncProject","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncProjectDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["synced-projects"]},"delete":{"operationId":"SyncedProjectsController_unSyncProject","parameters":[{"name":"project_id","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["synced-projects"]}},"/events":{"post":{"operationId":"EventsController_logEvent","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrackEventDto"}}}},"responses":{"204":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["events"]}},"/events/admin":{"get":{"operationId":"EventsController_getTrackEventsForAdminDashboard","parameters":[{"name":"take","required":false,"in":"query","schema":{"minimum":1,"maximum":1000,"default":100,"type":"number"}},{"name":"user_id","required":true,"in":"query","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AdminTrackEventResponseDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Fetches track events for a specific user. Used by the admin support dashboard\nto view user activity history in the \"Track Events\" tab.","tags":["events"]}},"/async-task/{id}":{"get":{"description":"Retrieve the current status and details of an async task by ID","operationId":"AsyncTaskController_getTaskStatus","parameters":[{"name":"id","required":true,"in":"path","description":"Unique identifier of the async task","schema":{"example":"uuid-string","type":"string"}}],"responses":{"200":{"description":"Async task details retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AsyncTaskResponseDto"}}}},"404":{"description":"Async task not found"}},"security":[{"Auth0AccessToken":[]}],"summary":"Get async task status","tags":["async-task"]}},"/accountability-buddy/invite":{"post":{"operationId":"AccountabilityBuddyController_inviteBuddy","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteBuddyDto"}}}},"responses":{"201":{"description":"Buddy invitation sent successfully"}},"security":[{"Auth0AccessToken":[]}],"tags":["accountability-buddy"]}},"/accountability-buddy":{"get":{"operationId":"AccountabilityBuddyController_getBuddies","parameters":[],"responses":{"200":{"description":"List of accountability buddies"}},"security":[{"Auth0AccessToken":[]}],"tags":["accountability-buddy"]}},"/accountability-buddy/invitations":{"get":{"operationId":"AccountabilityBuddyController_getReceivedInvitations","parameters":[{"name":"status","required":false,"in":"query","description":"Filter invitations by status","schema":{"type":"string","enum":["pending","accepted","rejected","expired"]}}],"responses":{"200":{"description":"List of received invitations","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AccountabilityBuddyResponseDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["accountability-buddy"]}},"/accountability-buddy/invitations/accept":{"post":{"operationId":"AccountabilityBuddyController_acceptInvitation","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcceptInvitationDto"}}}},"responses":{"200":{"description":"Invitation accepted successfully"}},"security":[{"Auth0AccessToken":[]}],"tags":["accountability-buddy"]}},"/accountability-buddy/invitations/{id}/accept":{"patch":{"operationId":"AccountabilityBuddyController_acceptInvitationById","parameters":[{"name":"id","required":true,"in":"path","description":"Accountability buddy invitation ID","schema":{"format":"uuid","example":"123e4567-e89b-12d3-a456-426614174000","type":"string"}}],"responses":{"200":{"description":"Invitation accepted successfully by ID"}},"security":[{"Auth0AccessToken":[]}],"tags":["accountability-buddy"]}},"/accountability-buddy/invitations/{id}/reject":{"patch":{"operationId":"AccountabilityBuddyController_rejectInvitationById","parameters":[{"name":"id","required":true,"in":"path","description":"Accountability buddy invitation ID","schema":{"format":"uuid","example":"123e4567-e89b-12d3-a456-426614174000","type":"string"}}],"responses":{"200":{"description":"Invitation rejected successfully"}},"security":[{"Auth0AccessToken":[]}],"tags":["accountability-buddy"]}},"/accountability-buddy/{id}":{"delete":{"operationId":"AccountabilityBuddyController_removeBuddy","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":"Buddy removed successfully"}},"security":[{"Auth0AccessToken":[]}],"tags":["accountability-buddy"]}},"/accountability-buddy/unlock-request":{"post":{"operationId":"AccountabilityBuddyController_createUnlockRequest","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUnlockRequestDto"}}}},"responses":{"201":{"description":"Unlock request created successfully"}},"security":[{"Auth0AccessToken":[]}],"tags":["accountability-buddy"]}},"/accountability-buddy/unlock-requests":{"get":{"operationId":"AccountabilityBuddyController_getUnlockRequests","parameters":[{"name":"order","required":false,"in":"query","schema":{"default":"ASC","type":"string","enum":["ASC","DESC"]}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"take","required":false,"in":"query","schema":{"minimum":1,"maximum":50,"default":10,"type":"number"}},{"name":"status","required":false,"in":"query","description":"Filter by unlock request status","schema":{"type":"string","enum":["pending","approved","rejected","expired"]}},{"name":"role","required":false,"in":"query","description":"Filter by role: sent (requests I made) or received (requests I need to approve). If not provided, returns both.","schema":{"type":"string","enum":["sent","received"]}},{"name":"created_from","required":false,"in":"query","description":"Filter requests created from this date (ISO string)","schema":{"type":"string"}},{"name":"created_to","required":false,"in":"query","description":"Filter requests created until this date (ISO string)","schema":{"type":"string"}}],"responses":{"200":{"description":"List of unlock requests","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UnlockRequestResponseDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["accountability-buddy"]}},"/accountability-buddy/unlock-request/approve":{"post":{"operationId":"AccountabilityBuddyController_approveUnlockRequestByToken","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApproveUnlockRequestByTokenDto"}}}},"responses":{"200":{"description":"Unlock request approved by token from email link"}},"security":[{"Auth0AccessToken":[]}],"tags":["accountability-buddy"]}},"/accountability-buddy/unlock-request/{id}/approve":{"patch":{"operationId":"AccountabilityBuddyController_approveUnlockRequest","parameters":[{"name":"id","required":true,"in":"path","description":"Unlock request ID","schema":{"format":"uuid","example":"123e4567-e89b-12d3-a456-426614174000","type":"string"}}],"responses":{"200":{"description":"Unlock request approved by ID (authenticated user)"}},"security":[{"Auth0AccessToken":[]}],"tags":["accountability-buddy"]}},"/accountability-buddy/unlock-request/{id}/reject":{"patch":{"operationId":"AccountabilityBuddyController_rejectUnlockRequest","parameters":[{"name":"id","required":true,"in":"path","description":"Unlock request ID","schema":{"format":"uuid","example":"123e4567-e89b-12d3-a456-426614174000","type":"string"}}],"responses":{"200":{"description":"Unlock request rejected successfully by ID"}},"security":[{"Auth0AccessToken":[]}],"tags":["accountability-buddy"]}},"/projects":{"post":{"operationId":"ProjectController_createProject","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponseDto"}}}},"409":{"description":"The project's owner already has a project with this name, ignoring case and surrounding spaces; body is { code: \"project_name_taken\", message }"}},"security":[{"Auth0AccessToken":[]}],"tags":["projects"]},"get":{"operationId":"ProjectController_getUserProjects","parameters":[{"name":"order","required":false,"in":"query","description":"Sort order by project creation date (newest first by default)","schema":{"default":"DESC","type":"string","enum":["ASC","DESC"]}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"take","required":false,"in":"query","description":"Number of projects per page","schema":{"minimum":1,"maximum":50,"default":20,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Case-insensitive substring filter on project name. Applied to both native and Zoho/synced projects.","schema":{"maxLength":255,"type":"string"}},{"name":"status","required":false,"in":"query","description":"Filter native projects by lifecycle status. Defaults to active, so completed/archived are hidden.","schema":{"default":"active","type":"string","enum":["active","completed","archived"]}},{"name":"tag","required":false,"in":"query","description":"Return only projects carrying this tag in metadata.tags. Case-insensitive (tags are stored lower-cased). Synced projects are excluded when set, as they cannot hold tags.","schema":{"maxLength":64,"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetProjectsResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["projects"]}},"/projects/invitations/pending":{"get":{"operationId":"ProjectController_getPendingInvitations","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectResponseDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["projects"]}},"/projects/{project_id}":{"get":{"operationId":"ProjectController_getProjectById","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["projects"]},"put":{"operationId":"ProjectController_updateProject","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProjectDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponseDto"}}}},"409":{"description":"The project's owner already has a project with this name, ignoring case and surrounding spaces; body is { code: \"project_name_taken\", message }. Only a real rename is checked: resending the current name, or changing only its case, is not"}},"security":[{"Auth0AccessToken":[]}],"tags":["projects"]},"delete":{"operationId":"ProjectController_deleteProject","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["projects"]}},"/projects/{project_id}/members":{"post":{"operationId":"ProjectController_inviteMember","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteProjectMemberDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectMemberResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["projects"]}},"/projects/{project_id}/members/{member_id}":{"delete":{"operationId":"ProjectController_removeMember","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"member_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":""},"400":{"description":"Cannot remove the owner, or remove yourself (use the leave endpoint)"},"403":{"description":"Caller is not an owner/admin, or an admin targeted another admin"}},"security":[{"Auth0AccessToken":[]}],"summary":"Remove a member — owner removes admins or members, admin removes members only","tags":["projects"]},"put":{"operationId":"ProjectController_updateMemberRole","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"member_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProjectMemberDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectMemberResponseDto"}}}},"400":{"description":"Cannot change or assign the owner role"},"403":{"description":"Caller is not an owner/admin, or an admin targeted another admin"}},"security":[{"Auth0AccessToken":[]}],"summary":"Update a member's role — owner changes admins or members, admin changes members only","tags":["projects"]}},"/projects/{project_id}/members/accept":{"post":{"operationId":"ProjectController_acceptInvitation","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectMemberResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["projects"]}},"/projects/{project_id}/members/leave":{"post":{"operationId":"ProjectController_leaveProject","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"201":{"description":""},"400":{"description":"The project owner cannot leave the project"},"403":{"description":"Caller is not an accepted member of this project"}},"security":[{"Auth0AccessToken":[]}],"summary":"Leave a project — accepted admins and members only; the owner cannot leave","tags":["projects"]}},"/projects/{project_id}/members/decline":{"post":{"operationId":"ProjectController_declineInvitation","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["projects"]}},"/projects/{project_id}/todos":{"get":{"operationId":"ProjectController_getToDosByProjectId","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"order","required":false,"in":"query","schema":{"default":"ASC","type":"string","enum":["ASC","DESC"]}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"take","required":false,"in":"query","schema":{"minimum":1,"maximum":50,"default":10,"type":"number"}},{"name":"status","required":false,"in":"query","schema":{"type":"string","enum":["NOT_STARTED","IN_PROGRESS","COMPLETED"]}},{"name":"custom_status_id","required":false,"in":"query","description":"Filter tasks by their project custom status column id (e.g. \"default-done\").","schema":{"maxLength":100,"type":"string"}},{"name":"sort_mode","required":false,"in":"query","description":"Mirrors `sort_mode` on the personal to-do list so the project details view\nkeeps its TOP ordering when it reads the shared project list. Omitted means\n`created_at`, which is what this endpoint has always returned — existing\ncallers (e.g. project note task embeds) are unaffected.","schema":{"type":"string","enum":["SMART","CHRONOLOGICAL","DUE_DATE"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetProjectToDosResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["projects"]}},"/class-management/classes/{teamId}/lesson-plan-preview":{"post":{"operationId":"ClassManagementController_previewLessonPlan","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"}}}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LessonPlanPreviewResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Preview tasks and relevant websites from a teacher lesson plan; does not save or start a session","tags":["class-management"]}},"/class-management/classes":{"post":{"operationId":"ClassManagementController_createClass","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateClassDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Team"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Create a class (sub-team) with the teacher as admin","tags":["class-management"]},"get":{"operationId":"ClassManagementController_getManagedClasses","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"List school-backed classes the caller owns/administers (owner, school admin, school teacher, class admin)","tags":["class-management"]}},"/class-management/classes/{teamId}":{"patch":{"operationId":"ClassManagementController_renameClass","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenameClassDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Rename a class (class admins + parent-school admins)","tags":["class-management"]}},"/class-management/classes/{teamId}/archive":{"post":{"operationId":"ClassManagementController_archiveClass","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Soft-archive a class (hidden from lists, reversible; data retained). 409 if a session is live.","tags":["class-management"]}},"/class-management/classes/{teamId}/unarchive":{"post":{"operationId":"ClassManagementController_unarchiveClass","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Restore a soft-archived class","tags":["class-management"]}},"/class-management/classes/{teamId}/candidate-members":{"get":{"operationId":"ClassManagementController_getClassCandidateMembers","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"q","required":false,"in":"query","description":"Search text matched (in memory) against first_name/last_name/email. Optional for parent-team\nowners/admins; REQUIRED (min length enforced in-service) for class admins who are not parent\nowner/admin — i.e. teachers, who never see the full school roster.","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Parent-team members annotated against the class roster (in_class, is_class_teacher) and their school Member Type (school_role: admin | teacher | member). Parent admins get the full list (q optional); teachers must pass q and only get matches (is_restricted: true)","tags":["class-management"]}},"/class-management/classes/{teamId}/members":{"post":{"operationId":"ClassManagementController_addClassMembers","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddClassMembersDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Batch-add registered parent-team members to the class (idempotent; TEACHER also gets class admin)","tags":["class-management"]}},"/class-management/classes/{teamId}/members/{memberId}":{"delete":{"operationId":"ClassManagementController_removeClassMember","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"memberId","required":true,"in":"path","description":"The `team_to_member` row id in the CLASS (not the parent team, not the user id).","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Remove a member from the class only (never touches the parent-team row)","tags":["class-management"]}},"/class-management/classes/{teamId}/attendance":{"get":{"description":"heartbeat_coverage_pct measures credited heartbeat/session-enforcement time divided by cumulative joined time. in_focus_pct is a deprecated compatibility alias. A session is missed, with opted_out_reason blocking_permissions_missing, when the student's latest explicit permission report at the end of the session was false (not a measure of how long permissions were missing); declined sessions carry opted_out_reason declined.","operationId":"ClassManagementController_getClassAttendance","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Per-student attendance matrix (joined/partial/missed) across ended sessions","tags":["class-management"]}},"/class-management/classes/{teamId}/concern-criteria":{"patch":{"operationId":"ClassManagementController_updateConcernCriteria","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateConcernCriteriaDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Update the \"students of concern\" criteria for a class (class + parent-school admins)","tags":["class-management"]}},"/class-management/sessions":{"post":{"operationId":"ClassManagementController_startClassSession","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartClassSessionDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Start a class focus session and invite every enrolled student","tags":["class-management"]},"get":{"description":"avg_heartbeat_coverage_pct replaces the deprecated avg_in_focus_pct name with identical values.","operationId":"ClassManagementController_listSessions","parameters":[{"name":"team_id","required":true,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"status","required":false,"in":"query","schema":{"type":"string","enum":["live","ended"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"List class sessions (history for the reports view)","tags":["class-management"]}},"/class-management/sessions/{id}/allowlist":{"patch":{"operationId":"ClassManagementController_amendAllowlist","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AmendAllowlistDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Amend the live allow-list (hot-syncs to all joined apps); 409 on stale version","tags":["class-management"]}},"/class-management/sessions/{id}/tasks":{"patch":{"description":"Full-set replace of the mutable fields: every existing task id must be listed exactly once. Task rows are updated in place so student completions survive. Emits class-session-tasks-updated and bumps tasks_version; allowlist_version is untouched.","operationId":"ClassManagementController_amendSessionTasks","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AmendSessionTasksDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Amend the live checklist (title, duration, order) for the session's existing tasks; 409 on stale version","tags":["class-management"]}},"/class-management/sessions/{id}/end":{"post":{"operationId":"ClassManagementController_endClassSession","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"End a live class session (force-finishes every joined student block)","tags":["class-management"]}},"/class-management/sessions/{id}/release-student":{"post":{"operationId":"ClassManagementController_releaseStudent","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveUnlockRequestsByStudentDto"}}}},"responses":{"204":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Release one student early from a live session (force-finishes just their block; session continues)","tags":["class-management"]}},"/class-management/sessions/{id}/save-allowlist-to-template":{"post":{"operationId":"ClassManagementController_saveAllowlistToTemplate","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Save the session's final allow-list back onto the linked shared focus mode (works on ended sessions)","tags":["class-management"]}},"/class-management/classes/{teamId}/live-session":{"get":{"operationId":"ClassManagementController_getLiveSession","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Current live session for a class (nullable) — dashboard reload/session discovery","tags":["class-management"]}},"/class-management/sessions/{id}/participants":{"get":{"description":"heartbeat_coverage_pct measures credited heartbeat/session-enforcement time divided by cumulative joined time. in_focus_pct is a deprecated compatibility alias. blocking_permissions_enabled is the latest explicit client report, or null when unknown. opted_out_reason is declined or blocking_permissions_missing; opted_out_count counts both once.","operationId":"ClassManagementController_getLiveParticipants","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Live roster: who joined, app state, and heartbeat coverage","tags":["class-management"]}},"/class-management/sessions/{id}/report":{"get":{"description":"heartbeat_coverage_pct measures credited heartbeat/session-enforcement time divided by cumulative joined time. It is not Focus Alignment. in_focus_pct is deprecated. blocking_permissions_enabled is the latest explicit client report (null when unknown), not historical permission coverage. opted_out_count counts declined students and students without blocking permissions once.","operationId":"ClassManagementController_getSessionReport","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"End-of-session heartbeat coverage report","tags":["class-management"]}},"/class-management/sessions/{id}/unlock-requests":{"get":{"operationId":"ClassManagementController_listUnlockRequests","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"status","required":false,"in":"query","schema":{"$ref":"#/components/schemas/Object"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ClassSessionUnlockRequest"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"List unlock requests for a session, optionally filtered by status","tags":["class-management"]}},"/class-management/unlock-requests/{id}/approve":{"post":{"operationId":"ClassManagementController_approveUnlockRequest","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClassSessionUnlockRequest"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Approve an unlock request (adds the app/site to the class allow-list live)","tags":["class-management"]}},"/class-management/unlock-requests/{id}/deny":{"post":{"operationId":"ClassManagementController_denyUnlockRequest","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClassSessionUnlockRequest"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Deny an unlock request","tags":["class-management"]}},"/class-management/sessions/{id}/unlock-requests/approve-all":{"post":{"operationId":"ClassManagementController_approveUnlockRequestsForStudent","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveUnlockRequestsByStudentDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ClassSessionUnlockRequest"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Approve every pending unlock request from one student (unions them into one allow-list amend)","tags":["class-management"]}},"/class-management/sessions/{id}/unlock-requests/reject-all":{"post":{"operationId":"ClassManagementController_rejectUnlockRequestsForStudent","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveUnlockRequestsByStudentDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ClassSessionUnlockRequest"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Reject every pending unlock request from one student","tags":["class-management"]}},"/class-session/invitations":{"get":{"operationId":"StudentClassSessionController_getInvitations","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Live class sessions the caller has been invited to (join prompt source)","tags":["class-session"]}},"/class-session/current":{"get":{"operationId":"StudentClassSessionController_getCurrentSession","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Live session where the caller is joined, invited or declined (join_status \"declined\" lets apps offer re-join) — next-launch adoption on all apps","tags":["class-session"]}},"/class-session/{id}/status":{"get":{"operationId":"StudentClassSessionController_getSessionStatus","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Whether a session is still live, for any participant status — lets declined/left students rejoin","tags":["class-session"]}},"/class-session/{id}/join":{"post":{"operationId":"StudentClassSessionController_joinSession","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Approve the join prompt: starts the enforced super-strict block on this account","tags":["class-session"]}},"/class-session/{id}/decline":{"post":{"operationId":"StudentClassSessionController_declineSession","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Decline the join prompt","tags":["class-session"]}},"/class-session/{id}/leave":{"post":{"operationId":"StudentClassSessionController_leaveSession","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Leave a joined session (teacher sees it; enforced block is force-finished)","tags":["class-session"]}},"/class-session/{id}/unlock-requests":{"post":{"operationId":"StudentClassSessionController_submitUnlockRequest","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitUnlockRequestDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClassSessionUnlockRequest"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Request an app/site unlock from the teacher","tags":["class-session"]}},"/class-session/{id}/ai-contest":{"post":{"operationId":"StudentClassSessionController_submitAiContest","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitAiContestDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Explain an AI-blocked site/app; the server re-runs the AI and records the verdict for the teacher","tags":["class-session"]}},"/class-session/{id}/heartbeat":{"post":{"description":"Report blocking_permissions_enabled as false when the OS reports a required permission missing (with missing_blocking_permissions naming them, e.g. [\"accessibility\"]), true when none is known missing, and omit both when the client cannot check. Omission/null preserves the latest explicit report within this session, including rejoins. While false, the student counts as opted out and earns no focus credit. Mac every 5s; others approximately 20-30s.","operationId":"StudentClassSessionController_recordHeartbeat","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeartbeatDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Presence heartbeat — {in_focus, device_id?, blocking_permissions_enabled?, missing_blocking_permissions?}","tags":["class-session"]}},"/class-session/{id}/tasks/{taskId}/complete":{"post":{"operationId":"StudentClassSessionController_completeTask","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"taskId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Tick a teacher-assigned task off (idempotent); fans progress to the teacher roster","tags":["class-session"]},"delete":{"operationId":"StudentClassSessionController_uncompleteTask","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"taskId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Un-tick a previously completed task (idempotent)","tags":["class-session"]}},"/webhooks/subscriptions":{"post":{"operationId":"WebhookSubscriptionController_createSubscription","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookSubscriptionDto"}}}},"responses":{"201":{"description":"Webhook subscription created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscriptionResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Create a new webhook subscription","tags":["Webhook - Subscriptions"]},"get":{"operationId":"WebhookSubscriptionController_getSubscriptions","parameters":[],"responses":{"200":{"description":"List of webhook subscriptions","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WebhookSubscriptionResponseDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"List all webhook subscriptions for the current user","tags":["Webhook - Subscriptions"]}},"/webhooks/subscriptions/{id}":{"get":{"operationId":"WebhookSubscriptionController_getSubscription","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Webhook subscription details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscriptionResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Get a specific webhook subscription","tags":["Webhook - Subscriptions"]},"patch":{"operationId":"WebhookSubscriptionController_updateSubscription","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookSubscriptionDto"}}}},"responses":{"200":{"description":"Webhook subscription updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscriptionResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Update a webhook subscription","tags":["Webhook - Subscriptions"]},"delete":{"operationId":"WebhookSubscriptionController_deleteSubscription","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Webhook subscription deleted successfully"}},"security":[{"Auth0AccessToken":[]}],"summary":"Delete a webhook subscription","tags":["Webhook - Subscriptions"]}},"/external/v1/me":{"get":{"operationId":"ExternalApiController_getCurrentUser","parameters":[],"responses":{"200":{"description":"User information retrieved successfully"}},"security":[{"Auth0AccessToken":[]}],"summary":"Get current user information","tags":["External API (Zapier/n8n)"]}},"/external/v1/focus-modes":{"get":{"operationId":"ExternalApiController_getFocusModes","parameters":[],"responses":{"200":{"description":"Focus modes retrieved successfully"}},"security":[{"Auth0AccessToken":[]}],"summary":"Get user focus modes","tags":["External API (Zapier/n8n)"]}},"/external/v1/routines":{"get":{"operationId":"ExternalApiController_getRoutines","parameters":[],"responses":{"200":{"description":"Routines retrieved successfully"}},"security":[{"Auth0AccessToken":[]}],"summary":"Get user routines (morning, evening, break)","tags":["External API (Zapier/n8n)"]}},"/external/v1/webhooks/sample/{eventType}":{"get":{"operationId":"ExternalApiController_getWebhookSample","parameters":[{"name":"eventType","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Sample webhook payload"}},"security":[{"Auth0AccessToken":[]}],"summary":"Get a sample webhook payload for testing","tags":["External API (Zapier/n8n)"]}},"/external/v1/focus-session/start":{"post":{"operationId":"ExternalApiController_startFocusSession","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartFocusSessionDto"}}}},"responses":{"200":{"description":"Focus session started successfully"}},"security":[{"Auth0AccessToken":[]}],"summary":"Start a focus session by focus mode name","tags":["External API (Zapier/n8n)"]}},"/external/v1/habit/complete":{"post":{"operationId":"ExternalApiController_completeHabit","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompleteHabitDto"}}}},"responses":{"200":{"description":"Habit completed successfully"}},"security":[{"Auth0AccessToken":[]}],"summary":"Complete a habit by name and routine name","tags":["External API (Zapier/n8n)"]}},"/external/v1/streaks":{"get":{"operationId":"ExternalApiController_getStreaks","parameters":[],"responses":{"200":{"description":"Streaks retrieved successfully"}},"security":[{"Auth0AccessToken":[]}],"summary":"Get user streaks","tags":["External API (Zapier/n8n)"]}},"/integration/assignee":{"get":{"operationId":"IntegrationController_getAssigneeStatus","parameters":[],"responses":{"200":{"description":""}},"tags":["Integration"]}},"/integration/{platform}":{"get":{"operationId":"IntegrationController_getPortals","parameters":[{"name":"platform","required":true,"in":"path","schema":{"type":"string","enum":["zoho","clickup","trello","jira","asana","monday","google","microsoft"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Portal"}}}}}},"tags":["Integration"]}},"/integration/{platform}/projects/all":{"get":{"operationId":"IntegrationController_getAllProjects","parameters":[{"name":"platform","required":true,"in":"path","schema":{"type":"string","enum":["zoho","clickup","trello","jira","asana","monday","google","microsoft"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IntegrationProject"}}}}}},"tags":["Integration"]}},"/integration/{platform}/user-projects":{"get":{"operationId":"IntegrationController_getAllUserProjects","parameters":[{"name":"platform","required":true,"in":"path","schema":{"type":"string","enum":["zoho","clickup","trello","jira","asana","monday","google","microsoft"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SyncedProjectDto"}}}}}},"tags":["Integration"]}},"/integration/{platform}/sync-project":{"post":{"operationId":"IntegrationController_syncProject","parameters":[{"name":"platform","required":true,"in":"path","schema":{"type":"string","enum":["zoho","clickup","trello","jira","asana","monday","google","microsoft"]}}],"responses":{"201":{"description":""}},"tags":["Integration"]}},"/integration/{platform}/sync-tasks":{"post":{"operationId":"IntegrationController_manuallySyncTasks","parameters":[{"name":"platform","required":true,"in":"path","schema":{"type":"string","enum":["zoho","clickup","trello","jira","asana","monday","google","microsoft"]}}],"responses":{"201":{"description":""}},"tags":["Integration"]}},"/integration/{platform}/{portalId}/projects":{"get":{"operationId":"IntegrationController_getProjects","parameters":[{"name":"platform","required":true,"in":"path","schema":{"type":"string","enum":["zoho","clickup","trello","jira","asana","monday","google","microsoft"]}},{"name":"portalId","required":false,"in":"path","schema":{"type":"string"}},{"name":"projectId","required":false,"in":"path","schema":{"type":"string"}},{"name":"taskId","required":false,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IntegrationProject"}}}}}},"tags":["Integration"]}},"/integration/{platform}/{portalId}/projects/{projectId}/tasks":{"get":{"operationId":"IntegrationController_getTasks","parameters":[{"name":"platform","required":true,"in":"path","schema":{"type":"string","enum":["zoho","clickup","trello","jira","asana","monday","google","microsoft"]}},{"name":"portalId","required":false,"in":"path","schema":{"type":"string"}},{"name":"projectId","required":false,"in":"path","schema":{"type":"string"}},{"name":"taskId","required":false,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Task"}}}}}},"tags":["Integration"]}},"/integration/{platform}/{portalId}/projects/{projectId}/tasks/{taskId}/logs":{"post":{"operationId":"IntegrationController_addTimeEntry","parameters":[{"name":"platform","required":true,"in":"path","schema":{"type":"string","enum":["zoho","clickup","trello","jira","asana","monday","google","microsoft"]}},{"name":"portalId","required":false,"in":"path","schema":{"type":"string"}},{"name":"projectId","required":false,"in":"path","schema":{"type":"string"}},{"name":"taskId","required":false,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTimeLog"}}}},"responses":{"201":{"description":""}},"tags":["Integration"]}},"/integration/{platform}/assignee-filter-status":{"put":{"operationId":"IntegrationController_updateAssigneeFilterStatus","parameters":[{"name":"platform","required":true,"in":"path","schema":{"type":"string","enum":["zoho","clickup","trello","jira","asana","monday","google","microsoft"]}}],"responses":{"200":{"description":""}},"tags":["Integration"]}},"/notifications":{"patch":{"description":"Identify the event by `id`, or by `external_id` together with `platform` and `platform_account`. Setting `is_dismissed` to true on an event that was not already dismissed also notifies the other devices of the user, exactly as the dismiss endpoint does — `device_id` included, so the caller can ignore its own echo. `device_id` is never stored on the event.","operationId":"NotificationController_updateOrCreateCalendarEvent","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCalendarEventDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCalendarEventDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Create or update a calendar event","tags":["notifications"]}},"/notifications/calendar-events/dismiss":{"post":{"description":"Call this when the user joins or silences a meeting on one device, so the rest stop alerting. The meeting is identified by `summary` and `event_begins` rather than by a calendar id, because the Mac app, the phone and the backend each know the same meeting by a different id. Events that the backend has never synced are accepted too: the other devices still hold their own copy. The dismissal is broadcast both as a silent FCM/Beams push (mobile) and as a `late-no-more-event-dismissed` Pusher Channels event on `private-<userId>` (desktop); send `device_id` to have your own device echoed back so you can ignore your own event.","operationId":"NotificationController_dismissCalendarEvent","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DismissCalendarEventDto"}}}},"responses":{"204":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Dismiss a meeting reminder on every device of the user","tags":["notifications"]}},"/activity-library":{"get":{"operationId":"ActivityLibraryController_getLibraryActivities","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UpdateActivityDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["activity-library"]},"put":{"operationId":"ActivityLibraryController_upsertLibraryActivities","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UpdateActivityDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["activity-library"]}},"/activity-library/routine-suggestions":{"post":{"operationId":"ActivityLibraryController_getRoutineSuggestions","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetRoutineSuggestionsDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Too many requests"}},"security":[{"Auth0AccessToken":[]}],"summary":"Get routine suggestions based on user goals","tags":["activity-library"]}},"/activity-library/routine-suggestions/async":{"post":{"operationId":"ActivityLibraryController_getRoutineSuggestionsAsync","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetRoutineSuggestionsDto"}}}},"responses":{"202":{"description":"Routine suggestion task accepted"}},"security":[{"Auth0AccessToken":[]}],"summary":"Request routine suggestions asynchronously","tags":["activity-library"]}},"/activity-library/adjust-habits-with-ai":{"post":{"operationId":"ActivityLibraryController_adjustHabitsWithAi","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdjustHabitsWithAiDto"}}}},"responses":{"200":{"description":"Habits adjusted successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UpdateActivityTemplateDto"}}}}},"400":{"description":"Invalid request data"},"401":{"description":"Unauthorized"}},"security":[{"Auth0AccessToken":[]}],"summary":"Adjust habits using AI based on user feedback","tags":["activity-library"]}},"/activity-library/adjust-habits-with-ai/async":{"post":{"operationId":"ActivityLibraryController_adjustHabitsWithAiAsync","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdjustHabitsWithAiDto"}}}},"responses":{"202":{"description":"Adjust habits task accepted"}},"security":[{"Auth0AccessToken":[]}],"summary":"Adjust habits with AI asynchronously","tags":["activity-library"]}},"/activity-library/habits/ai/async":{"post":{"operationId":"ActivityLibraryController_createHabitWithAiAsync","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateHabitWithAiDto"}}}},"responses":{"202":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Create habits using AI asynchronously (RAG preferred)","tags":["activity-library"]}},"/activity-library/habits/import/generate-upload-url":{"post":{"operationId":"ActivityLibraryController_generateHabitImportUploadUrl","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateImportUploadUrlDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["activity-library"]}},"/activity-library/habits/import/async":{"post":{"operationId":"ActivityLibraryController_triggerHabitImport","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HabitImportUploadedDto"}}}},"responses":{"202":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["activity-library"]}},"/support-request":{"post":{"operationId":"SupportRequestController_submit","parameters":[{"name":"idempotency-key","required":true,"in":"header","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"UUID v4 request idempotency key","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSupportRequestDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"example":{"submitted":true,"request_id":"3d908555-6a1f-4a78-bf7f-52e9201292fc"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Submit a native support form to the Zoho Desk support inbox","tags":["support-request"]}},"/student-discount/status":{"get":{"operationId":"StudentDiscountController_getStatus","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"example":{"verified":true}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Get student discount eligibility status","tags":["student-discount"]}},"/student-discount/request-code":{"post":{"operationId":"StudentDiscountController_requestCode","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestStudentDiscountCodeDto"}}}},"responses":{"200":{"description":"Code sent, already verified, or routed to manual review","content":{"application/json":{"schema":{"example":{"status":"code_sent","masked_email":"stud***@example.edu","expires_in_seconds":900,"resend_after_seconds":30}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Request student discount email verification","tags":["student-discount"]}},"/student-discount/verify-code":{"post":{"operationId":"StudentDiscountController_verifyCode","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyStudentDiscountCodeDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"example":{"verified":true}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Verify student discount email ownership","tags":["student-discount"]}},"/video-metadata":{"post":{"operationId":"VideoMetadataController_updateVideosMetadata","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VideoMetadataBodyDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VideoMetadataResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["activity"]}},"/tracks":{"get":{"operationId":"TracksController_getAllTracks","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TrackResponseDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["tracks"]},"put":{"operationId":"TracksController_upsertTrack","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertTrackDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Track"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["tracks"]}},"/course/admin":{"get":{"operationId":"CoursesController_getAllCourses","parameters":[{"name":"order","required":false,"in":"query","schema":{"default":"ASC","type":"string","enum":["ASC","DESC"]}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"take","required":false,"in":"query","schema":{"minimum":1,"maximum":50,"default":10,"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["course"]}},"/course":{"post":{"operationId":"CoursesController_createCourse","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCourseDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Course"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["course"]}},"/course/{course_id}":{"get":{"operationId":"CoursesController_getCourseDetails","parameters":[{"name":"course_id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Course"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["course"]},"patch":{"operationId":"CoursesController_updateCourse","parameters":[{"name":"course_id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCourseDto"}}}},"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["course"]},"delete":{"operationId":"CoursesController_deleteCourse","parameters":[{"name":"course_id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteCourseDto"}}}},"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["course"]}},"/course/{course_id}/hide":{"patch":{"operationId":"CoursesController_hideCourse","parameters":[{"name":"course_id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCourseHideDto"}}}},"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["course"]}},"/course/{course_id}/rating":{"get":{"operationId":"CoursesController_getCourseRatings","parameters":[{"name":"course_id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CourseRating"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["course"]}},"/course/rating":{"post":{"operationId":"CoursesController_createCourseRating","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCourseRatingDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CourseRating"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["course"]}},"/course/enrolled":{"post":{"operationId":"CoursesController_createCourseEnrolment","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCourseEnrolmentDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CourseEnrolment"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["course"]},"patch":{"operationId":"CoursesController_updateCourseLessonCompletion","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCourseEnrolmentDto"}}}},"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["course"]},"get":{"operationId":"CoursesController_getUserEnrolledCourses","parameters":[{"name":"language","required":false,"in":"query","schema":{"type":"string","enum":["en","es","de","ja","vi","pt-BR","pt-PT","zh-CN","zh-TW","nl","tl","fr","it","pl","ru","ar","ro"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Course"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["course"]}},"/course/user":{"get":{"operationId":"CoursesController_getUserCourses","parameters":[{"name":"hidden","required":false,"in":"query","schema":{"default":true,"type":"boolean"}},{"name":"deleted","required":false,"in":"query","schema":{"default":true,"type":"boolean"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Course"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["course"]}},"/course/user-not-enrolled":{"get":{"operationId":"CoursesController_getUserNotEnrolledCourses","parameters":[{"name":"language","required":false,"in":"query","schema":{"type":"string","enum":["en","es","de","ja","vi","pt-BR","pt-PT","zh-CN","zh-TW","nl","tl","fr","it","pl","ru","ar","ro"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["course"]}},"/course/sync-platform-courses":{"post":{"operationId":"CoursesController_syncPlatformCourses","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncPlatformCoursesDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["course"]}},"/course/user-tutorials":{"get":{"operationId":"CoursesController_getUserTutorials","parameters":[{"name":"language","required":false,"in":"query","schema":{"type":"string","enum":["en","es","de","ja","vi","pt-BR","pt-PT","zh-CN","zh-TW","nl","tl","fr","it","pl","ru","ar","ro"]}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["course"]}},"/course/{course_id}/discussion":{"get":{"operationId":"CourseDiscussionController_getCourseDiscussion","parameters":[{"name":"course_id","required":true,"in":"path","schema":{"type":"string"}},{"name":"order","required":false,"in":"query","schema":{"default":"DESC","type":"string","enum":["ASC","DESC"]}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"take","required":false,"in":"query","schema":{"minimum":1,"maximum":50,"default":10,"type":"number"}}],"responses":{"200":{"description":""},"404":{"description":"Course couldn't be found"}},"security":[{"Auth0AccessToken":[]}],"summary":"List a page of non-deleted discussion threads for a course","tags":["course"]},"post":{"operationId":"CourseDiscussionController_createThread","parameters":[{"name":"course_id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDiscussionThreadDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Course couldn't be found"}},"security":[{"Auth0AccessToken":[]}],"summary":"Start a discussion thread on a course","tags":["course"]}},"/course/{course_id}/discussion/{thread_id}/reply":{"post":{"operationId":"CourseDiscussionController_createReply","parameters":[{"name":"course_id","required":true,"in":"path","schema":{"type":"string"}},{"name":"thread_id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDiscussionReplyDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Course or thread couldn't be found"}},"security":[{"Auth0AccessToken":[]}],"summary":"Reply to a course discussion thread","tags":["course"]},"get":{"operationId":"CourseDiscussionController_getDiscussionReplies","parameters":[{"name":"course_id","required":true,"in":"path","schema":{"type":"string"}},{"name":"thread_id","required":true,"in":"path","schema":{"type":"string"}},{"name":"order","required":false,"in":"query","schema":{"default":"ASC","type":"string","enum":["ASC","DESC"]}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"take","required":false,"in":"query","schema":{"minimum":1,"maximum":50,"default":10,"type":"number"}}],"responses":{"200":{"description":""},"404":{"description":"Course or thread couldn't be found"}},"security":[{"Auth0AccessToken":[]}],"summary":"List a page of non-deleted replies for a discussion thread","tags":["course"]}},"/lesson/{course_id}":{"get":{"operationId":"LessonsController_getLessons","parameters":[{"name":"course_id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Lesson"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["lesson"]}},"/lesson":{"patch":{"operationId":"LessonsController_upsertLessons","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertLessonsDto"}}}},"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["lesson"]},"delete":{"operationId":"LessonsController_deleteLesson","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteLessonDto"}}}},"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["lesson"]}},"/lesson/complete":{"post":{"operationId":"LessonsController_createLessonCompletion","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLessonCompletionDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["lesson"]}},"/tab-keywords":{"post":{"operationId":"TabKeywordsController_getKeywords","parameters":[],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["tab-keywords"]}},"/common-apps":{"get":{"operationId":"CommonAppsController_getCommonApps","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommonAppsResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"The shared table of well-known apps and their platform identities, for app pickers and matching.","tags":["common-apps"]}},"/app-logs":{"post":{"operationId":"AppLogsController_uploadFile","parameters":[],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Deprecated: Use the user/uninstall endpoint instead","tags":["app-logs"]}},"/app-logs/upload-logs-url":{"get":{"operationId":"AppLogsController_generateUploadUrl","parameters":[{"name":"mimetype","required":true,"in":"query","schema":{"type":"string","enum":["text/plain","application/zip"]}},{"name":"filename","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"string"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["app-logs"]}},"/app-logs/notify-upload-success":{"post":{"operationId":"AppLogsController_notifyLogsUploadSuccess","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotifyLogsUploadSuccessDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["app-logs"]}},"/saved-website":{"get":{"operationId":"SavedWebsiteController_getUserSavedWebsites","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SavedWebsite"}}}}}},"tags":["saved-website"]},"post":{"operationId":"SavedWebsiteController_saveWebsite","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SavedWebsite"}}}}}},"tags":["saved-website"]},"delete":{"operationId":"SavedWebsiteController_deleteSavedWebsite","parameters":[{"name":"website_id","required":true,"in":"query","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseMessage"}}}}},"tags":["saved-website"]}},"/saved-website/delete":{"put":{"operationId":"SavedWebsiteController_deleteMultipleWebsites","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseMessage"}}}}},"tags":["saved-website"]}},"/browser-bookmarks/sync":{"get":{"description":"Without a cursor: every live item, paged. With one: every item created, changed or deleted since it, deletions included (deleted_at set). Page while has_more is true, then store next_cursor for the next sync.","operationId":"BrowserBookmarkController_syncBookmarks","parameters":[{"name":"cursor","required":false,"in":"query","description":"next_cursor from the previous response. Omit for a first sync (live items only); with it, the response holds every item created, changed or deleted since, deletions included.","schema":{"maxLength":256,"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":1000,"default":500,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrowserBookmarkSyncResponseDto"}}}},"400":{"description":"Body is { code, message }; code is one of: browser_bookmark_invalid_cursor"}},"security":[{"Auth0AccessToken":[]}],"summary":"Read bookmark changes since a cursor","tags":["browser-bookmarks"]}},"/browser-bookmarks/import":{"post":{"description":"A flat list where each item names its folder by client_parent_id. Items whose client_id is already stored are skipped, so a retried or resumed import never duplicates. Large libraries go in several requests, parents first.","operationId":"BrowserBookmarkController_importBookmarks","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportBrowserBookmarksDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportBrowserBookmarksResponseDto"}}}},"400":{"description":"Body is { code, message }; code is one of: browser_bookmark_import_duplicate_client_id, browser_bookmark_import_parent_unresolved, browser_bookmark_import_cycle, browser_bookmark_parent_not_folder, browser_bookmark_url_required, browser_bookmark_url_not_allowed_on_folder"},"409":{"description":"Body is { code, message }; code is one of: browser_bookmark_parent_not_found, browser_bookmark_parent_not_folder, browser_bookmark_limit_reached. The limit is 25000 live items; nothing is imported when it would be exceeded."}},"security":[{"Auth0AccessToken":[]}],"summary":"Import a bookmark tree (e.g. from Chrome)","tags":["browser-bookmarks"]}},"/browser-bookmarks/{id}":{"get":{"operationId":"BrowserBookmarkController_getBookmark","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrowserBookmarkResponseDto"}}}},"404":{"description":"No live bookmark or folder with this id belongs to the caller"}},"security":[{"Auth0AccessToken":[]}],"summary":"Get one live bookmark or folder","tags":["browser-bookmarks"]},"patch":{"operationId":"BrowserBookmarkController_updateBookmark","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBrowserBookmarkDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrowserBookmarkResponseDto"}}}},"400":{"description":"Body is { code, message }; code is one of: browser_bookmark_url_not_allowed_on_folder"},"404":{"description":"No live bookmark or folder with this id belongs to the caller"},"409":{"description":"Body is { code, message }; code is one of: browser_bookmark_parent_not_found, browser_bookmark_parent_not_folder, browser_bookmark_move_into_descendant"}},"security":[{"Auth0AccessToken":[]}],"summary":"Rename, re-point, move or reorder a bookmark or folder","tags":["browser-bookmarks"]},"delete":{"operationId":"BrowserBookmarkController_deleteBookmark","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""},"404":{"description":"No live bookmark or folder with this id belongs to the caller"}},"security":[{"Auth0AccessToken":[]}],"summary":"Delete a bookmark, or a folder and everything in it","tags":["browser-bookmarks"]}},"/browser-bookmarks":{"post":{"description":"Retry-safe with client_id: a live item with the same client_id is returned unchanged.","operationId":"BrowserBookmarkController_createBookmark","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBrowserBookmarkDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrowserBookmarkResponseDto"}}}},"400":{"description":"Body is { code, message }; code is one of: browser_bookmark_url_required, browser_bookmark_url_not_allowed_on_folder"},"409":{"description":"Body is { code, message }; code is one of: browser_bookmark_parent_not_found, browser_bookmark_parent_not_folder, browser_bookmark_limit_reached"}},"security":[{"Auth0AccessToken":[]}],"summary":"Create a bookmark or folder","tags":["browser-bookmarks"]}},"/ai/chat":{"post":{"operationId":"AiController_getCompletion","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateChatBotResponseDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["ai"]}},"/managed-blocking/categories":{"get":{"operationId":"ManagedBlockingController_categories","parameters":[],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/bypass-sites":{"get":{"operationId":"ManagedBlockingController_bypassSites","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"One list for every app: managed policies and class sessions both apply it.","tags":["managed-blocking"]}},"/managed-blocking/context":{"get":{"operationId":"ManagedBlockingController_context","parameters":[],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/effective-policy":{"get":{"operationId":"ManagedBlockingController_effective","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/schools/{schoolId}/policies":{"get":{"operationId":"ManagedBlockingController_list","parameters":[{"name":"schoolId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]},"post":{"operationId":"ManagedBlockingController_create","parameters":[{"name":"schoolId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedPolicyDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/policies/{policyId}":{"put":{"operationId":"ManagedBlockingController_update","parameters":[{"name":"policyId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateManagedPolicyDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/policies/{policyId}/publish":{"post":{"operationId":"ManagedBlockingController_publish","parameters":[{"name":"policyId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevisionDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/schools/{schoolId}/students":{"get":{"operationId":"ManagedBlockingController_students","parameters":[{"name":"schoolId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/schools/{schoolId}/students/year-level":{"put":{"operationId":"ManagedBlockingController_updateYearLevel","parameters":[{"name":"schoolId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateManagedYearLevelDto"}}}},"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/schools/{schoolId}/assignments":{"put":{"operationId":"ManagedBlockingController_assign","parameters":[{"name":"schoolId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignManagedPolicyDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/schools/{schoolId}/assignments/{studentId}":{"delete":{"operationId":"ManagedBlockingController_unassign","parameters":[{"name":"schoolId","required":true,"in":"path","schema":{"type":"string"}},{"name":"studentId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/children/{studentId}/effective-policy":{"get":{"operationId":"ManagedBlockingController_childEffective","parameters":[{"name":"studentId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/children/{studentId}/home-policy":{"get":{"operationId":"ManagedBlockingController_home","parameters":[{"name":"studentId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/policies/{policyId}/history":{"get":{"operationId":"ManagedBlockingController_history","parameters":[{"name":"policyId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/children/{studentId}/parents":{"get":{"operationId":"ManagedBlockingController_parentList","parameters":[{"name":"studentId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/schools/{schoolId}/children/{studentId}/parents":{"post":{"operationId":"ManagedBlockingController_invite","parameters":[{"name":"schoolId","required":true,"in":"path","schema":{"type":"string"}},{"name":"studentId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteManagedParentDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/parent-grants/invitations":{"get":{"operationId":"ManagedBlockingController_invitations","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/parent-grants/{grantId}/accept":{"post":{"operationId":"ManagedBlockingController_accept","parameters":[{"name":"grantId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/parent-grants/{grantId}":{"delete":{"operationId":"ManagedBlockingController_revoke","parameters":[{"name":"grantId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/settings-edit-requests":{"get":{"operationId":"ManagedBlockingController_inbox","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]},"post":{"operationId":"ManagedBlockingController_request","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSettingsEditDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/settings-edit-requests/{id}":{"get":{"operationId":"ManagedBlockingController_requestStatus","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/settings-edit-requests/{id}/approve":{"post":{"operationId":"ManagedBlockingController_approve","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/settings-edit-requests/{id}/reject":{"post":{"operationId":"ManagedBlockingController_reject","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/settings-edit-requests/{id}/propose":{"post":{"operationId":"ManagedBlockingController_propose","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProposeSettingsEditDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/settings-edit-requests/{id}/commit":{"post":{"operationId":"ManagedBlockingController_commit","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommitSettingsEditDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/policies/{policyId}/test-url":{"post":{"operationId":"ManagedSafetyController_test","parameters":[{"name":"policyId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestManagedUrlDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/check-url":{"post":{"operationId":"ManagedSafetyController_check","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckManagedUrlDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/policies/{policyId}/test-app":{"post":{"operationId":"ManagedSafetyController_testApp","parameters":[{"name":"policyId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestManagedAppDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/check-app":{"post":{"operationId":"ManagedSafetyController_checkApp","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckManagedAppDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/violations":{"get":{"operationId":"ManagedSafetyController_list","parameters":[{"name":"student_id","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"school_id","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"take","required":true,"in":"query","schema":{"minimum":1,"maximum":100,"default":50,"allOf":[{"$ref":"#/components/schemas/Object"}]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]},"post":{"operationId":"ManagedSafetyController_ingest","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OfflineViolationsDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/violations/{violationId}/appeals":{"post":{"operationId":"ManagedSafetyController_appeal","parameters":[{"name":"violationId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateManagedAppealDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]},"get":{"operationId":"ManagedSafetyController_history","parameters":[{"name":"violationId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/device-receipts":{"post":{"operationId":"ManagedNativeController_receipt","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedDeviceReceiptDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/children/{studentId}/device-receipts":{"get":{"operationId":"ManagedNativeController_receipts","parameters":[{"name":"studentId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/managed-blocking/violations/batch":{"post":{"operationId":"ManagedNativeController_violations","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MinimalOfflineViolationsDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["managed-blocking"]}},"/survey":{"post":{"operationId":"SurveyController_createSurvey","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSurveyDto"}}}},"responses":{"201":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["survey"]},"patch":{"operationId":"SurveyController_updateSurvey","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSurveyDto"}}}},"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["survey"]},"get":{"operationId":"SurveyController_getSurveys","parameters":[{"name":"order","required":false,"in":"query","schema":{"default":"ASC","type":"string","enum":["ASC","DESC"]}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"take","required":false,"in":"query","schema":{"minimum":1,"maximum":50,"default":10,"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["survey"]}},"/survey/{survey_id}/answer":{"post":{"operationId":"SurveyController_createSurveyAnswer","parameters":[{"name":"survey_id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSurveyAnswerDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SurveyAnswer"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["survey"]}},"/survey/{survey_id}/completed":{"patch":{"operationId":"SurveyController_updateSurveyAnswerCompletion","parameters":[{"name":"survey_id","required":true,"in":"path","schema":{"type":"string"}},{"name":"completed","required":true,"in":"query","schema":{"type":"boolean"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["survey"]}},"/survey/unanswered":{"get":{"operationId":"SurveyController_getUserUnansweredSurveys","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Survey"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["survey"]}},"/survey/answers_completed":{"get":{"operationId":"SurveyController_getAnsweredSurveys","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Survey"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["survey"]}},"/survey/answers_uncompleted":{"get":{"operationId":"SurveyController_getUnCompletedAnsweredSurveys","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Survey"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["survey"]}},"/support/customer-lookup":{"post":{"operationId":"SupportPanelController_lookup","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerLookupDto"}}}},"responses":{"200":{"description":"Lookup outcome for the ticket, echoing the ticket id"},"503":{"description":"Zoho Desk or Auth0 could not be reached. The body carries `service`: `zoho_desk` or `auth0`"}},"security":[{"Auth0AccessToken":[]}],"summary":"Resolve the Focus Bear customer for a Zoho Desk ticket","tags":["support-panel"]}},"/support/action-token":{"post":{"operationId":"SupportPanelController_issueActionToken","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActionTokenDto"}}}},"responses":{"200":{"description":"Lookup outcome for the ticket, with an action token when a customer was found"},"503":{"description":"Zoho Desk or Auth0 could not be reached. The body carries `service`: `zoho_desk` or `auth0`"}},"security":[{"Auth0AccessToken":[]}],"summary":"Resolve the ticket customer and issue a single-use token for one sensitive action","tags":["support-panel"]}},"/support/cancel-subscription":{"post":{"operationId":"SupportPanelController_cancelSubscription","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelSubscriptionDto"}}}},"responses":{"200":{"description":"What happened to the subscription, echoing the ticket id"},"503":{"description":"A check or the audit record could not be completed, and nothing was cancelled. The body carries `service`: `zoho_desk`, `auth0`, `action_token_store` or `audit_store`"}},"security":[{"Auth0AccessToken":[]}],"summary":"Stop the subscription of the customer an action token names from renewing","tags":["support-panel"]}},"/projects/{project_id}/notes":{"post":{"operationId":"ProjectNoteController_createNote","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectNoteDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectNoteResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Create a shared note in a project","tags":["project-notes"]},"get":{"operationId":"ProjectNoteController_getNotes","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"order","required":false,"in":"query","schema":{"default":"ASC","type":"string","enum":["ASC","DESC"]}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"take","required":false,"in":"query","schema":{"minimum":1,"maximum":50,"default":10,"type":"number"}},{"name":"archived","required":false,"in":"query","description":"Omitted or false returns only active (non-archived) notes — the default, so existing clients are unaffected. True returns only archived notes. Soft-deleted notes are excluded either way.","schema":{"type":"boolean"}},{"name":"tag_id","required":false,"in":"query","description":"Only notes carrying this tag of the project.","schema":{"format":"uuid","type":"string"}},{"name":"pinned","required":false,"in":"query","description":"True returns only the notes the caller pinned. Omitted or false applies no pin filter, so existing clients are unaffected.","schema":{"type":"boolean"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Get paginated shared notes for a project (active by default, archived=true for the archive)","tags":["project-notes"]}},"/projects/{project_id}/notes/tags":{"get":{"operationId":"ProjectNoteController_getProjectTags","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectNoteTagResponseDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Get the project's note tags (for suggesting and filtering) — any accepted project member","tags":["project-notes"]}},"/projects/{project_id}/notes/{note_id}":{"get":{"operationId":"ProjectNoteController_getNoteById","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectNoteResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Get a single shared note (including its content)","tags":["project-notes"]},"patch":{"description":"pinned pins or unpins the note for the caller only; pinned_at in responses is the caller's own pin.","operationId":"ProjectNoteController_updateNote","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProjectNoteDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectNoteResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Update a shared note (title, content, tags, archived and/or pinned) — any accepted project member, admin or owner","tags":["project-notes"]},"delete":{"operationId":"ProjectNoteController_deleteNote","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Delete a shared note","tags":["project-notes"]}},"/projects/{project_id}/notes/{note_id}/doc":{"get":{"operationId":"ProjectNoteController_getNoteDoc","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteDocResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Get a note's collaborative document state (Y.Doc + rendered content)","tags":["project-notes"]},"put":{"operationId":"ProjectNoteController_saveNoteDoc","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveNoteDocDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteDocResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Persist a snapshot of a note's collaborative document","tags":["project-notes"]}},"/projects/{project_id}/notes/{note_id}/realtime-auth":{"post":{"operationId":"ProjectNoteController_authorizeRealtime","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RealtimeAuthDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RealtimeAuthResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Authorise a Pusher presence subscription to a note's realtime channel","tags":["project-notes"]}},"/projects/{project_id}/notes/{note_id}/comments":{"post":{"operationId":"ProjectNoteCommentController_addComment","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateNoteCommentDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteCommentResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Add a comment to a shared note","tags":["project-note-comments"]},"get":{"operationId":"ProjectNoteCommentController_getComments","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"order","required":false,"in":"query","schema":{"default":"ASC","type":"string","enum":["ASC","DESC"]}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"take","required":false,"in":"query","schema":{"minimum":1,"maximum":50,"default":10,"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Get paginated comments for a shared note","tags":["project-note-comments"]}},"/projects/{project_id}/notes/{note_id}/comments/{comment_id}":{"delete":{"operationId":"ProjectNoteCommentController_deleteComment","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"comment_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Delete your own comment on a shared note","tags":["project-note-comments"]}},"/projects/{project_id}/note-embeds/tasks":{"get":{"operationId":"ProjectNoteEmbedController_resolveTasks","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"ids","required":true,"in":"query","schema":{"type":"array","items":{"type":"string","format":"uuid"}}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EmbeddableTaskResponseDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Resolve embedded tasks by id for note task-embeds","tags":["project-note-embeds"]}},"/projects/{project_id}/notes/{note_id}/images/upload-url":{"post":{"operationId":"ProjectNoteImageController_createUpload","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateNoteImageUploadDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteImageUploadResponseDto"}}}},"400":{"description":"note_image_unsupported_type | note_image_too_large"},"409":{"description":"note_image_limit_reached"}},"security":[{"Auth0AccessToken":[]}],"summary":"Start an image upload: returns a presigned PUT URL and the future image id","tags":["project-note-images"]}},"/projects/{project_id}/notes/{note_id}/images/{image_id}/complete":{"post":{"operationId":"ProjectNoteImageController_completeUpload","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"image_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompleteNoteImageUploadDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteImageResponseDto"}}}},"400":{"description":"note_image_not_uploaded | note_image_unsupported_type | note_image_too_large"},"409":{"description":"note_image_limit_reached"}},"security":[{"Auth0AccessToken":[]}],"summary":"Confirm an uploaded image: verifies the bytes and makes it embeddable","tags":["project-note-images"]}},"/projects/{project_id}/notes/{note_id}/images":{"get":{"operationId":"ProjectNoteImageController_listImages","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NoteImageResponseDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"List a note's images, each with a fresh short-lived URL","tags":["project-note-images"]}},"/projects/{project_id}/notes/{note_id}/images/{image_id}":{"get":{"operationId":"ProjectNoteImageController_getImage","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"image_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteImageResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Get one image with a fresh short-lived URL","tags":["project-note-images"]},"delete":{"operationId":"ProjectNoteImageController_deleteImage","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"image_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Delete an image and its stored file — its uploader, the note author or a project admin","tags":["project-note-images"]}},"/projects/{project_id}/notes/{note_id}/audio/upload-url":{"post":{"operationId":"ProjectNoteAudioController_createUpload","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateNoteAudioUploadDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteImageUploadResponseDto"}}}},"400":{"description":"note_audio_unsupported_type | note_audio_too_large"},"409":{"description":"note_audio_limit_reached"}},"security":[{"Auth0AccessToken":[]}],"summary":"Start an audio upload: returns a presigned PUT URL and the future audio id","tags":["project-note-audio"]}},"/projects/{project_id}/notes/{note_id}/audio/{audio_id}/complete":{"post":{"operationId":"ProjectNoteAudioController_completeUpload","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"audio_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompleteNoteImageUploadDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteImageResponseDto"}}}},"400":{"description":"note_audio_not_uploaded | note_audio_unsupported_type | note_audio_too_large"},"409":{"description":"note_audio_limit_reached"}},"security":[{"Auth0AccessToken":[]}],"summary":"Confirm an uploaded recording: verifies the bytes and makes it embeddable","tags":["project-note-audio"]}},"/projects/{project_id}/notes/{note_id}/audio":{"get":{"operationId":"ProjectNoteAudioController_listAudio","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NoteImageResponseDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"List a note's recordings, each with a fresh short-lived URL","tags":["project-note-audio"]}},"/projects/{project_id}/notes/{note_id}/audio/{audio_id}":{"get":{"operationId":"ProjectNoteAudioController_getAudio","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"audio_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteImageResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Get one recording with a fresh short-lived URL","tags":["project-note-audio"]},"delete":{"operationId":"ProjectNoteAudioController_deleteAudio","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"audio_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Delete a recording and its stored file — its uploader, the note author or a project admin","tags":["project-note-audio"]}},"/projects/{project_id}/notes/{note_id}/pdfs/upload-url":{"post":{"operationId":"ProjectNotePdfController_createUpload","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateNotePdfUploadDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteImageUploadResponseDto"}}}},"400":{"description":"note_pdf_unsupported_type | note_pdf_too_large"},"409":{"description":"note_pdf_limit_reached"}},"security":[{"Auth0AccessToken":[]}],"summary":"Start a PDF upload: returns a presigned PUT URL and the future PDF id","tags":["project-note-pdfs"]}},"/projects/{project_id}/notes/{note_id}/pdfs/{pdf_id}/complete":{"post":{"operationId":"ProjectNotePdfController_completeUpload","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"pdf_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompleteNoteImageUploadDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteImageResponseDto"}}}},"400":{"description":"note_pdf_not_uploaded | note_pdf_unsupported_type | note_pdf_too_large"},"409":{"description":"note_pdf_limit_reached"}},"security":[{"Auth0AccessToken":[]}],"summary":"Confirm an uploaded PDF: verifies the bytes and makes it embeddable","tags":["project-note-pdfs"]}},"/projects/{project_id}/notes/{note_id}/pdfs":{"get":{"operationId":"ProjectNotePdfController_listPdfs","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NoteImageResponseDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"List a note's PDFs, each with a fresh short-lived URL","tags":["project-note-pdfs"]}},"/projects/{project_id}/notes/{note_id}/pdfs/{pdf_id}":{"get":{"operationId":"ProjectNotePdfController_getPdf","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"pdf_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteImageResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Get one PDF with a fresh short-lived URL","tags":["project-note-pdfs"]},"delete":{"operationId":"ProjectNotePdfController_deletePdf","parameters":[{"name":"project_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"pdf_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Delete a PDF and its stored file — its uploader, the note author or a project admin","tags":["project-note-pdfs"]}},"/portfolio":{"get":{"operationId":"PortfolioController_getPortfolio","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortfolioResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["portfolio"]}},"/portfolio/forecast":{"get":{"operationId":"PortfolioController_getForecast","parameters":[{"name":"days","required":false,"in":"query","schema":{"minimum":1,"maximum":90,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortfolioForecastResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["portfolio"]}},"/portfolio/settings":{"get":{"operationId":"PortfolioController_getSettings","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortfolioSettingsResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["portfolio"]},"put":{"operationId":"PortfolioController_updateSettings","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePortfolioSettingsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortfolioSettingsResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["portfolio"]}},"/portfolio/busy-hours":{"put":{"operationId":"PortfolioController_updateBusyHours","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportBusyHoursDto"}}}},"responses":{"204":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["portfolio"]}},"/app-versions/latest":{"get":{"description":"Retrieve latest app version for specific operating system","operationId":"AppVersionsController_getLatestAppVersion","parameters":[{"name":"os_name","required":true,"in":"query","description":"Operating system name (case-insensitive)","schema":{"example":"iOS","type":"string","enum":["iOS","Android","MacOS","Windows","Web"]}},{"name":"is_beta","required":false,"in":"query","description":"Include beta versions","schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"description":"Latest version information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LatestAppVersionResponseDto"}}}}},"summary":"Get latest app version","tags":["app-versions"]}},"/app-versions/create-version":{"post":{"operationId":"AppVersionsController_createAppVersion","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAppVersionDto"}}}},"responses":{"201":{"description":"Version created successfully"},"401":{"description":"Unauthorized"}},"security":[{"bearer":[]}],"summary":"Create new app version (CI/CD)","tags":["app-versions"]}},"/note/folders":{"get":{"operationId":"NoteFolderController_getFolders","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NoteFolderResponseDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Get every one of the current user's note folders, A-Z (nest them by parent_id)","tags":["note"]},"put":{"description":"Creates a folder when no id is given, otherwise renames it (name) or moves it (parent_id, null for the top level). Creating with a system_key the user already has returns that folder unchanged, so a folder a client makes for itself exists once however many devices ask for it.","operationId":"NoteFolderController_upsertFolder","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertNoteFolderDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteFolderResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Create, rename or move a note folder","tags":["note"]}},"/note/folders/{id}":{"delete":{"description":"Its subfolders are deleted too. The notes inside are kept, back among the unfiled notes.","operationId":"NoteFolderController_deleteFolder","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Delete a note folder","tags":["note"]}},"/note":{"put":{"description":"Creates a note when no id is given, otherwise updates it. A request with is_brain_dump=true that does not resolve to an existing note updates the user's existing brain dump instead of creating a second one; setting is_brain_dump=true on a different existing note is rejected with 409 while a brain dump exists. pinned=true/false pins or unpins the note (pinned_at is set by the server); a request that only pins leaves updated_at unchanged.","operationId":"NoteController_upsertNote","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateNoteDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteResponseDto"}}}},"409":{"description":"The user already has a different brain dump note"}},"security":[{"Auth0AccessToken":[]}],"summary":"Create or update a note","tags":["note"]},"get":{"operationId":"NoteController_getUserNotes","parameters":[{"name":"order","required":false,"in":"query","schema":{"default":"ASC","type":"string","enum":["ASC","DESC"]}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"take","required":false,"in":"query","schema":{"minimum":1,"maximum":50,"default":10,"type":"number"}},{"name":"pinned","required":false,"in":"query","description":"True returns only pinned notes. Omitted or false applies no pin filter, so existing clients are unaffected.","schema":{"type":"boolean"}},{"name":"folder_id","required":false,"in":"query","description":"Only the notes filed directly in this folder. Takes precedence over unfiled.","schema":{"format":"uuid","type":"string"}},{"name":"unfiled","required":false,"in":"query","description":"True returns only notes in no folder. Omitted or false applies no folder filter, so existing clients see every note.","schema":{"type":"boolean"}},{"name":"completed_activity_id","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"tag_id","required":false,"in":"query","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Get paginated notes for the current user","tags":["note"]},"delete":{"operationId":"NoteController_deleteNote","parameters":[{"name":"note_id","required":true,"in":"query","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Delete a note for the current user","tags":["note"]}},"/note/search":{"get":{"operationId":"NoteController_searchNotes","parameters":[{"name":"take","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":20,"type":"number"}},{"name":"query","required":false,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NoteResponseDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Search notes for the current user","tags":["note"]}},"/note/tags":{"get":{"operationId":"NoteController_getUserTags","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NoteTag"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Get all note tags for the current user","tags":["note"]}},"/note/{id}":{"get":{"operationId":"NoteController_getNoteById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Get a note by id for the current user","tags":["note"]}},"/note/{note_id}/images/upload-url":{"post":{"operationId":"NoteImageController_createUpload","parameters":[{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateNoteImageUploadDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteImageUploadResponseDto"}}}},"400":{"description":"note_image_unsupported_type | note_image_too_large"},"409":{"description":"note_image_limit_reached"}},"security":[{"Auth0AccessToken":[]}],"summary":"Start an image upload: returns a presigned PUT URL and the future image id","tags":["note-images"]}},"/note/{note_id}/images/{image_id}/complete":{"post":{"operationId":"NoteImageController_completeUpload","parameters":[{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"image_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompleteNoteImageUploadDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteImageResponseDto"}}}},"400":{"description":"note_image_not_uploaded | note_image_unsupported_type | note_image_too_large"},"409":{"description":"note_image_limit_reached"}},"security":[{"Auth0AccessToken":[]}],"summary":"Confirm an uploaded image: verifies the bytes and makes it embeddable","tags":["note-images"]}},"/note/{note_id}/images":{"get":{"operationId":"NoteImageController_listImages","parameters":[{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NoteImageResponseDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"List a note's images, each with a fresh short-lived URL","tags":["note-images"]}},"/note/{note_id}/images/{image_id}":{"get":{"operationId":"NoteImageController_getImage","parameters":[{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"image_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteImageResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Get one image with a fresh short-lived URL","tags":["note-images"]},"delete":{"operationId":"NoteImageController_deleteImage","parameters":[{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"image_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Delete an image and its stored file","tags":["note-images"]}},"/note/{note_id}/audio/upload-url":{"post":{"operationId":"NoteAudioController_createUpload","parameters":[{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateNoteAudioUploadDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteImageUploadResponseDto"}}}},"400":{"description":"note_audio_unsupported_type | note_audio_too_large"},"409":{"description":"note_audio_limit_reached"}},"security":[{"Auth0AccessToken":[]}],"summary":"Start an audio upload: returns a presigned PUT URL and the future audio id","tags":["note-audio"]}},"/note/{note_id}/audio/{audio_id}/complete":{"post":{"operationId":"NoteAudioController_completeUpload","parameters":[{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"audio_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompleteNoteImageUploadDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteImageResponseDto"}}}},"400":{"description":"note_audio_not_uploaded | note_audio_unsupported_type | note_audio_too_large"},"409":{"description":"note_audio_limit_reached"}},"security":[{"Auth0AccessToken":[]}],"summary":"Confirm an uploaded recording: verifies the bytes and makes it embeddable","tags":["note-audio"]}},"/note/{note_id}/audio":{"get":{"operationId":"NoteAudioController_listAudio","parameters":[{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NoteImageResponseDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"List a note's recordings, each with a fresh short-lived URL","tags":["note-audio"]}},"/note/{note_id}/audio/{audio_id}":{"get":{"operationId":"NoteAudioController_getAudio","parameters":[{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"audio_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteImageResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Get one recording with a fresh short-lived URL","tags":["note-audio"]},"delete":{"operationId":"NoteAudioController_deleteAudio","parameters":[{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"audio_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Delete a recording and its stored file","tags":["note-audio"]}},"/note/{note_id}/pdfs/upload-url":{"post":{"operationId":"NotePdfController_createUpload","parameters":[{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateNotePdfUploadDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteImageUploadResponseDto"}}}},"400":{"description":"note_pdf_unsupported_type | note_pdf_too_large"},"409":{"description":"note_pdf_limit_reached"}},"security":[{"Auth0AccessToken":[]}],"summary":"Start a PDF upload: returns a presigned PUT URL and the future PDF id","tags":["note-pdfs"]}},"/note/{note_id}/pdfs/{pdf_id}/complete":{"post":{"operationId":"NotePdfController_completeUpload","parameters":[{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"pdf_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompleteNoteImageUploadDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteImageResponseDto"}}}},"400":{"description":"note_pdf_not_uploaded | note_pdf_unsupported_type | note_pdf_too_large"},"409":{"description":"note_pdf_limit_reached"}},"security":[{"Auth0AccessToken":[]}],"summary":"Confirm an uploaded PDF: verifies the bytes and makes it embeddable","tags":["note-pdfs"]}},"/note/{note_id}/pdfs":{"get":{"operationId":"NotePdfController_listPdfs","parameters":[{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NoteImageResponseDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"List a note's PDFs, each with a fresh short-lived URL","tags":["note-pdfs"]}},"/note/{note_id}/pdfs/{pdf_id}":{"get":{"operationId":"NotePdfController_getPdf","parameters":[{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"pdf_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteImageResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Get one PDF with a fresh short-lived URL","tags":["note-pdfs"]},"delete":{"operationId":"NotePdfController_deletePdf","parameters":[{"name":"note_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"pdf_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"204":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Delete a PDF and its stored file","tags":["note-pdfs"]}},"/note/generate/upload-url":{"post":{"operationId":"NoteGenerationController_createUpload","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateNoteGenerationUploadDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteGenerationUploadResponseDto"}}}},"400":{"description":"note_generation_unsupported_type | note_generation_too_large"}},"security":[{"Auth0AccessToken":[]}],"summary":"Start a photo upload for note generation: returns a presigned PUT URL","tags":["note"]}},"/note/generate":{"post":{"description":"Returns an async task to poll. The draft is not saved: the client reviews it and saves it with PUT /note.","operationId":"NoteGenerationController_generateNote","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateNoteFromImageDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateNoteFromImageResponseDto"}}}},"400":{"description":"note_generation_not_uploaded | note_generation_unsupported_type | note_generation_too_large"}},"security":[{"Auth0AccessToken":[]}],"summary":"Generate a draft note from an uploaded photo","tags":["note"]}},"/revise/decks":{"get":{"operationId":"ReviseDeckController_listDecks","parameters":[{"name":"updated_since","required":false,"in":"query","description":"ISO time; when set, deleted decks are returned as tombstones","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseDeckListResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"List the user's flashcard decks; with updated_since, changes and tombstones since then","tags":["revise"]},"post":{"operationId":"ReviseDeckController_createDeck","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReviseDeckDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseDeckResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Create a deck; repeating a client-generated id returns the existing deck","tags":["revise"]}},"/revise/decks/{id}":{"patch":{"operationId":"ReviseDeckController_updateDeck","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateReviseDeckDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseDeckResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Rename a deck or change the note/project it belongs to","tags":["revise"]},"delete":{"operationId":"ReviseDeckController_deleteDeck","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Delete a deck and its cards","tags":["revise"]}},"/revise/cards":{"get":{"operationId":"ReviseCardController_listCards","parameters":[{"name":"updated_since","required":false,"in":"query","description":"ISO time; when set, deleted cards are returned as tombstones","schema":{"type":"string"}},{"name":"deck_id","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"cursor","required":false,"in":"query","description":"next_cursor from the previous page","schema":{"maxLength":256,"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":500,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseCardPageResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Page through cards; with updated_since, changes and tombstones since then","tags":["revise"]},"post":{"operationId":"ReviseCardController_createCard","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReviseCardDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseCardResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Create a card; repeating a client-generated id returns the existing card","tags":["revise"]}},"/revise/cards/rewrite-queue":{"get":{"operationId":"ReviseCardController_getRewriteQueue","parameters":[{"name":"deck_id","required":false,"in":"query","description":"Limit to one deck; omit for every deck","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseCardListResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Cards flagged for rewriting, which block the next session until resolved","tags":["revise"]}},"/revise/cards/batch":{"post":{"operationId":"ReviseCardController_createCardBatch","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchCreateReviseCardsDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseCardListResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Create up to 100 cards at once, all or nothing (used to save AI drafts)","tags":["revise"]}},"/revise/cards/{id}":{"get":{"operationId":"ReviseCardController_getCard","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseCardResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["revise"]},"patch":{"operationId":"ReviseCardController_updateCard","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateReviseCardDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseCardResponseDto"}}}},"409":{"description":"expected_updated_at did not match; the body carries the current card"}},"security":[{"Auth0AccessToken":[]}],"summary":"Edit a card, move it between decks, or flag it for rewriting","tags":["revise"]},"delete":{"operationId":"ReviseCardController_deleteCard","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["revise"]}},"/revise/cards/{id}/rewrite":{"post":{"operationId":"ReviseCardController_rewriteCard","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseCardContentDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseCardResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Replace a flagged card’s content and clear the rewrite flag","tags":["revise"]}},"/revise/cards/{id}/keep":{"post":{"operationId":"ReviseCardController_keepCard","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseCardResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Clear the rewrite flag without changing the card","tags":["revise"]}},"/revise/cards/{id}/reviews":{"get":{"operationId":"ReviseCardController_getCardReviews","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ReviseReviewLogResponseDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"The card's review history, oldest first","tags":["revise"]}},"/revise/cards/{cardId}/images/upload-url":{"post":{"operationId":"ReviseCardImageController_createUpload","parameters":[{"name":"cardId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReviseCardImageUploadDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseCardImageUploadResponseDto"}}}},"400":{"description":"REVISE_IMAGE_UNSUPPORTED_TYPE or REVISE_IMAGE_TOO_LARGE"},"409":{"description":"REVISE_IMAGE_LIMIT_REACHED"}},"security":[{"Auth0AccessToken":[]}],"summary":"A presigned URL to upload an image for the card (PNG, JPEG, GIF or WebP, ≤ 10 MB)","tags":["revise"]}},"/revise/cards/{cardId}/images/{imageId}/complete":{"post":{"operationId":"ReviseCardImageController_complete","parameters":[{"name":"cardId","required":true,"in":"path","schema":{"type":"string"}},{"name":"imageId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompleteReviseCardImageUploadDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseCardImageResponseDto"}}}},"400":{"description":"REVISE_IMAGE_UNSUPPORTED_TYPE, REVISE_IMAGE_TOO_LARGE or REVISE_IMAGE_NOT_UPLOADED"}},"security":[{"Auth0AccessToken":[]}],"summary":"Check the uploaded bytes and keep the image. Safe to repeat","tags":["revise"]}},"/revise/cards/{cardId}/images":{"get":{"operationId":"ReviseCardImageController_list","parameters":[{"name":"cardId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ReviseCardImageResponseDto"}}}}},"404":{"description":"No such card for this user"}},"security":[{"Auth0AccessToken":[]}],"summary":"The card's images with fresh signed URLs, oldest first","tags":["revise"]}},"/revise/card-images":{"get":{"operationId":"ReviseCardImageController_lookup","parameters":[{"name":"ids","required":true,"in":"query","description":"Comma-separated image ids, at most 100","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ReviseCardImageResponseDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Signed URLs for up to 100 image ids; ids that are not yours are left out","tags":["revise"]}},"/revise/cards/{cardId}/images/{imageId}":{"patch":{"operationId":"ReviseCardImageController_update","parameters":[{"name":"cardId","required":true,"in":"path","schema":{"type":"string"}},{"name":"imageId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateReviseCardImageDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseCardImageResponseDto"}}}},"404":{"description":"No such card or image for this user"}},"security":[{"Auth0AccessToken":[]}],"summary":"Keep how the image should be turned (degrees clockwise); the bytes are not re-encoded","tags":["revise"]},"delete":{"operationId":"ReviseCardImageController_delete","parameters":[{"name":"cardId","required":true,"in":"path","schema":{"type":"string"}},{"name":"imageId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"security":[{"Auth0AccessToken":[]}],"tags":["revise"]}},"/revise/sessions/start":{"post":{"operationId":"ReviseSessionController_startSession","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartReviseSessionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartReviseSessionResponseDto"}}}},"409":{"description":"REVISE_REWRITE_REQUIRED: cards flagged \"No idea\" must be rewritten or kept first; body lists them"}},"security":[{"Auth0AccessToken":[]}],"summary":"Start a review session: due cards first, then new cards","tags":["revise"]}},"/revise/reviews":{"post":{"operationId":"ReviseSessionController_submitReviews","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitReviseReviewsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitReviseReviewsResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Submit up to 200 reviews (idempotent by review id); returns each updated card","tags":["revise"]}},"/revise/stats":{"get":{"operationId":"ReviseSessionController_getStats","parameters":[{"name":"deck_id","required":false,"in":"query","description":"Limit to one deck; omit for every deck","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseStatsResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["revise"]}},"/revise/ai/pdf/upload-url":{"post":{"operationId":"ReviseAiController_createPdfUploadUrl","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRevisePdfUploadUrlDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevisePdfUploadUrlResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Presigned URL for uploading a PDF to generate flashcards from","tags":["revise"]}},"/revise/ai/generate/pdf":{"post":{"operationId":"ReviseAiController_generateFromPdf","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateFromPdfDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseGenerationResponseDto"}}}},"422":{"description":"REVISE_GENERATION_FAILED: the model failed or found nothing to learn"}},"security":[{"Auth0AccessToken":[]}],"summary":"Draft flashcards from an uploaded PDF. Saves nothing; the PDF is deleted afterwards","tags":["revise"]}},"/revise/ai/generate/notes":{"post":{"operationId":"ReviseAiController_generateFromNotes","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateFromNotesDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseGenerationResponseDto"}}}},"422":{"description":"REVISE_GENERATION_FAILED: the model failed or found nothing to learn"}},"security":[{"Auth0AccessToken":[]}],"summary":"Draft flashcards from the user's notes. Saves nothing","tags":["revise"]}},"/revise/ai/generate/chat":{"post":{"operationId":"ReviseAiController_generateFromChat","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateFromChatDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseGenerationResponseDto"}}}},"422":{"description":"REVISE_GENERATION_FAILED: the model failed or found nothing to learn"}},"security":[{"Auth0AccessToken":[]}],"summary":"Draft flashcards from a conversation with an AI assistant. Saves nothing","tags":["revise"]}},"/revise/ai/conversation":{"post":{"operationId":"ReviseAiController_converse","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseConversationDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseConversationResponseDto"}}}},"422":{"description":"REVISE_GENERATION_FAILED: the model failed or found nothing to learn"}},"security":[{"Auth0AccessToken":[]}],"summary":"Discuss a learning topic before generating cards. Saves nothing","tags":["revise"]}},"/revise/ai/drafts/assist":{"post":{"operationId":"ReviseAiController_assistDraft","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseDraftAssistDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseAssistResponseDto"}}}},"422":{"description":"REVISE_GENERATION_FAILED: the model failed or found nothing to learn"}},"security":[{"Auth0AccessToken":[]}],"summary":"Clarify or correct an unsaved draft card. Saves nothing","tags":["revise"]}},"/revise/cards/{id}/assist":{"post":{"operationId":"ReviseAiController_assist","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseAssistDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseAssistResponseDto"}}}},"422":{"description":"REVISE_GENERATION_FAILED: the model failed or found nothing to learn"}},"security":[{"Auth0AccessToken":[]}],"summary":"Ask the assistant to explain a card, or to suggest a clearer rewrite","tags":["revise"]}},"/revise/imports/upload-url":{"post":{"operationId":"ReviseImportController_createUploadUrl","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReviseImportUploadUrlDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseImportUploadUrlResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Start an import: a presigned URL to upload an .apkg, .colpkg, AlgoApp or text deck file","tags":["revise"]}},"/revise/imports/{id}/complete":{"post":{"operationId":"ReviseImportController_complete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseImportResponseDto"}}}},"404":{"description":"No such import for this user"},"422":{"description":"REVISE_IMPORT_INVALID_FILE or REVISE_IMPORT_TOO_LARGE"}},"security":[{"Auth0AccessToken":[]}],"summary":"Check the uploaded file and queue the import. Safe to repeat","tags":["revise"]}},"/revise/imports/{id}":{"get":{"operationId":"ReviseImportController_getImport","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviseImportResponseDto"}}}},"404":{"description":"No such import for this user"}},"security":[{"Auth0AccessToken":[]}],"summary":"An import's status and, once finished, what it imported and skipped","tags":["revise"]}},"/geofences":{"get":{"operationId":"GeofenceController_getUserGeofences","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Geofence"}}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["geofences"]},"post":{"operationId":"GeofenceController_createGeofence","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGeofenceDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Geofence"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["geofences"]}},"/geofences/{geofence_id}":{"get":{"operationId":"GeofenceController_getGeofenceById","parameters":[{"name":"geofence_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Geofence"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["geofences"]},"put":{"operationId":"GeofenceController_updateGeofence","parameters":[{"name":"geofence_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGeofenceDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Geofence"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["geofences"]},"delete":{"operationId":"GeofenceController_deleteGeofence","parameters":[{"name":"geofence_id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseMessage"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["geofences"]}},"/mcp/auth/tokens":{"post":{"description":"Generates a scoped access token for an MCP client to access this Focus Bear account. The raw token is returned ONCE and cannot be retrieved again — store it securely in your MCP client settings.","operationId":"ExternalMcpAuthController_issueToken","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateExternalApiTokenDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalApiTokenIssuedResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Issue a new MCP access token","tags":["mcp-auth"]},"get":{"description":"Returns all active MCP tokens for this user. Raw tokens are never returned.","operationId":"ExternalMcpAuthController_listTokens","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ExternalApiTokenResponseDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"List active MCP connections","tags":["mcp-auth"]}},"/mcp/auth/tokens/{id}":{"delete":{"description":"Immediately invalidates the specified token. The MCP client will no longer be able to access data.","operationId":"ExternalMcpAuthController_revokeToken","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Revoke an MCP access token","tags":["mcp-auth"]}},"/mcp/auth/agents":{"get":{"description":"Returns all MCP tokens that have an agent_name set. Use the token id as assigned_mcp_token_id when assigning tasks to an AI agent via the tasks API.","operationId":"ExternalMcpAuthController_listAgents","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/McpAgentResponseDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"List MCP agents for the current user","tags":["mcp-auth"]}},"/mcp/tasks":{"get":{"description":"Returns tasks where assigned_mcp_token_id matches the authenticated bearer token. Requires scope: tasks:read.","operationId":"ExternalMcpTasksController_listTasks","parameters":[{"name":"order","required":false,"in":"query","schema":{"default":"ASC","type":"string","enum":["ASC","DESC"]}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"take","required":false,"in":"query","schema":{"minimum":1,"maximum":50,"default":10,"type":"number"}},{"name":"status","required":false,"in":"query","schema":{"type":"string","enum":["NOT_STARTED","IN_PROGRESS","COMPLETED"]}},{"name":"exclude_completed","required":false,"in":"query","description":"Exclude effectively completed tasks before pagination. Known native custom columns override raw status; other tasks use materialized COMPLETED status. Intersects the optional status filter. When applied, response meta.excludesCompleted is true.","schema":{"type":"boolean"}},{"name":"eisenhower_quadrant","required":false,"in":"query","schema":{"minimum":1,"maximum":4,"type":"number"}},{"name":"should_use_cache","required":false,"in":"query","description":"Deprecated. `GET /to-do` always serves cached data; integration freshness is driven by the off-thread sync worker. This field is ignored.","deprecated":true,"schema":{"default":true,"type":"boolean"}},{"name":"project_id","required":false,"in":"query","description":"Filter tasks belonging to a native Focus Bear project.","schema":{"format":"uuid","type":"string"}},{"name":"project_ids","required":false,"in":"query","description":"Tasks in any of these native projects (comma-separated, repeated, or both). Empty = no project filter. Intersects `project_id` when both are sent.","schema":{"type":"array","items":{"type":"string","format":"uuid"}}},{"name":"sort_mode","required":false,"in":"query","description":"Ordering strategy for the returned page. `SMART` ranks by the computed TOP score, `CHRONOLOGICAL` by creation time — both honour the `order` param. `DUE_DATE` sorts by task due date ascending (earliest and overdue first) with undated tasks last, tie-broken by `id`; it ignores `order`, which is always treated as ascending.","schema":{"default":"SMART","type":"string","enum":["SMART","CHRONOLOGICAL","DUE_DATE"]}},{"name":"include_comments","required":false,"in":"query","description":"Include comments (with reactions) for each task","schema":{"default":false,"type":"boolean"}},{"name":"include_reactions","required":false,"in":"query","description":"Include task-level reactions for each task","schema":{"default":false,"type":"boolean"}},{"name":"tag_id","required":false,"in":"query","schema":{"format":"uuid","type":"string"}},{"name":"perspiration_gte","required":false,"in":"query","schema":{"minimum":1,"maximum":10,"type":"number"}},{"name":"perspiration_lte","required":false,"in":"query","schema":{"minimum":1,"maximum":10,"type":"number"}},{"name":"synced_project_id","required":false,"in":"query","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":""}},"security":[{"McpBearerToken":[]}],"summary":"List tasks assigned to the authenticated agent","tags":["mcp-tasks"]}},"/mcp/tasks/{id}":{"get":{"description":"Returns the full detail for a task assigned to the authenticated agent. Returns 404 if the task does not exist or is not assigned to this agent. Requires scope: tasks:read.","operationId":"ExternalMcpTasksController_getTask","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToDoResponse"}}}}},"security":[{"McpBearerToken":[]}],"summary":"Get a single task assigned to the agent","tags":["mcp-tasks"]}},"/mcp/tasks/{id}/status":{"patch":{"description":"Updates the status of a task assigned to this agent. Accepts either a core ToDoStatus enum value (status field) or a project-level custom status ID (custom_status_id field). At least one must be provided. Requires scope: tasks:write.","operationId":"ExternalMcpTasksController_updateTaskStatus","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTaskStatusDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToDoResponse"}}}}},"security":[{"McpBearerToken":[]}],"summary":"Update task status (core or custom)","tags":["mcp-tasks"]},"put":{"description":"Deprecated alias for PATCH /:id/status. Will be removed in a future release.","operationId":"ExternalMcpTasksController_updateTaskStatusLegacy","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTaskStatusDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToDoResponse"}}}}},"security":[{"McpBearerToken":[]}],"summary":"[Deprecated] Update task status — use PATCH instead","tags":["mcp-tasks"]}},"/mcp/tasks/{id}/notes":{"post":{"description":"Adds a comment/note to a task assigned to this agent. Requires scope: tasks:write.","operationId":"ExternalMcpTasksController_addNote","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddTaskNoteDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskComment"}}}}},"security":[{"McpBearerToken":[]}],"summary":"Add a note to a task","tags":["mcp-tasks"]}},"/mcp/tasks/project-statuses":{"post":{"description":"Idempotent: if a status with the same label (case-insensitive) already exists on the project, it is returned as-is. Otherwise a new status is created and appended. User must be the project owner or an accepted member. Requires scope: tasks:write.","operationId":"ExternalMcpTasksController_ensureProjectStatus","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnsureProjectStatusDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnsureProjectStatusResponseDto"}}}}},"security":[{"McpBearerToken":[]}],"summary":"Ensure a custom status exists on a project","tags":["mcp-tasks"]}},"/day-plan/day/{day}":{"get":{"operationId":"DayPlanController_getDay","parameters":[{"name":"day","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DayPlanDayResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Get the day plan for a given day (yyyy-MM-dd): the todos planned for that day plus dismissed event ids","tags":["day-plan"]}},"/day-plan/events":{"post":{"operationId":"DayPlanController_createEvents","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDayPlanEventsDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDayPlanEventsResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Create one or more user-owned one-off calendar events atomically","tags":["day-plan"]}},"/day-plan/events/day/{day}":{"get":{"operationId":"DayPlanController_getEventsForDay","parameters":[{"name":"day","required":true,"in":"path","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","description":"Zero-based page number. Each page contains at most 1,000 events.","schema":{"minimum":0,"maximum":100,"default":0,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DayPlanEventsForDayResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Get one-off events overlapping a calendar day in the user timezone","tags":["day-plan"]}},"/day-plan/events/{eventId}":{"delete":{"operationId":"DayPlanController_deleteEvent","parameters":[{"name":"eventId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Delete a one-off event owned by the current user","tags":["day-plan"]}},"/day-plan/event-series":{"post":{"operationId":"DayPlanController_createEventSeries","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEventSeriesDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEventSeriesResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Create one or more user-owned recurring event series atomically","tags":["day-plan"]},"get":{"operationId":"DayPlanController_getEventSeries","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventSeriesListResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"List all recurring event series owned by the current user","tags":["day-plan"]}},"/day-plan/event-series/day/{day}":{"get":{"operationId":"DayPlanController_getEventSeriesOccurrences","parameters":[{"name":"day","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventSeriesOccurrencesResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Get concrete recurring-event occurrences overlapping a calendar day","tags":["day-plan"]}},"/day-plan/event-series/{seriesId}":{"delete":{"operationId":"DayPlanController_deleteEventSeries","parameters":[{"name":"seriesId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Delete an entire recurring event series","tags":["day-plan"]}},"/day-plan/day/{day}/dismissed-event":{"put":{"operationId":"DayPlanController_dismissEventFromBody","parameters":[{"name":"day","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DayPlanEventIdDto"}}}},"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Mark a calendar event as dismissed (hidden) for a given day; the event id is in the body","tags":["day-plan"]},"delete":{"operationId":"DayPlanController_undismissEventFromBody","parameters":[{"name":"day","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DayPlanEventIdDto"}}}},"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Un-dismiss a calendar event for a given day; the event id is in the body","tags":["day-plan"]}},"/day-plan/day/{day}/dismissed-event/{eventId}":{"put":{"operationId":"DayPlanController_dismissEvent","parameters":[{"name":"day","required":true,"in":"path","schema":{"type":"string"}},{"name":"eventId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Mark a calendar event as dismissed (hidden) for a given day","tags":["day-plan"]},"delete":{"operationId":"DayPlanController_undismissEvent","parameters":[{"name":"day","required":true,"in":"path","schema":{"type":"string"}},{"name":"eventId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Un-dismiss a previously dismissed calendar event for a given day","tags":["day-plan"]}},"/day-plan/event-colour":{"get":{"operationId":"DayPlanController_getEventColours","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventColourResponseDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Get all per-event colour overrides for the current user","tags":["day-plan"]},"put":{"operationId":"DayPlanController_upsertEventColour","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertEventColourDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventColourResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Create or update a per-event colour override","tags":["day-plan"]},"delete":{"operationId":"DayPlanController_deleteEventColourFromBody","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DayPlanEventIdDto"}}}},"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Delete a per-event colour override; the event id is in the body","tags":["day-plan"]}},"/day-plan/event-colour/{eventId}":{"delete":{"operationId":"DayPlanController_deleteEventColour","parameters":[{"name":"eventId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Delete a per-event colour override","tags":["day-plan"]}},"/day-plan/import/file/generate-upload-url":{"post":{"operationId":"DayPlanController_generateFileImportUploadUrl","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateFileImportUploadUrlDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateFileImportUploadUrlResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Generate a presigned URL for uploading a transient calendar image, PDF or DOCX file","tags":["day-plan"]}},"/day-plan/import/file":{"post":{"operationId":"DayPlanController_importEventsFromFile","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportFileDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DayPlanImportResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Extract calendar entries from an image, PDF or DOCX file. Returns incomplete-time drafts as unscheduled_entries, timed one-offs as events, and timed recurrences as event_series without expanding recurrences. This endpoint is stateless and never writes records.","tags":["day-plan"]}},"/day-plan/event-project-links":{"get":{"operationId":"DayPlanEventProjectLinkController_getLinks","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventProjectLinkResponseDto"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"List the user's calendar event ↔ project links","tags":["day-plan"]},"put":{"operationId":"DayPlanEventProjectLinkController_upsertLink","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertEventProjectLinkDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventProjectLinkResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Link a calendar event, or one occurrence of it, to projects (replaces that link's projects)","tags":["day-plan"]},"delete":{"operationId":"DayPlanEventProjectLinkController_deleteLink","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventProjectLinkScopeDto"}}}},"responses":{"200":{"description":""}},"security":[{"Auth0AccessToken":[]}],"summary":"Remove the link of a calendar event, or of one occurrence of it","tags":["day-plan"]}},"/integration/canvas/import-preview":{"post":{"operationId":"CanvasImportController_preview","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CanvasImportPreviewDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CanvasImportPreviewResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Each course's project: the one already linked, or the student's likely existing project for it","tags":["canvas-import"]}},"/integration/canvas/import":{"post":{"description":"Re-imports never duplicate a project or to-do and never undo the student’s edits, completions or deletions. With generate_subtasks, new to-dos get an AI breakdown.","operationId":"CanvasImportController_importCourses","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CanvasImportDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CanvasImportResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Create or link a project per course and a to-do per assignment; safe to repeat","tags":["canvas-import"]}},"/late-no-more/config":{"get":{"operationId":"LateNoMoreController_getConfig","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LateNoMoreConfigResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["late-no-more"]},"put":{"operationId":"LateNoMoreController_updateConfig","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLateNoMoreConfigDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LateNoMoreConfigResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"tags":["late-no-more"]}},"/voice/transcribe":{"post":{"operationId":"VoiceController_transcribe","parameters":[],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"}}}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceTranscriptionResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Transcribe a recorded voice command","tags":["voice"]}},"/voice/intent":{"post":{"operationId":"VoiceController_classifyIntent","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceIntentDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceIntentResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Classify a voice command transcript into an app action","tags":["voice"]}},"/voice/suggest-title":{"post":{"description":"Always 200 for a valid transcript; `title` is null when no title could be suggested.","operationId":"VoiceController_suggestTitle","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceSuggestTitleDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceSuggestTitleResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Suggest a short title for a transcribed voice note","tags":["voice"]}},"/voice/action-items":{"post":{"description":"`action_items` is empty when the meeting had none and `summary` is empty when there was too little to summarise; action_tasks contains editable metadata aligned with action_items. Optional current_datetime resolves relative deadlines, and optional user_names (the user's own names) tell the user's actions from other people's; 502 when extraction fails.","operationId":"VoiceController_suggestActionItems","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceActionItemsDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceActionItemsResponseDto"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Summarise a meeting transcript and list its action items","tags":["voice"]}},"/school-feature-policy/me":{"get":{"operationId":"SchoolFeaturePolicyController_mine","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MySchoolFeaturePolicy"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Features the caller's school has locked off (empty for anyone who isn't a school student)","tags":["school-feature-policy"]}},"/school-feature-policy/schools/{schoolId}":{"get":{"operationId":"SchoolFeaturePolicyController_get","parameters":[{"name":"schoolId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchoolFeaturePolicyView"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"A school's student feature policy (school owner or administrator)","tags":["school-feature-policy"]},"put":{"operationId":"SchoolFeaturePolicyController_save","parameters":[{"name":"schoolId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSchoolFeaturePolicyDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchoolFeaturePolicyView"}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Replace a school's locked student features; every change is audit-logged","tags":["school-feature-policy"]}},"/school-feature-policy/schools/{schoolId}/history":{"get":{"operationId":"SchoolFeaturePolicyController_history","parameters":[{"name":"schoolId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SchoolFeaturePolicyChange"}}}}}},"security":[{"Auth0AccessToken":[]}],"summary":"Who changed a school's student feature policy, newest first","tags":["school-feature-policy"]}}},"info":{"title":"API documentation","description":"","version":"1.0.0","contact":{}},"tags":[],"servers":[],"components":{"securitySchemes":{"Auth0AccessToken":{"type":"http","scheme":"bearer","bearerFormat":"JWT"},"Auth0ActionSecret":{"name":"auth0_action_secret","type":"apiKey","in":"header"}},"schemas":{"SecurityChallengeDto":{"type":"object","properties":{"action":{"type":"string","enum":["change_password","mfa_enrollment"]}},"required":["action"]},"SecurityChangePasswordDto":{"type":"object","properties":{"newPassword":{"type":"string"},"reauthentication_token":{"type":"string"}},"required":["newPassword","reauthentication_token"]},"SecurityReauthenticationDto":{"type":"object","properties":{"reauthentication_token":{"type":"string"}},"required":["reauthentication_token"]},"PusherAuthDto":{"type":"object","properties":{"channel_name":{"type":"string","description":"Accepted for Pusher client-library compatibility (the default authorizer posts it with\n`socket_id`). The server ignores it.","maxLength":200},"socket_id":{"type":"string"}},"required":["socket_id"]},"PusherChannelAuthDto":{"type":"object","properties":{"socket_id":{"type":"string"},"channel_name":{"type":"string"}},"required":["socket_id","channel_name"]},"PusherBeamsAuthResponse":{"type":"object","properties":{"token":{"type":"string"}},"required":["token"]},"ResetPasswordDto":{"type":"object","properties":{"lang":{"enum":["en","es","de","ja","vi","pt-BR","pt-PT","zh-CN","zh-TW","nl","tl","fr","it","pl","ru","ar","ro"],"type":"string","default":"en"},"email":{"type":"string","format":"email"}},"required":["email"]},"ChangePasswordDto":{"type":"object","properties":{"token":{"type":"string"},"newPassword":{"type":"string"}},"required":["token","newPassword"]},"Object":{"type":"object","properties":{}},"EmailConfirmationForGuestDto":{"type":"object","properties":{"email":{"type":"string","format":"email"}},"required":["email"]},"ConvertGuestDto":{"type":"object","properties":{"email":{"type":"string","format":"email"},"newPassword":{"type":"string"}},"required":["email","newPassword"]},"LinkSocialToGuestDto":{"type":"object","properties":{"linkWith":{"type":"string"}},"required":["linkWith"]},"SendEmailVerificationDto":{"type":"object","properties":{"lang":{"enum":["en","es","de","ja","vi","pt-BR","pt-PT","zh-CN","zh-TW","nl","tl","fr","it","pl","ru","ar","ro"],"type":"string","default":"en"},"email":{"type":"string","format":"email"}},"required":["email"]},"CalendarStatusDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"is_selected":{"type":"boolean"}},"required":["id","is_selected"]},"UpdateCalendarStatusDto":{"type":"object","properties":{"body":{"$ref":"#/components/schemas/CalendarStatusDto"}},"required":["body"]},"RoutineNotificationTimes":{"type":"object","properties":{"last_time_notified_of_morning_routine":{"format":"date-time","type":"string","nullable":true},"last_time_notified_of_evening_routine":{"format":"date-time","type":"string","nullable":true},"last_date_notified_of_custom_routines":{"type":"object","additionalProperties":{"type":"string"}}},"required":["last_time_notified_of_morning_routine","last_time_notified_of_evening_routine"]},"OnboardingDto":{"type":"object","properties":{}},"WebDeviceSettingsDto":{"type":"object","properties":{"hasEditedSettings":{"type":"boolean"},"onboarding":{"$ref":"#/components/schemas/OnboardingDto"}}},"UpdateLocalDeviceSettingsDto":{"type":"object","properties":{"MacOS":{"type":"object"},"Windows":{"type":"object"},"Android":{"type":"object"},"iOS":{"type":"object"},"Web":{"$ref":"#/components/schemas/WebDeviceSettingsDto"}}},"UserMetadata":{"type":"object","properties":{"profile_image":{"type":"string"},"description":{"type":"string"},"name":{"type":"string"},"last_email_sent":{"type":"string"},"email_preferences":{"type":"object","additionalProperties":true}}},"UserOnboardingProgress":{"type":"object","properties":{"level":{"type":"number"},"has_edited_focus_mode":{"type":"boolean"},"has_edited_settings":{"type":"boolean"},"has_edited_always_blocked_urls":{"type":"boolean"},"has_installed_desktop_app":{"type":"boolean"},"has_installed_mobile_app":{"type":"boolean"},"has_chatted_with_focus_bear":{"type":"boolean"}}},"SubscriptionStatus":{"type":"object","properties":{"hasActiveSubscription":{"type":"boolean"},"activeEntitlements":{"type":"array","items":{"type":"string"}},"expirations":{"type":"object","additionalProperties":{"type":"object","additionalProperties":true}},"entitlements":{"type":"object","additionalProperties":{"type":"object","additionalProperties":true}},"subscriptions":{"type":"object","additionalProperties":{"type":"object","additionalProperties":true}}},"required":["hasActiveSubscription","activeEntitlements"]},"ExternalTaskStatus":{"type":"object","properties":{"label":{"type":"string"},"status_id":{"type":"string"},"should_complete_task":{"type":"boolean"}},"required":["label","status_id","should_complete_task"]},"SubtaskDto":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"is_completed":{"type":"boolean"},"trello_check_item_id":{"type":"string"}},"required":["name","is_completed"]},"ProjectMember":{"type":"object","properties":{"project_id":{"type":"string"},"user_id":{"type":"string"},"email":{"type":"string"},"role":{"type":"string","enum":["owner","admin","member"]},"invitation_status":{"type":"string","enum":["pending","accepted","declined","failed"]},"invitation_sent_at":{"format":"date-time","type":"string"},"invitation_responded_at":{"format":"date-time","type":"string"},"project":{"$ref":"#/components/schemas/Project"},"user":{"$ref":"#/components/schemas/User"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["project_id","role","invitation_status"]},"Project":{"type":"object","properties":{"owner_id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"custom_statuses":{"type":"array","items":{"type":"object"}},"icon":{"type":"string"},"due_date":{"format":"date-time","type":"string","nullable":true},"due_date_is_date_only":{"type":"boolean"},"importance":{"type":"number"},"outcome":{"type":"number","nullable":true},"status":{"type":"string","enum":["active","completed","archived"]},"metadata":{"type":"object","additionalProperties":true,"nullable":true,"description":"Open jsonb bag for per-project client data; `tags` is the one reserved key (validated, normalized\nlower-case, GIN-indexed). Deliberately NOT encrypted, unlike `focus_modes.metadata` — an encrypted\nvalue could not be indexed or queried, which is the whole point of storing tags here."},"deleted_at":{"format":"date-time","type":"string"},"owner":{"$ref":"#/components/schemas/User"},"members":{"type":"array","items":{"$ref":"#/components/schemas/ProjectMember"}},"tasks":{"type":"array","items":{"$ref":"#/components/schemas/ToDo"}},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["owner_id","name","due_date_is_date_only","importance","status"]},"TeamToMember":{"type":"object","properties":{"team_id":{"type":"string"},"member_id":{"type":"string"},"first_name":{"type":"string"},"last_name":{"type":"string"},"year_level":{"type":"string","nullable":true},"member_expiry_date":{"format":"date-time","type":"string"},"invitation_status":{"type":"string","enum":["failed","pending","accepted","declined","expired"]},"invited_role":{"type":"string","nullable":true,"enum":["admin","teacher","member"]},"invitation_sent_at":{"format":"date-time","type":"string"},"invitation_responded_at":{"format":"date-time","type":"string"},"invitation_send_count":{"type":"number"},"email":{"type":"string"},"member":{"$ref":"#/components/schemas/User"},"team":{"$ref":"#/components/schemas/Team"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["team_id","member_id","invitation_status","invitation_send_count","member","team"]},"TeamToAdmin":{"type":"object","properties":{"team_id":{"type":"string"},"admin_id":{"type":"string"},"admin":{"$ref":"#/components/schemas/User"},"team":{"$ref":"#/components/schemas/Team"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["team_id","admin_id","admin","team"]},"TeamToTeacher":{"type":"object","properties":{"team_id":{"type":"string"},"teacher_id":{"type":"string"},"teacher":{"$ref":"#/components/schemas/User"},"team":{"$ref":"#/components/schemas/Team"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["team_id","teacher_id","teacher","team"]},"Team":{"type":"object","properties":{"owner_id":{"type":"string","nullable":true},"team_size":{"type":"number"},"team_size_limit":{"type":"number"},"is_active":{"type":"boolean"},"expires_date":{"type":"object"},"stripe_data":{"type":"object"},"stripe_subscription_id":{"type":"string"},"name":{"type":"string"},"payment_type":{"type":"string"},"parent_team_id":{"type":"string"},"parent_team":{"$ref":"#/components/schemas/Team"},"is_class":{"type":"boolean"},"is_school":{"type":"boolean"},"archived_at":{"format":"date-time","type":"string","nullable":true},"class_session_window_start":{"type":"string"},"class_session_window_end":{"type":"string"},"concern_focus_threshold_pct":{"type":"number"},"concern_lookback_sessions":{"type":"number"},"child_teams":{"type":"array","items":{"$ref":"#/components/schemas/Team"}},"owner":{"$ref":"#/components/schemas/User"},"teamToMember":{"type":"array","items":{"$ref":"#/components/schemas/TeamToMember"}},"teamToAdmin":{"type":"array","items":{"$ref":"#/components/schemas/TeamToAdmin"}},"teamToTeacher":{"type":"array","items":{"$ref":"#/components/schemas/TeamToTeacher"}},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"InstalledFocusModeTemplate":{"type":"object","properties":{"user_id":{"type":"string"},"focus_mode_template_id":{"type":"string"},"installation_status":{"type":"boolean"},"user":{"$ref":"#/components/schemas/User"},"focus_mode_template":{"$ref":"#/components/schemas/FocusModeTemplate"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"FocusModeTag":{"type":"object","properties":{"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"FocusModeTemplate":{"type":"object","properties":{"author_id":{"type":"string"},"author_name":{"type":"string"},"name":{"type":"string"},"allowed_apps":{"type":"array","items":{"type":"string"}},"allowed_urls":{"type":"array","items":{"type":"string"}},"description":{"type":"string"},"description_video_url":{"type":"string"},"welcome_message":{"type":"string"},"welcome_video_url":{"type":"string"},"description_plain_text":{"type":"string"},"welcome_message_plain_text":{"type":"string"},"marketplace_approval_status":{"type":"boolean"},"marketplace_request":{"enum":["requested","unrequested"],"type":"string"},"is_featured":{"type":"boolean"},"featured_for_onboarding":{"type":"boolean"},"language":{"type":"string"},"deleted_at":{"format":"date-time","type":"string"},"author":{"$ref":"#/components/schemas/User"},"installs":{"type":"array","items":{"$ref":"#/components/schemas/InstalledFocusModeTemplate"}},"focus_modes":{"type":"array","items":{"$ref":"#/components/schemas/FocusMode"}},"tags":{"type":"array","items":{"$ref":"#/components/schemas/FocusModeTag"}},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"CompletedFocusBlock":{"type":"object","properties":{"user_id":{"type":"string"},"focus_mode_id":{"type":"string"},"start_time":{"format":"date-time","type":"string"},"finish_time":{"format":"date-time","type":"string"},"scheduled_finish_time":{"format":"date-time","type":"string"},"status":{"enum":["active","paused","completed"],"type":"string"},"paused_at":{"format":"date-time","type":"string"},"total_paused_seconds":{"type":"number"},"intention":{"type":"string"},"achievements":{"type":"string"},"distractions":{"type":"string"},"focus_duration_seconds":{"type":"number"},"metadata":{"type":"object"},"user":{"$ref":"#/components/schemas/User"},"focus_mode":{"$ref":"#/components/schemas/FocusMode"},"tags":{"type":"array","items":{"$ref":"#/components/schemas/FocusModeTag"}},"to_dos":{"type":"array","items":{"$ref":"#/components/schemas/ToDo"}},"block_level":{"nullable":true,"enum":["gentle","strict","super-strict"],"type":"string"},"version":{"type":"number"},"class_session_id":{"type":"string","nullable":true},"project_id":{"type":"string","nullable":true},"project":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/Project"}]},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"BlockingSchedule":{"type":"object","properties":{"days_of_week_text":{"type":"array","items":{"type":"string","enum":["ALL","MON","TUE","WED","THU","FRI","SAT","SUN"]},"readOnly":true},"user_id":{"type":"string"},"name":{"type":"string"},"start_time":{"type":"string"},"end_time":{"type":"string"},"days_of_week":{"type":"array","items":{"type":"number"}},"focus_mode_id":{"type":"string"},"pause_friction":{"enum":["none","timer","100_random_chars","password"],"type":"string"},"block_level":{"enum":["gentle","strict","super-strict"],"type":"string"},"is_ai_blocking_enabled":{"type":"boolean"},"emoji":{"type":"string","nullable":true},"metadata":{"type":"object","additionalProperties":true},"user":{"$ref":"#/components/schemas/User"},"focus_mode":{"$ref":"#/components/schemas/FocusMode"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"FocusMode":{"type":"object","properties":{"user_id":{"type":"string"},"name":{"type":"string"},"allowed_apps":{"type":"array","items":{"type":"string"}},"allowed_urls":{"type":"array","items":{"type":"string"}},"metadata":{"type":"object"},"categories":{"description":"Per-entry categories for this block list: `[{ entry, category }]`, where `entry` mirrors an\n`allowed_urls` / `allowed_apps` value and `category` is a client taxonomy id.\n\nEncrypted like the other list columns, because the entries are the user's own blocked sites.\nNullable with no SQL default on purpose: a plaintext `'[]'` default could not be read back\nthrough the encryption transformer, so \"empty\" is applied in code by the response serializer.\n\nDeliberately outside `MAX_ALLOWLIST_TOTAL_BYTES`: that budget exists because a shared mode's\nallow-lists ride verbatim inside Pusher/FCM payloads, and `categories` never does — a class\nsession snapshots only `allowed_apps` / `allowed_urls`. Anything that starts fanning the whole\nmode out over realtime must bring this column into that budget.","type":"array","items":{"type":"object"}},"app_identities":{"nullable":true,"description":"Platform identities for the app entries (`allowed_apps`, and on focus modes the Windows app's\n`metadata.allowed_apps_win`), keyed by `entry` like `categories`. Clients match the running app\nby these instead of a renameable name; entries with none are matched by name as before. Filled\nfrom the common-apps catalog on every write, so older clients that send names only still get\nthem. Encrypted and nullable with no SQL default for the same reason as `categories`.","type":"array","items":{"type":"object"}},"is_ai_enabled":{"type":"boolean"},"focus_mode_template_id":{"type":"string"},"team_id":{"type":"string","nullable":true,"description":"Team-shared focus mode (Teacher Mode): team_id = school (parent team) makes the mode\nvisible school-wide, team_id = class makes it class-wide; NULL = personal mode.\n`user_id` stays the creator; shared modes are managed by that team's admins."},"team":{"$ref":"#/components/schemas/Team"},"deleted_at":{"format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User"},"focus_mode_template":{"$ref":"#/components/schemas/FocusModeTemplate"},"completed_logs":{"type":"array","items":{"$ref":"#/components/schemas/CompletedFocusBlock"}},"to_dos":{"type":"array","items":{"$ref":"#/components/schemas/ToDo"}},"tags":{"type":"array","items":{"$ref":"#/components/schemas/FocusModeTag"}},"blocking_schedules":{"type":"array","items":{"$ref":"#/components/schemas/BlockingSchedule"}},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["is_ai_enabled"]},"TaskTimeLog":{"type":"object","properties":{"user_id":{"type":"string"},"completed_focus_block_id":{"type":"string"},"task_id":{"type":"string"},"duration_logged_seconds":{"type":"number"},"note":{"type":"string"},"user":{"$ref":"#/components/schemas/User"},"to_do":{"$ref":"#/components/schemas/ToDo"},"completed_focus_block":{"$ref":"#/components/schemas/CompletedFocusBlock"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"TaskAttachment":{"type":"object","properties":{"task_id":{"type":"string"},"user_id":{"type":"string"},"file_name":{"type":"string"},"file_key":{"type":"string"},"content_type":{"type":"string"},"file_size":{"type":"number"},"task":{"$ref":"#/components/schemas/ToDo"},"user":{"$ref":"#/components/schemas/User"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["task_id","user_id","file_name","file_key","content_type","file_size"]},"ToDo":{"type":"object","properties":{"user_id":{"type":"string"},"focus_type":{"type":"string"},"synced_project_id":{"type":"string"},"project_id":{"type":"string"},"assignee_id":{"type":"string"},"assigned_mcp_token_id":{"type":"string"},"custom_status_id":{"type":"string"},"title":{"type":"string"},"details":{"type":"string"},"objective":{"type":"string"},"external_task_id":{"type":"string"},"external_task_metadata":{"type":"object"},"subtasks":{"type":"array","items":{"$ref":"#/components/schemas/SubtaskDto"}},"due_date":{"format":"date-time","type":"string","nullable":true},"eisenhower_quadrant":{"type":"number"},"outcome":{"type":"number"},"perspiration_level":{"type":"number"},"status":{"type":"string"},"duration":{"type":"number"},"icon":{"type":"string"},"top_score":{"type":"number","nullable":true,"description":"@brief Materialised priority score, written by application code.\n@details Mirrors the SQL expression that previously computed the\n         \"top score\" inside `ORDER BY` on every page load. Persisting\n         the value allows the planner to satisfy `ORDER BY ... LIMIT`\n         with the `(user_id, top_score DESC)` index instead of a\n         parallel sequential scan + in-memory sort. The score depends\n         on the user's local \"today\", so it is refreshed daily by the\n         off-thread top-score worker as well as on every write that\n         touches `due_date`, `outcome`, or `perspiration_level`.\n\n         PostgreSQL's `numeric` type round-trips through node-postgres\n         as a string; the transformer below converts it to `number`\n         on read so the application can treat it as a plain numeric\n         value."},"current_external_status_id":{"type":"string","nullable":true,"description":"@brief Materialised external status identifier from the linked platform.\n@details Populated by the integration sync worker so list-view rendering\n         no longer needs to decrypt/parse the `external_task_metadata`\n         JSONB on the request path."},"current_external_status_label":{"type":"string","nullable":true,"description":"@brief Materialised external status label from the linked platform.\n@details See `current_external_status_id`. The label is exposed via the\n         API as the human-readable status text."},"planned_date":{"type":"string","nullable":true,"description":"@brief Day Plan pointer: the day this todo is planned for (YYYY-MM-DD).\n@details NULL means the todo is not in any Day Plan. A planned task is a\n         pointer into `to_do` by date, not a copy; the Day Plan panel reads\n         todos by `planned_date` and writes planning changes through\n         `PATCH /to-do/:id`."},"planned_block_key":{"type":"string","nullable":true,"description":"@brief Day Plan time-box assignment within the planned day.\n@details Opaque, never parsed by the backend. One of `event:<id>`,\n         `deepwork:<unix-epoch>`, `habit:<title>`, or NULL when planned but\n         not yet time-boxed onto a block. Encrypted at rest because the\n         `habit:<title>` form can embed a habit name, matching `title`/\n         `details`. The column stays unbounded `varchar` (ciphertext is\n         longer than plaintext); the DTO caps plaintext input at 256 chars."},"planned_order":{"type":"number","nullable":true,"description":"@brief Manual ordering within the planned day (drag-to-reorder)."},"recurrence_rule":{"type":"string","nullable":true,"description":"@brief Recurrence: canonical RFC 5545 RRULE content line, e.g.\n       `RRULE:FREQ=WEEKLY;INTERVAL=2` for a fortnightly chore.\n@details NULL means the todo is a one-off and takes no recurrence code path,\n         which is every todo that existed before this column. Set together\n         with the other three `recurrence_*` columns (a DB CHECK enforces\n         all-or-none). Validated and canonicalised through the same RFC 5545\n         subset the Day Plan's event series use."},"recurrence_timezone":{"type":"string","nullable":true,"description":"@brief Recurrence: IANA zone the rule is evaluated in (keeps the local time of day across DST)."},"recurrence_dtstart":{"format":"date-time","type":"string","nullable":true,"description":"@brief Recurrence: the series DTSTART — the first occurrence's due date.\n@details Copied unchanged onto every occurrence so the next due date is\n         always computed from the series anchor. Completing an occurrence\n         late therefore does not shift the schedule."},"recurrence_series_id":{"type":"string","nullable":true,"description":"@brief Recurrence: groups every occurrence of one repeating todo.\n@details Equal to the first occurrence's own id. Lets history be read per\n         series and `DELETE /to-do?scope=series` remove the whole thing."},"user":{"$ref":"#/components/schemas/User"},"synced_project":{"$ref":"#/components/schemas/SyncedProject"},"project":{"$ref":"#/components/schemas/Project"},"assignee":{"$ref":"#/components/schemas/User"},"focus_mode":{"$ref":"#/components/schemas/FocusMode"},"task_time_logs":{"type":"array","items":{"$ref":"#/components/schemas/TaskTimeLog"}},"tags":{"type":"array","items":{"$ref":"#/components/schemas/FocusModeTag"}},"completedFocusBlocks":{"type":"array","items":{"$ref":"#/components/schemas/CompletedFocusBlock"}},"attachments":{"type":"array","items":{"$ref":"#/components/schemas/TaskAttachment"}},"attachment_count":{"type":"number"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["title","details","objective","eisenhower_quadrant","outcome","perspiration_level","status","completedFocusBlocks"]},"SyncedProject":{"type":"object","properties":{"user_id":{"type":"string"},"platform":{"type":"string"},"external_project_id":{"type":"string"},"external_portal_id":{"type":"string"},"available_statuses":{"type":"array","items":{"$ref":"#/components/schemas/ExternalTaskStatus"}},"have_tasks_been_synced":{"type":"boolean"},"name":{"type":"string"},"synced_at":{"format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User"},"to_dos":{"type":"array","items":{"$ref":"#/components/schemas/ToDo"}},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"UserConsentMetadata":{"type":"object","properties":{"policy_version":{"type":"string","description":"The policy version the client showed the user when they gave this consent."}}},"UserConsent":{"type":"object","properties":{"user_id":{"type":"string"},"consent_type":{"type":"string","enum":["event_tracking","privacy_policy","terms_of_service","data_processing","marketing_emails"]},"consent_status":{"type":"boolean"},"withdrawal_date":{"format":"date-time","type":"string"},"metadata":{"$ref":"#/components/schemas/UserConsentMetadata"},"policy_version":{"type":"string","nullable":true},"consented_at":{"format":"date-time","type":"string","nullable":true},"user":{"$ref":"#/components/schemas/User"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["consent_type"]},"InstalledPack":{"type":"object","properties":{"user_id":{"type":"string"},"pack_id":{"type":"string"},"installation_status":{"type":"boolean"},"activity_sequence_id":{"type":"string"},"user":{"$ref":"#/components/schemas/User"},"habit_pack":{"$ref":"#/components/schemas/HabitPack"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"ActivityImageData":{"type":"object","properties":{"file_path":{"type":"string","description":"R2 object key (e.g. `activity_images/{activityId}/...`); required when `url` is not set.","maxLength":1024},"url":{"type":"string","description":"External image URL; required when `file_path` is not set (e.g. R2-only entries use `file_path` alone)."}}},"ActivityData":{"type":"object","properties":{"name":{"type":"string"},"is_office_friendly":{"type":"boolean"},"take_notes":{"enum":["NO_NOTE","DURING_ACTIVITY","END_OF_ACTIVITY"],"type":"string"},"priority":{"enum":["STANDARD","HIGH"],"type":"string"},"allowed_focus_mode_id":{"type":"string","format":"uuid"},"video_urls":{"type":"array","items":{"type":"string"}},"include_in_every_break":{"type":"boolean"},"habit_icon":{"type":"string"},"habit_icon_generation_failed":{"type":"boolean"},"log_quantity_question":{"type":"string"},"choice_type":{"enum":["random","normal","competency","check_list"],"type":"string"},"allowed_apps":{"type":"array","items":{"type":"string"}},"allowed_mobile_apps":{"type":"array","items":{"type":"string"}},"allowed_urls":{"type":"array","items":{"type":"string"}},"break_type":{"enum":["micro","pomodoro"],"type":"string"},"linked_project_ids":{"maxItems":10,"type":"array","items":{"type":"string","format":"uuid"}},"tags":{"type":"array","items":{"type":"string"}},"linked_project_id":{"type":"string","format":"uuid","description":"First of linked_project_ids, for older clients"},"category":{"type":"string"},"text_instructions":{"type":"string"},"image_urls":{"type":"array","items":{"$ref":"#/components/schemas/ActivityImageData"}},"current_competency_level":{"type":"number"},"competency_level":{"type":"number"},"show_saved_distracting_websites":{"type":"boolean"}},"required":["name"]},"Geofence":{"type":"object","properties":{"user_id":{"type":"string"},"name":{"type":"string"},"latitude":{"type":"string"},"longitude":{"type":"string"},"radius":{"type":"number"},"trigger_after_time":{"type":"string"},"associated_routine_id":{"type":"string"},"user":{"$ref":"#/components/schemas/User"},"associated_routine":{"$ref":"#/components/schemas/ActivitySequence"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["user_id","name","latitude","longitude","radius"]},"CompletedActivityMetadata":{"type":"object","properties":{}},"DailyStats":{"type":"object","properties":{"user_id":{"type":"string"},"date_completed":{"format":"date-time","type":"string"},"focus_modes_completed":{"type":"number"},"morning_routine_completion_percentage":{"type":"number"},"evening_routine_completion_percentage":{"type":"number"},"micro_breaks_routine_completion_percentage":{"type":"number"},"should_recalculate":{"type":"boolean"},"morning_sequence_log_id":{"type":"string"},"evening_sequence_log_id":{"type":"string"},"number_of_distractions_blocked":{"type":"number"},"seconds_spent_doing_breaks":{"type":"number"},"seconds_spent_in_focus_sessions":{"type":"number"},"break_sequence_log_id":{"type":"string"},"morning_sequence_log":{"$ref":"#/components/schemas/CompletedActivitySequence"},"evening_sequence_log":{"$ref":"#/components/schemas/CompletedActivitySequence"},"user":{"$ref":"#/components/schemas/User"},"break_sequence_log":{"$ref":"#/components/schemas/CompletedActivitySequence"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"CompletedActivitySequence":{"type":"object","properties":{"user_id":{"type":"string"},"activity_sequence_id":{"type":"string"},"start_time":{"format":"date-time","type":"string"},"ownership_window_start":{"format":"date-time","type":"string"},"finish_time":{"format":"date-time","type":"string"},"duration_minutes":{"type":"number"},"plan_duration_minutes":{"type":"number"},"is_completed":{"type":"boolean"},"was_force_completed":{"type":"boolean"},"duration_percent_deviation":{"type":"number"},"user":{"$ref":"#/components/schemas/User"},"activity_sequence":{"$ref":"#/components/schemas/ActivitySequence"},"completed_activity_logs":{"type":"array","items":{"$ref":"#/components/schemas/CompletedActivity"}},"completed_morning_sequence":{"$ref":"#/components/schemas/DailyStats"},"completed_evening_sequence":{"$ref":"#/components/schemas/DailyStats"},"completed_break_sequence":{"$ref":"#/components/schemas/DailyStats"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["completed_break_sequence"]},"LogQuantityAnswer":{"type":"object","properties":{"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"CompletedActivity":{"type":"object","properties":{"user_id":{"type":"string"},"activity_id":{"type":"string"},"activity_sequence_id":{"type":"string"},"start_time":{"format":"date-time","type":"string"},"finish_time":{"format":"date-time","type":"string"},"quantity_logged":{"type":"number"},"duration_logged":{"type":"number"},"completed_sequence_id":{"type":"string"},"activity_note":{"type":"string"},"metadata":{"$ref":"#/components/schemas/CompletedActivityMetadata"},"user":{"$ref":"#/components/schemas/User"},"activity":{"$ref":"#/components/schemas/Activity"},"activity_sequence":{"$ref":"#/components/schemas/ActivitySequence"},"completed_sequence_log":{"$ref":"#/components/schemas/CompletedActivitySequence"},"answers":{"type":"array","items":{"$ref":"#/components/schemas/LogQuantityAnswer"}},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"LogQuantityQuestion":{"type":"object","properties":{"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"Tutorial":{"type":"object","properties":{"activity_id":{"type":"string"},"user_id":{"type":"string"},"activity_template_id":{"type":"string"},"activity":{"$ref":"#/components/schemas/Activity"},"user":{"$ref":"#/components/schemas/User"},"activity_template":{"$ref":"#/components/schemas/ActivityTemplate"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["activity_id","user_id","user"]},"Activity":{"type":"object","properties":{"user_id":{"type":"string"},"parent_id":{"type":"string"},"linked_activity_id":{"type":"string"},"activity_template_id":{"type":"string"},"has_choices":{"type":"boolean"},"activity_sequence_id":{"type":"string"},"type":{"enum":["breaking","morning","evening","standalone","library"],"type":"string"},"log_summary_type":{"type":"string"},"log_quantity":{"type":"boolean"},"duration_seconds":{"type":"number"},"completion_requirements":{"type":"string"},"activity_data":{"$ref":"#/components/schemas/ActivityData"},"is_default":{"type":"boolean"},"run_micro_breaks":{"type":"boolean"},"days_of_week":{"type":"array","items":{"type":"string","enum":["ALL","MON","TUE","WED","THU","FRI","SAT","SUN"]}},"check_list":{"type":"array","items":{"type":"string"}},"impact_category":{"enum":["hours_of_sleep","energy_level_upon_awakening","mood","perception_of_productivity","minutes_spent_on_distracting_websites","minutes_spent_postponing_app_blocks","minutes_spent_postponing_habits"],"type":"string"},"cutoff_time_for_doing_activity":{"type":"string"},"geofence_id":{"type":"string"},"is_deleted":{"type":"boolean"},"geofence":{"$ref":"#/components/schemas/Geofence"},"activity_sequence":{"$ref":"#/components/schemas/ActivitySequence"},"completed_activities":{"type":"array","items":{"$ref":"#/components/schemas/CompletedActivity"}},"parent_activity":{"$ref":"#/components/schemas/ActivitySequence"},"linked_activity":{"$ref":"#/components/schemas/ActivitySequence"},"linked_activities":{"type":"array","items":{"$ref":"#/components/schemas/Activity"}},"choices":{"type":"array","items":{"$ref":"#/components/schemas/Activity"}},"log_quantity_questions":{"type":"array","items":{"$ref":"#/components/schemas/LogQuantityQuestion"}},"user":{"$ref":"#/components/schemas/User"},"user_activities":{"$ref":"#/components/schemas/User"},"activity_template":{"$ref":"#/components/schemas/ActivityTemplate"},"tutorial":{"$ref":"#/components/schemas/Tutorial"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"ActivityTemplateTag":{"type":"object","properties":{"tags":{"type":"array","items":{"type":"string"}},"activity_template_id":{"type":"string"},"activity_template":{"$ref":"#/components/schemas/ActivityTemplate"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["tags","activity_template_id"]},"ActivityTemplateEmbedding":{"type":"object","properties":{"activity_template_id":{"type":"string"},"embedding":{"type":"array","items":{"type":"number"}},"text_source":{"type":"string"},"metadata":{"type":"object","additionalProperties":true},"model_version":{"type":"string"},"activity_template":{"$ref":"#/components/schemas/ActivityTemplate"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["activity_template_id","embedding","text_source"]},"ActivityTemplate":{"type":"object","properties":{"pack_id":{"type":"string"},"user_id":{"type":"string"},"activity_type":{"type":"string"},"log_summary_type":{"type":"string"},"log_quantity":{"type":"boolean"},"activity_data":{"$ref":"#/components/schemas/ActivityData"},"has_choices":{"type":"boolean"},"duration_seconds":{"type":"number"},"completion_requirements":{"type":"string"},"parent_id":{"type":"string"},"linked_activity_template_id":{"type":"string"},"sequence_index":{"type":"number"},"check_list":{"type":"array","items":{"type":"string"}},"impact_category":{"type":"string","enum":["hours_of_sleep","energy_level_upon_awakening","mood","perception_of_productivity","minutes_spent_on_distracting_websites","minutes_spent_postponing_app_blocks","minutes_spent_postponing_habits"]},"deleted_at":{"format":"date-time","type":"string"},"parent_activity":{"$ref":"#/components/schemas/ActivitySequence"},"choices":{"type":"array","items":{"$ref":"#/components/schemas/ActivityTemplate"}},"linked_activity_template":{"$ref":"#/components/schemas/ActivitySequence"},"linked_activity_templates":{"type":"array","items":{"$ref":"#/components/schemas/Activity"}},"log_quantity_questions":{"type":"array","items":{"$ref":"#/components/schemas/LogQuantityQuestion"}},"habit_pack":{"$ref":"#/components/schemas/HabitPack"},"user":{"$ref":"#/components/schemas/User"},"activities":{"type":"array","items":{"$ref":"#/components/schemas/Activity"}},"tutorial":{"$ref":"#/components/schemas/Tutorial"},"tags":{"type":"array","items":{"$ref":"#/components/schemas/ActivityTemplateTag"}},"embeddings":{"type":"array","items":{"$ref":"#/components/schemas/ActivityTemplateEmbedding"}},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"HabitPack":{"type":"object","properties":{"user_id":{"type":"string"},"pack_type":{"enum":["routine","standalone"],"type":"string"},"pack_name":{"type":"string"},"creator_name":{"type":"string"},"description":{"type":"string"},"description_video_url":{"type":"string"},"welcome_message":{"type":"string"},"welcome_video_url":{"type":"string"},"description_plain_text":{"type":"string"},"welcome_message_plain_text":{"type":"string"},"marketplace_approval_status":{"type":"boolean"},"marketplace_request":{"enum":["requested","unrequested"],"type":"string"},"is_featured":{"type":"boolean"},"featured_for_onboarding":{"type":"boolean"},"language":{"type":"string"},"morning_routine_duration_seconds":{"type":"number"},"evening_routine_duration_seconds":{"type":"number"},"duration":{"type":"number"},"breaks_only":{"type":"boolean"},"deleted_at":{"format":"date-time","type":"string"},"installs":{"type":"array","items":{"$ref":"#/components/schemas/InstalledPack"}},"activity_sequences":{"type":"array","items":{"$ref":"#/components/schemas/ActivitySequence"}},"activity_templates":{"type":"array","items":{"$ref":"#/components/schemas/ActivityTemplate"}},"signed_up_users":{"type":"array","items":{"$ref":"#/components/schemas/User"}},"user":{"$ref":"#/components/schemas/User"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"CustomRoutine":{"type":"object","properties":{"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"ActivitySequence":{"type":"object","properties":{"user_id":{"type":"string"},"type":{"type":"string","enum":["breaking","morning","evening","standalone","library"]},"activity_ids":{"type":"array","items":{"type":"string"}},"generated_sequence_activity_ids":{"type":"array","items":{"type":"string"}},"total_duration_seconds":{"type":"number"},"generated_total_duration_seconds":{"type":"number"},"pack_id":{"type":"string"},"custom_routine_id":{"type":"string"},"user":{"$ref":"#/components/schemas/User"},"habit_pack":{"$ref":"#/components/schemas/HabitPack"},"activities":{"type":"array","items":{"$ref":"#/components/schemas/Activity"}},"completed_activities":{"type":"array","items":{"$ref":"#/components/schemas/CompletedActivity"}},"completed_activity_sequences":{"type":"array","items":{"$ref":"#/components/schemas/CompletedActivitySequence"}},"custom_routine":{"$ref":"#/components/schemas/CustomRoutine"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"DeviceMetadata":{"type":"object","properties":{}},"Device":{"type":"object","properties":{"user_id":{"type":"string"},"operating_system":{"enum":["MacOS","Windows","Android","iOS","Web","Unknown"],"type":"string"},"is_leader":{"type":"boolean"},"app_version":{"type":"string"},"metadata":{"$ref":"#/components/schemas/DeviceMetadata"},"user":{"$ref":"#/components/schemas/User"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"Notification":{"type":"object","properties":{"user_id":{"type":"string"},"platform":{"type":"string","enum":["google","microsoft"]},"platform_account":{"type":"string"},"calendar_id":{"type":"string"},"external_id":{"type":"string"},"summary":{"type":"string"},"description":{"type":"string"},"event_begins":{"format":"date-time","type":"string"},"event_ends":{"format":"date-time","type":"string"},"is_dismissed":{"type":"boolean"},"dismiss_reason":{"type":"string"},"received":{"type":"boolean"},"notified_silent_at":{"format":"date-time","type":"string","nullable":true},"user":{"$ref":"#/components/schemas/User"},"external_metadata":{"type":"object"},"notification_type":{"type":"string","enum":["calendar_event","accountability_buddy_invitation","accountability_buddy_invitation_accepted","unlock_request_received","unlock_request_approved","unlock_request_rejected"]},"action_url":{"type":"string"},"related_entity_id":{"type":"string"},"related_entity_type":{"type":"string"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"SavedWebsite":{"type":"object","properties":{"user_id":{"type":"string"},"url":{"type":"string"},"title":{"type":"string"},"metadata":{"type":"object"},"note":{"type":"string"},"user":{"$ref":"#/components/schemas/User"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["user_id","url","metadata"]},"ImpactEvent":{"type":"object","properties":{"user_id":{"type":"string"},"impact_category":{"type":"string","enum":["hours_of_sleep","energy_level_upon_awakening","mood","perception_of_productivity","minutes_spent_on_distracting_websites","minutes_spent_postponing_app_blocks","minutes_spent_postponing_habits"]},"quantity":{"type":"number"},"user":{"$ref":"#/components/schemas/User"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"UserFeedback":{"type":"object","properties":{"user_id":{"type":"string"},"rating":{"type":"number"},"feedback":{"type":"string"},"metadata":{"type":"object"},"user":{"$ref":"#/components/schemas/User"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"PlatformIntegrationMetadataDto":{"type":"object","properties":{"requires_reauth":{"type":"boolean","description":"Frontend should key UI logic on this field, not on the presence of reauth_reason."},"reauth_reason":{"type":"object","description":"May be non-null even when requires_reauth is false."},"reauth_requested_at":{"type":"string","nullable":true,"description":"ISO timestamp recorded when reauthentication was requested. Cleared when reauth is resolved."},"client_id":{"type":"string"},"access_token":{"type":"string"},"refresh_token":{"type":"string"},"expiry_date":{"type":"number"},"account_server":{"type":"string"},"accountId":{"type":"string"},"location":{"type":"string"},"scope":{"type":"string"}}},"PlatformIntegration":{"type":"object","properties":{"user_id":{"type":"string"},"platform":{"type":"string"},"external_user_id":{"type":"string"},"data":{"$ref":"#/components/schemas/PlatformIntegrationMetadataDto"},"only_assigned":{"type":"boolean"},"user":{"$ref":"#/components/schemas/User"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"CalendarExcludedKeyword":{"type":"object","properties":{"user_id":{"type":"string"},"keyword":{"type":"string"},"platform":{"type":"string","enum":["google","microsoft"]},"intitle":{"type":"boolean"},"indescription":{"type":"boolean"},"user":{"$ref":"#/components/schemas/User"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"Calendar":{"type":"object","properties":{"user_id":{"type":"string"},"platform":{"type":"string","enum":["google","microsoft"]},"platform_account":{"type":"string"},"calendar_id":{"type":"string"},"summary":{"type":"string"},"is_selected":{"type":"boolean"},"user":{"$ref":"#/components/schemas/User"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"UnlockRequest":{"type":"object","properties":{"user_id":{"type":"string"},"accountability_buddy_id":{"type":"string"},"reason":{"type":"string"},"status":{"type":"string","enum":["pending","approved","rejected","expired"]},"approved_at":{"format":"date-time","type":"string"},"unlock_duration_minutes":{"type":"number"},"user":{"$ref":"#/components/schemas/User"},"accountability_buddy":{"$ref":"#/components/schemas/AccountabilityBuddy"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["user_id","accountability_buddy_id","status"]},"AccountabilityBuddy":{"type":"object","properties":{"user_id":{"type":"string"},"buddy_user_id":{"type":"string"},"buddy_email":{"type":"string"},"invitation_status":{"type":"string","enum":["pending","accepted","rejected","expired"]},"invitation_sent_at":{"format":"date-time","type":"string"},"invitation_responded_at":{"format":"date-time","type":"string"},"user":{"$ref":"#/components/schemas/User"},"buddy":{"$ref":"#/components/schemas/User"},"unlock_requests":{"type":"array","items":{"$ref":"#/components/schemas/UnlockRequest"}},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["user_id","buddy_email","invitation_status"]},"Feedback":{"type":"object","properties":{"cancel_subscription_reason":{"type":"string"},"user_id":{"type":"string"},"user":{"$ref":"#/components/schemas/User"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["cancel_subscription_reason","user_id"]},"User":{"type":"object","properties":{"stripe_customer_id":{"type":"string","nullable":true},"profitwell_id":{"type":"string"},"profitwell_registration_date":{"format":"date-time","type":"string"},"auth0_id":{"type":"string"},"startup_time":{"type":"string"},"shutdown_time":{"type":"string"},"utc_startup_time":{"type":"string"},"utc_shutdown_time":{"type":"string"},"routine_notification_times":{"$ref":"#/components/schemas/RoutineNotificationTimes"},"break_after_minutes":{"type":"number"},"current_focus_mode_finish_time":{"format":"date-time","type":"string"},"password_for_settings":{"type":"string"},"is_office_mode_activated":{"type":"boolean"},"current_activity_sequence_id":{"type":"string"},"current_focus_mode_id":{"type":"string"},"current_completing_focus_block_id":{"type":"string"},"current_activity_id":{"type":"string"},"current_activity_assigned_at":{"format":"date-time","type":"string"},"last_completed_sequence_id":{"type":"string"},"current_completing_sequence_log_id":{"type":"string"},"last_completed_sequence_at":{"format":"date-time","type":"string"},"last_completed_sequence_started_at":{"format":"date-time","type":"string"},"current_sequence_started_at":{"format":"date-time","type":"string"},"local_device_settings":{"$ref":"#/components/schemas/UpdateLocalDeviceSettingsDto"},"user_type":{"enum":["STANDARD","ADMIN"],"type":"string"},"signed_up_via_habit_pack":{"type":"string"},"signed_up_via_focus_mode":{"type":"string"},"current_sequence_skipped_activities":{"type":"array","items":{"type":"string"}},"timezone":{"type":"string"},"iana_timezone":{"type":"string","nullable":true,"description":"The user's explicitly declared IANA zone (for example `Australia/Melbourne`), or null when unset.\nDistinct from `timezone`, which is a device-synced UTC offset continuously overwritten by client\nsettings sync. Written only by PATCH /user/timezone."},"has_edited_settings":{"type":"boolean"},"cutoff_time_for_non_high_priority_activities":{"type":"string"},"metadata":{"$ref":"#/components/schemas/UserMetadata"},"user_job_details":{"type":"string"},"user_typical_distractions":{"type":"string"},"habit_theme":{"type":"string","nullable":true,"description":"The habit theme chosen during onboarding (e.g. \"Elmo\"), reused for routine notifications (#2617)."},"themed_routine_notification_titles":{"type":"object","nullable":true,"description":"Written once when the theme is saved, so sending a routine notification never calls the AI (#2617)."},"onboarding_progress":{"$ref":"#/components/schemas/UserOnboardingProgress"},"onboarding_completed_at":{"format":"date-time","type":"string","nullable":true},"last_time_stats_updated":{"format":"date-time","type":"string"},"last_top_score_refreshed_for_date":{"type":"string","nullable":true,"description":"@brief Last user-local date for which `to_do.top_score` has been refreshed.\n@details Stored as a SQL `date` (no time component) holding the user's\n         local calendar date at the time of the last refresh. The\n         off-thread top-score cron compares this against the user's\n         current local \"today\" (computed via the stored `timezone`) and\n         enqueues a recompute job when the local clock has crossed\n         midnight. Updated by the consumer on successful refresh."},"last_completed_focus_mode_at":{"format":"date-time","type":"string"},"morning_routines_streak":{"type":"number"},"evening_routines_streak":{"type":"number"},"focus_modes_streak":{"type":"number"},"micro_breaks_streak":{"type":"number"},"morning_percent_number_day_of_stats_completed":{"type":"number"},"evening_percent_number_day_of_stats_completed":{"type":"number"},"micro_percent_number_day_of_stats_completed":{"type":"number"},"morning_number_days_completed":{"type":"number"},"morning_num_days_of_stats":{"type":"number"},"evening_number_days_completed":{"type":"number"},"evening_num_days_of_stats":{"type":"number"},"micro_breaks_number_days_completed":{"type":"number"},"micro_breaks_num_days_of_stats":{"type":"number"},"focus_modes_number_days_completed":{"type":"number"},"focus_modes_num_days_of_stats":{"type":"number"},"num_days_of_stats":{"type":"number"},"number_days_completed":{"type":"number"},"has_consented_to_terms_of_service":{"type":"boolean"},"has_consented_to_privacy_policy":{"type":"boolean"},"long_term_goals":{"type":"array","items":{"type":"string"}},"verbose_logging":{"type":"boolean"},"last_time_user_settings_modified":{"format":"date-time","type":"string"},"username":{"type":"string"},"has_received_inactivity_warning":{"type":"boolean"},"language":{"type":"string"},"email_frequency":{"enum":["daily","weekly","monthly","unsubscribed"],"type":"string"},"feature_flags":{"type":"array","items":{"type":"string"}},"revenue_cat_data":{"$ref":"#/components/schemas/SubscriptionStatus"},"revenue_cat_status":{"type":"string"},"last_date_revenue_cat_data_synced":{"format":"date-time","type":"string"},"last_status_synced_with_profitwell":{"type":"string"},"last_date_gave_feedback":{"format":"date-time","type":"string"},"is_relax_activity_generated":{"type":"boolean"},"is_internal_tester":{"type":"boolean","description":"Set to true when the mobile app reports this install as an internal tester\nbuild (see mobile-app#4848). Write-once: only ever flips false -> true so a\nlater production reinstall never demotes a known staff account. Used to keep\ninternal testers out of analytics cohorts even when they use real emails."},"internal_tester_source":{"nullable":true,"enum":["build_flag","ios_testflight","android_non_play"],"type":"string"},"synced_projects":{"type":"array","items":{"$ref":"#/components/schemas/SyncedProject"}},"consents":{"type":"array","items":{"$ref":"#/components/schemas/UserConsent"}},"activity_sequences":{"type":"array","items":{"$ref":"#/components/schemas/ActivitySequence"}},"completed_activities":{"type":"array","items":{"$ref":"#/components/schemas/CompletedActivity"}},"completed_activity_sequences":{"type":"array","items":{"$ref":"#/components/schemas/CompletedActivitySequence"}},"completed_focus_blocks":{"type":"array","items":{"$ref":"#/components/schemas/CompletedFocusBlock"}},"devices":{"type":"array","items":{"$ref":"#/components/schemas/Device"}},"to_dos":{"type":"array","items":{"$ref":"#/components/schemas/ToDo"}},"notifications":{"type":"array","items":{"$ref":"#/components/schemas/Notification"}},"focus_modes":{"type":"array","items":{"$ref":"#/components/schemas/FocusMode"}},"blocking_schedules":{"type":"array","items":{"$ref":"#/components/schemas/BlockingSchedule"}},"focus_mode_templates":{"type":"array","items":{"$ref":"#/components/schemas/FocusModeTemplate"}},"created_habit_packs":{"type":"array","items":{"$ref":"#/components/schemas/HabitPack"}},"installed_packs":{"type":"array","items":{"$ref":"#/components/schemas/InstalledPack"}},"installed_focus_modes":{"type":"array","items":{"$ref":"#/components/schemas/InstalledFocusModeTemplate"}},"activity_templates":{"type":"array","items":{"$ref":"#/components/schemas/ActivityTemplate"}},"activities":{"type":"array","items":{"$ref":"#/components/schemas/Activity"}},"log_quantity_questions":{"type":"array","items":{"$ref":"#/components/schemas/LogQuantityQuestion"}},"log_quantity_answers":{"type":"array","items":{"$ref":"#/components/schemas/LogQuantityAnswer"}},"saved_websites":{"type":"array","items":{"$ref":"#/components/schemas/SavedWebsite"}},"impact_events":{"type":"array","items":{"$ref":"#/components/schemas/ImpactEvent"}},"feedback":{"type":"array","items":{"$ref":"#/components/schemas/UserFeedback"}},"task_time_logs":{"type":"array","items":{"$ref":"#/components/schemas/TaskTimeLog"}},"platform_integrations":{"type":"array","items":{"$ref":"#/components/schemas/PlatformIntegration"}},"owned_teams":{"type":"array","items":{"$ref":"#/components/schemas/Team"}},"calendar_keywords":{"type":"array","items":{"$ref":"#/components/schemas/CalendarExcludedKeyword"}},"calendars":{"type":"array","items":{"$ref":"#/components/schemas/Calendar"}},"teamToMember":{"type":"array","items":{"$ref":"#/components/schemas/TeamToMember"}},"teamToAdmin":{"type":"array","items":{"$ref":"#/components/schemas/TeamToAdmin"}},"teamToTeacher":{"type":"array","items":{"$ref":"#/components/schemas/TeamToTeacher"}},"accountability_buddies":{"type":"array","items":{"$ref":"#/components/schemas/AccountabilityBuddy"}},"sign_up_habit_pack":{"$ref":"#/components/schemas/User"},"current_activity":{"$ref":"#/components/schemas/Activity"},"current_activity_sequence":{"$ref":"#/components/schemas/ActivitySequence"},"last_completed_sequence":{"$ref":"#/components/schemas/ActivitySequence"},"completing_sequence_log":{"$ref":"#/components/schemas/CompletedActivitySequence"},"completing_focus_block":{"$ref":"#/components/schemas/CompletedFocusBlock"},"current_focus_mode":{"$ref":"#/components/schemas/FocusMode"},"tutorials":{"type":"array","items":{"$ref":"#/components/schemas/Tutorial"}},"cancel_subscription_feedback":{"$ref":"#/components/schemas/Feedback"},"custom_routines":{"type":"array","items":{"$ref":"#/components/schemas/CustomRoutine"}},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"CurrentTaskDto":{"type":"object","properties":{"task_name":{"type":"string","maxLength":200},"task_id":{"type":"string","format":"uuid"}},"required":["task_name","task_id"]},"CheckInTurnDto":{"type":"object","properties":{"text":{"type":"string","maxLength":4000},"role":{"type":"string","enum":["user","assistant"]}},"required":["text","role"]},"FastSafetyCheckDto":{"type":"object","properties":{"intention":{"type":"string","maxLength":500},"justificationForThisUrl":{"type":"string","maxLength":500},"justification":{"type":"string","maxLength":500},"extraJustificationForThisSite":{"type":"string","maxLength":500},"lastFiveJustificationsInThisFocusSession":{"type":"array","items":{"type":"string","maxLength":500}},"class_session_id":{"type":"string","format":"uuid"},"justificationForThisSpecificApp":{"type":"string","maxLength":500},"target":{"enum":["url","app"],"type":"string","description":"Whether the fields describe a website or an app"},"url":{"type":"string"},"tab_title":{"type":"string"},"meta_description":{"type":"string"},"focus_mode":{"type":"string"},"language":{"type":"object","default":"English"},"currentTaskInToDoPlayer":{"type":"string"},"task_must_align_to_focus_intention":{"type":"boolean"},"current_tasks":{"type":"array","items":{"$ref":"#/components/schemas/CurrentTaskDto"}},"check_in_conversation":{"type":"array","items":{"$ref":"#/components/schemas/CheckInTurnDto"}},"focusMode":{"type":"string"},"appName":{"type":"string"}},"required":["intention","target","url","tab_title","meta_description","focus_mode","language","focusMode","appName"]},"FastSafetyCheckResponseDto":{"type":"object","properties":{"allow":{"type":"boolean","description":"true: allow now, no further check needed. false: blur and call the full check (/user/is-url-safe-to-use or /user/is-app-safe-to-use) for the decision and the reason to show."},"score":{"type":"number","description":"0–1 allow score from the gate; for diagnostics only","minimum":0,"maximum":1},"source":{"enum":["assistive_technology","jev","unavailable","skipped"],"type":"string"}},"required":["allow","score","source"]},"ActivityChoiceData":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"completion_requirements":{"type":"string"},"log_quantity":{"type":"boolean"},"log_quantity_question":{"type":"string"},"log_quantity_questions":{"type":"array","items":{"$ref":"#/components/schemas/LogQuantityQuestion"}},"log_summary_type":{"enum":["SUM","AVG"],"type":"string"},"video_urls":{"type":"array","items":{"type":"string"}},"allowed_apps":{"type":"array","items":{"type":"string"}},"allowed_mobile_apps":{"type":"array","items":{"type":"string"}},"allowed_urls":{"type":"array","items":{"type":"string"}},"geofence_id":{"type":"string","nullable":true,"format":"uuid"},"duration_seconds":{"type":"number"},"competency_level":{"type":"number"},"activity_template_id":{"type":"string","format":"uuid"},"linked_activity_id":{"type":"string","format":"uuid"},"linked_activity_template_id":{"type":"string","format":"uuid"},"habit_icon":{"type":"string"}},"required":["id","name"]},"UpdateActivityDto":{"type":"object","properties":{"name":{"type":"string"},"is_office_friendly":{"type":"boolean"},"take_notes":{"enum":["NO_NOTE","DURING_ACTIVITY","END_OF_ACTIVITY"],"type":"string"},"priority":{"enum":["STANDARD","HIGH"],"type":"string"},"allowed_focus_mode_id":{"type":"string","format":"uuid"},"video_urls":{"type":"array","items":{"type":"string"}},"include_in_every_break":{"type":"boolean"},"habit_icon":{"type":"string"},"habit_icon_generation_failed":{"type":"boolean"},"log_quantity_question":{"type":"string"},"choice_type":{"enum":["random","normal","competency","check_list"],"type":"string"},"allowed_apps":{"type":"array","items":{"type":"string"}},"allowed_mobile_apps":{"type":"array","items":{"type":"string"}},"allowed_urls":{"type":"array","items":{"type":"string"}},"break_type":{"enum":["micro","pomodoro"],"type":"string"},"linked_project_ids":{"maxItems":10,"type":"array","items":{"type":"string","format":"uuid"}},"tags":{"type":"array","items":{"type":"string"}},"linked_project_id":{"type":"string","format":"uuid","description":"First of linked_project_ids, for older clients"},"log_quantity":{"type":"boolean"},"duration_seconds":{"type":"number"},"completion_requirements":{"type":"string"},"log_summary_type":{"enum":["SUM","AVG"],"type":"string"},"choices":{"minItems":1,"type":"array","items":{"$ref":"#/components/schemas/ActivityChoiceData"}},"days_of_week":{"minItems":1,"items":{"type":"string","enum":["ALL","MON","TUE","WED","THU","FRI","SAT","SUN"]},"default":["ALL"],"type":"array"},"impact_category":{"enum":["hours_of_sleep","energy_level_upon_awakening","mood","perception_of_productivity","minutes_spent_on_distracting_websites","minutes_spent_postponing_app_blocks","minutes_spent_postponing_habits"],"type":"string"},"geofence_id":{"type":"string","nullable":true,"format":"uuid"},"id":{"type":"string","format":"uuid"},"activity_template_id":{"type":"string","format":"uuid"},"is_default":{"type":"boolean"},"run_micro_breaks":{"type":"boolean"},"log_quantity_questions":{"type":"array","items":{"$ref":"#/components/schemas/LogQuantityQuestion"}},"linked_activity_id":{"type":"string","format":"uuid"},"linked_activity_template_id":{"type":"string","format":"uuid"},"check_list":{"type":"array","items":{"type":"string"}},"activity_type":{"type":"string"},"tutorial":{"type":"string","format":"uuid"},"cutoff_time_for_doing_activity":{"type":"string"},"category":{"type":"string"},"text_instructions":{"type":"string"},"image_urls":{"type":"array","items":{"$ref":"#/components/schemas/ActivityImageData"}},"current_competency_level":{"type":"number"},"competency_level":{"type":"number"},"show_saved_distracting_websites":{"type":"boolean"}},"required":["name","id"]},"UpdateCustomRoutineDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"trigger":{"enum":["ON_DEMAND","ON_SCHEDULE"],"type":"string"},"days_of_week":{"minItems":1,"type":"array","items":{"type":"string","enum":["ALL","MON","TUE","WED","THU","FRI","SAT","SUN"]}},"standalone_activities":{"type":"array","items":{"$ref":"#/components/schemas/UpdateActivityDto"}},"start_time":{"type":"string"},"end_time":{"type":"string"},"activity_sequence_id":{"type":"string","format":"uuid"}},"required":["name","trigger"]},"UpdateUserSettingsDto":{"type":"object","properties":{"morning_activities":{"type":"array","items":{"$ref":"#/components/schemas/UpdateActivityDto"}},"evening_activities":{"type":"array","items":{"$ref":"#/components/schemas/UpdateActivityDto"}},"break_activities":{"type":"array","items":{"$ref":"#/components/schemas/UpdateActivityDto"}},"language":{"enum":["en","es","de","ja","vi","pt-BR","pt-PT","zh-CN","zh-TW","nl","tl","fr","it","pl","ru","ar","ro"],"type":"string","default":"en"},"custom_routines":{"type":"array","items":{"$ref":"#/components/schemas/UpdateCustomRoutineDto"}},"verbose_logging":{"type":"boolean"},"startup_time":{"type":"string"},"shutdown_time":{"type":"string"},"sleep_time":{"type":"string"},"cutoff_time_for_non_high_priority_activities":{"type":"string"},"break_after_minutes":{"type":"number","minimum":1}}},"Auth0ClientDto":{"type":"object","properties":{"client_id":{"type":"string"},"name":{"type":"string"},"user_agent":{"type":"string"}},"required":["client_id","name"]},"SyncUserAccountDto":{"type":"object","properties":{"auth0_id":{"type":"string"},"email":{"type":"string","format":"email"},"auth0_client":{"$ref":"#/components/schemas/Auth0ClientDto"}},"required":["email"]},"UserAuthContext":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"a91d601e-f06d-4c22-8d0c-da3eccfc271a"},"subscriptionStatus":{"$ref":"#/components/schemas/SubscriptionStatus"},"stripeCustomerId":{"type":"string"},"email":{"type":"string"}},"required":["id"]},"AdminTeamSummaryDto":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"]},"UserSummaryResponseDto":{"type":"object","properties":{"id":{"type":"string"},"stripe_customer_id":{"type":"string"},"email":{"type":"string"},"email_verified":{"type":"boolean"},"username":{"type":"string"},"language":{"type":"string"},"adminForTeams":{"type":"array","items":{"$ref":"#/components/schemas/AdminTeamSummaryDto"}},"has_consented_to_terms_of_service":{"type":"boolean"},"user_type":{"enum":["STANDARD","ADMIN"],"type":"string"},"has_consented_to_privacy_policy":{"type":"boolean"}},"required":["id","email","email_verified"]},"SequenceStatus":{"type":"string","enum":["completed","postponed","in_progress"]},"RoutineProgressItem":{"type":"object","properties":{"sequence_id":{"type":"string"},"status":{"allOf":[{"$ref":"#/components/schemas/SequenceStatus"}]},"completed_habit_ids":{"description":"All logged activity IDs for this routine, including skipped activities.","type":"array","items":{"type":"string"}},"skipped_habit_ids":{"description":"Subset of completed_habit_ids that were skipped without completion. skipped_did_complete is excluded.","type":"array","items":{"type":"string"}},"was_force_completed":{"type":"boolean","description":"Present only when status is completed. Indicates the routine was force-completed."}},"required":["sequence_id","status"]},"TodayRoutineProgress":{"type":"object","properties":{"morning_routine":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/RoutineProgressItem"}]},"evening_routine":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/RoutineProgressItem"}]},"custom_routines":{"type":"array","items":{"$ref":"#/components/schemas/RoutineProgressItem"}},"standalone_routines":{"type":"array","items":{"$ref":"#/components/schemas/RoutineProgressItem"}}},"required":["morning_routine","evening_routine","custom_routines","standalone_routines"]},"CurrentActivityProps":{"type":"object","properties":{"current_activity_sequence":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/ActivitySequence"}]},"last_completed_sequence_started_at":{"format":"date-time","type":"string","nullable":true},"current_activity":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/Activity"}]},"current_activity_assigned_at":{"format":"date-time","type":"string","nullable":true},"last_completed_sequence":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/ActivitySequence"}]},"last_completed_sequence_at":{"format":"date-time","type":"string","nullable":true},"current_focus_mode":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/FocusMode"}]},"current_focus_mode_finish_time":{"format":"date-time","type":"string","nullable":true},"current_sequence_skipped_activities":{"type":"array","items":{"type":"string"}},"last_time_user_settings_modified":{"format":"date-time","type":"string"},"current_sequence_completed_activities":{"type":"array","items":{"type":"string"}},"completing_focus_block":{"$ref":"#/components/schemas/CompletedFocusBlock"},"today_routine_progress":{"$ref":"#/components/schemas/TodayRoutineProgress"}},"required":["today_routine_progress"]},"UpdateFocusBlockDto":{"type":"object","properties":{"intention":{"type":"string","maxLength":400},"achievements":{"type":"string","maxLength":400},"distractions":{"type":"string","maxLength":400},"focus_duration_seconds":{"type":"number","minimum":0,"description":"Duration in seconds (numeric, e.g. 3600). Must be ≥ 0."},"project_id":{"type":"string","nullable":true,"format":"uuid","description":"The project the session was for. The caller must own or be an accepted member of it; null clears it."},"focus_stars":{"type":"number","minimum":1,"maximum":5,"description":"The \"How focused were you?\" rating, stored as metadata.focus_stars like the finish call does."}}},"CreateFocusBlockDto":{"type":"object","properties":{"intention":{"type":"string","maxLength":400},"achievements":{"type":"string","maxLength":400},"distractions":{"type":"string","maxLength":400},"focus_duration_seconds":{"type":"number","minimum":0,"description":"Duration in seconds (numeric, e.g. 3600). Must be ≥ 0."},"start_time":{"type":"string"},"finish_time":{"type":"string"},"focus_mode_id":{"type":"string","format":"uuid","description":"Optional focus mode ID. Defaults to a special \"Manual\" focus mode."}},"required":["focus_duration_seconds","start_time","finish_time"]},"UpdateUserSignUpFieldDto":{"type":"object","properties":{"pack_id":{"type":"string","format":"uuid"},"focus_mode_template_id":{"type":"string","format":"uuid"}}},"UpdateUserMetadataDto":{"type":"object","properties":{"profile_image":{"type":"string","description":"Profile image must be a valid R2-hosted URL.\nThe legacy bytecloud { url: string } object format is no longer accepted.","format":"uri"},"description":{"type":"string"},"name":{"type":"string"},"email_preferences":{"type":"object","additionalProperties":true},"user_job_details":{"type":"string"},"user_typical_distractions":{"type":"string"}}},"PolicyConsentStatusDto":{"type":"object","properties":{"current_version":{"type":"string"},"accepted_version":{"type":"string","nullable":true},"accepted_at":{"type":"string","nullable":true,"description":"For consents recorded before versioning this is the row's last update, an approximation"},"requires_consent":{"type":"boolean"},"url":{"type":"string"}},"required":["current_version","accepted_version","accepted_at","requires_consent","url"]},"ConsentStatusResponseDto":{"type":"object","properties":{"requires_consent":{"type":"boolean","description":"True when any policy needs (re-)consent; clients block use until the user accepts"},"policies":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/PolicyConsentStatusDto"},"description":"Keyed by consent type: privacy_policy and terms_of_service"}},"required":["requires_consent","policies"]},"OnboardingStatsResponseDto":{"type":"object","properties":{"level":{"type":"number"},"total_percent":{"type":"number"},"has_edited_settings":{"type":"boolean"},"has_edited_always_blocked_urls":{"type":"boolean"},"has_edited_focus_mode":{"type":"boolean"},"has_chatted_with_focus_bear":{"type":"boolean"},"has_installed_desktop_app":{"type":"boolean"},"has_installed_mobile_app":{"type":"boolean"},"morning_routine_completion_streak_days":{"type":"number"},"evening_routine_completion_streak_days":{"type":"number"},"focus_mode_completion_streak_days":{"type":"number"},"morning_routines_completion_percentage_for_current_level":{"type":"number"},"evening_routines_completion_percentage_for_current_level":{"type":"number"},"focus_modes_completion_percentage_for_current_level":{"type":"number"},"average_morning_routines_completion_percentage":{"type":"number"},"average_evening_routines_completion_percentage":{"type":"number"},"average_num_focus_modes_completed_per_day":{"type":"number"},"routines_threshold":{"type":"number"},"focus_modes_threshold":{"type":"number"},"break_routines_completion_percentage_for_current_level":{"type":"number"},"break_routine_completion_streak_days":{"type":"number"},"average_break_routines_completion_percentage":{"type":"number"}},"required":["level","total_percent","has_edited_settings","has_edited_always_blocked_urls","has_edited_focus_mode","has_chatted_with_focus_bear","has_installed_desktop_app","has_installed_mobile_app","morning_routine_completion_streak_days","evening_routine_completion_streak_days","focus_mode_completion_streak_days","morning_routines_completion_percentage_for_current_level","evening_routines_completion_percentage_for_current_level","focus_modes_completion_percentage_for_current_level","average_morning_routines_completion_percentage","average_evening_routines_completion_percentage","average_num_focus_modes_completed_per_day","routines_threshold","focus_modes_threshold","break_routines_completion_percentage_for_current_level","break_routine_completion_streak_days","average_break_routines_completion_percentage"]},"OnboardingReEngagementEmailResponseDto":{"type":"object","properties":{"sent":{"type":"boolean"},"reason":{"type":"string","enum":["onboarding_already_complete","no_email_on_file","user_not_found","unsubscribed","send_failed"]}},"required":["sent"]},"IsUrlSafeDto":{"type":"object","properties":{"intention":{"type":"string","maxLength":500},"justificationForThisUrl":{"type":"string","maxLength":500},"justification":{"type":"string","maxLength":500},"extraJustificationForThisSite":{"type":"string","maxLength":500},"lastFiveJustificationsInThisFocusSession":{"type":"array","items":{"type":"string","maxLength":500}},"class_session_id":{"type":"string","format":"uuid"},"url":{"type":"string"},"tab_title":{"type":"string"},"meta_description":{"type":"string"},"focus_mode":{"type":"string"},"language":{"type":"object","default":"English"},"currentTaskInToDoPlayer":{"type":"string"},"task_must_align_to_focus_intention":{"type":"boolean"},"current_tasks":{"type":"array","items":{"$ref":"#/components/schemas/CurrentTaskDto"}},"check_in_conversation":{"type":"array","items":{"$ref":"#/components/schemas/CheckInTurnDto"}}},"required":["intention","url","tab_title","meta_description","focus_mode","language"]},"URLSafeProbabilityResponseDto":{"type":"object","properties":{"isTaskMisalignedWithIntention":{"type":"boolean"},"allowed_probability":{"type":"number","minimum":0,"maximum":1},"reason":{"type":"string"},"suggested_task":{"type":"string"},"suggested_task_id":{"type":"string"},"suggested_duration_minutes":{"type":"number"}},"required":["allowed_probability","reason"]},"IsAppSafeDto":{"type":"object","properties":{"intention":{"type":"string","maxLength":500},"justificationForThisSpecificApp":{"type":"string","maxLength":500},"justification":{"type":"string","maxLength":500},"extraJustificationForThisSite":{"type":"string","maxLength":500},"lastFiveJustificationsInThisFocusSession":{"type":"array","items":{"type":"string","maxLength":500}},"class_session_id":{"type":"string","format":"uuid"},"focusMode":{"type":"string"},"appName":{"type":"string"},"language":{"type":"object","default":"English"},"currentTaskInToDoPlayer":{"type":"string"},"task_must_align_to_focus_intention":{"type":"boolean"},"current_tasks":{"type":"array","items":{"$ref":"#/components/schemas/CurrentTaskDto"}},"check_in_conversation":{"type":"array","items":{"$ref":"#/components/schemas/CheckInTurnDto"}}},"required":["intention","focusMode","appName","language"]},"TaskIntentionCheckDto":{"type":"object","properties":{"intention":{"type":"string","maxLength":500,"description":"The focus intention the user set for this session."},"task_name":{"type":"string","maxLength":200,"description":"The name of the task the user is (or is about to be) working on."},"focus_mode":{"type":"string","maxLength":200,"description":"Optional focus mode name for extra context."}},"required":["intention","task_name"]},"TaskIntentionCheckResponseDto":{"type":"object","properties":{"aligns":{"type":"boolean","description":"Whether the task supports the focus intention. Lenient: true unless clearly conflicting."},"reason":{"type":"string","description":"Short, kind, user-facing sentence localised to the user's language. When aligns=false it names both the intention and the task; when aligns=true it may be a brief confirmation or empty."}},"required":["aligns","reason"]},"FocusPostponementMessageDto":{"type":"object","properties":{"content":{"type":"string","maxLength":500},"role":{"type":"string","enum":["user","assistant"]}},"required":["content","role"]},"FocusPostponementTaskCandidateDto":{"type":"object","properties":{"title":{"type":"string","maxLength":200},"project":{"type":"string","maxLength":200},"id":{"type":"string","maxLength":128}},"required":["title","id"]},"FocusPostponementDayBlockDto":{"type":"object","properties":{"start":{"type":"string"},"end":{"type":"string"},"kind":{"type":"string","enum":["event","routine","free"]}},"required":["start","end","kind"]},"EvaluateFocusPostponementDto":{"type":"object","properties":{"uncompletedHabits":{"type":"array","items":{"type":"string","maxLength":200}},"dayPlanTasks":{"type":"array","items":{"type":"string","maxLength":200}},"currentMeetingTitle":{"type":"string","nullable":true,"maxLength":2000},"calendarEvents":{"type":"array","items":{"type":"string","maxLength":2000}},"language":{"type":"string","maxLength":200},"routineCompletionPercent":{"type":"number","minimum":0,"maximum":100},"minutesLeftInDay":{"type":"number","minimum":0,"maximum":1440},"requestedMinutes":{"type":"number","minimum":0,"maximum":1440},"recentHabitMinutes":{"type":"number","minimum":0,"maximum":60},"minutesSinceLastPostpone":{"type":"number","minimum":0,"maximum":1440},"postponesToday":{"type":"number","minimum":0,"maximum":100},"freeMinutesToday":{"type":"number","minimum":0,"maximum":1440},"remainingHabitMinutes":{"type":"number","minimum":0,"maximum":1440},"plannedTaskMinutes":{"type":"number","minimum":0,"maximum":1440},"messages":{"minItems":1,"type":"array","items":{"$ref":"#/components/schemas/FocusPostponementMessageDto"}},"dayPlanTaskCandidates":{"maxItems":100,"type":"array","items":{"$ref":"#/components/schemas/FocusPostponementTaskCandidateDto"}},"currentLocalTime":{"type":"string"},"restOfDayBlocks":{"type":"array","items":{"$ref":"#/components/schemas/FocusPostponementDayBlockDto"}}},"required":["uncompletedHabits","dayPlanTasks","messages"]},"EvaluateFocusPostponementResponseDto":{"type":"object","properties":{"verdict":{"type":"string","enum":["approve","deny"]},"intention":{"type":"string"},"clampedDurationMinutes":{"type":"number"},"allowedApps":{"type":"array","items":{"type":"string"}},"allowedUrls":{"type":"array","items":{"type":"string"}},"reason":{"type":"string"},"selectedTaskIds":{"type":"array","items":{"type":"string"}}},"required":["verdict","intention","clampedDurationMinutes","allowedApps","allowedUrls","reason"]},"GenerateOccupationSitesDto":{"type":"object","properties":{"user_occupation":{"type":"string","maxLength":200}},"required":["user_occupation"]},"OccupationSitesResponseDto":{"type":"object","properties":{"user_relevant_sites":{"type":"array","items":{"type":"string"}},"user_typical_distractions":{"type":"array","items":{"type":"string"}}},"required":["user_relevant_sites","user_typical_distractions"]},"UpdateLongTermGoalsDto":{"type":"object","properties":{"goals":{"type":"array","items":{"type":"string"}}},"required":["goals"]},"UserTimezoneResponseDto":{"type":"object","properties":{"timezone":{"type":"string","nullable":true,"description":"The timezone the user has explicitly declared, or null when they have never set one. Clients should fall back to their own local zone on null rather than assuming UTC.","example":"Australia/Melbourne"}},"required":["timezone"]},"UpdateUserTimezoneDto":{"type":"object","properties":{"timezone":{"type":"string","maxLength":255,"description":"Named IANA timezone identifier. UTC offsets such as \"UTC+10:00\" or \"+05:00\" are rejected.","example":"Australia/Melbourne"}},"required":["timezone"]},"UpdateUsernameDto":{"type":"object","properties":{"username":{"type":"string","maxLength":30}},"required":["username"]},"EmailPreferencesResponseDto":{"type":"object","properties":{"email_frequency":{"enum":["daily","weekly","monthly","unsubscribed"],"type":"string","description":"Current email frequency setting"},"last_email_sent":{"type":"string","nullable":true,"description":"Timestamp of last email sent"},"unsubscribe_token":{"type":"string","description":"Token for one-click unsubscribe"}},"required":["email_frequency","last_email_sent","unsubscribe_token"]},"EmailPreferences":{"type":"object","properties":{"include_shareable_content":{"type":"boolean"}}},"UpdateEmailPreferencesDto":{"type":"object","properties":{"email_frequency":{"enum":["daily","weekly","monthly","unsubscribed"],"type":"string","description":"Email frequency preference"},"preferences":{"description":"Email preferences object","allOf":[{"$ref":"#/components/schemas/EmailPreferences"}]}}},"UnsubscribeEmailDto":{"type":"object","properties":{"token":{"type":"string","description":"Unsubscribe token from email link"},"reason":{"type":"string","description":"Reason for unsubscribing"}}},"UpdateEmailPreferencesWithTokenDto":{"type":"object","properties":{"token":{"type":"string","description":"The email preferences token sent to the user via email.","example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."},"email_frequency":{"enum":["daily","weekly","monthly","unsubscribed"],"type":"string","description":"The desired new email frequency.","example":"daily"}},"required":["token","email_frequency"]},"RequestEmailPreferencesLinkDto":{"type":"object","properties":{"email":{"type":"string","format":"email","description":"Email address to send the preferences link to"}},"required":["email"]},"ConfirmProfileImageUploadDto":{"type":"object","properties":{"publicUrl":{"type":"string","description":"The public R2 URL returned by GET /user/profile-image-upload-url.\nMust be a valid URL pointing to Focus Bear R2 storage.","format":"uri"}},"required":["publicUrl"]},"DailyStatSummary":{"type":"object","properties":{"date":{"format":"date-time","type":"string"},"day_of_week":{"type":"string"},"morning_percentage":{"type":"number"},"evening_percentage":{"type":"number"},"micro_breaks_completion_percentage":{"type":"number"},"focus_modes":{"type":"number"},"morning_minutes":{"type":"number"},"morning_total_minutes":{"type":"number"},"evening_minutes":{"type":"number"},"evening_total_minutes":{"type":"number"},"micro_breaks_minutes":{"type":"number"},"micro_breaks_total_minutes":{"type":"number"},"total_hours_spent_in_focus_sessions":{"type":"number"}},"required":["date","day_of_week","morning_total_minutes","evening_total_minutes","micro_breaks_total_minutes","total_hours_spent_in_focus_sessions"]},"AdminUserStatsResponseDto":{"type":"object","properties":{"total_focus_sessions":{"type":"number"},"total_focus_duration_minutes":{"type":"number"},"total_habits_completed":{"type":"number"},"total_routines_completed":{"type":"number"},"average_daily_focus_minutes":{"type":"number"},"streak_days":{"type":"number"}}},"UserFeedbackDto":{"type":"object","properties":{"rating":{"type":"number","minimum":0,"maximum":5},"feedback":{"type":"string","maxLength":2500},"metadata":{"type":"object"}}},"LinkUserToParticipantCodeDto":{"type":"object","properties":{"participantCode":{"type":"string"}},"required":["participantCode"]},"TrialResultDto":{"type":"object","properties":{"trialIndex":{"type":"number"},"stimulusType":{"type":"string","enum":["congruent","incongruent"]},"correctDirection":{"type":"string","enum":["left","right"]},"userResponse":{"type":"string","enum":["left","right"]},"isCorrect":{"type":"boolean"},"reactionTimeMs":{"type":"number","nullable":true}},"required":["trialIndex","stimulusType","correctDirection","userResponse","isCorrect","reactionTimeMs"]},"SaveFlankerTestResultDto":{"type":"object","properties":{"totalTrials":{"type":"number"},"missedTrials":{"type":"number"},"overallAccuracy":{"type":"number"},"congruentAccuracy":{"type":"number"},"incongruentAccuracy":{"type":"number"},"meanRtCongruent":{"type":"number"},"meanRtIncongruent":{"type":"number"},"trialResults":{"type":"array","items":{"$ref":"#/components/schemas/TrialResultDto"}},"isEndOfStudy":{"type":"boolean"}},"required":["totalTrials","missedTrials","overallAccuracy","congruentAccuracy","incongruentAccuracy","meanRtCongruent","meanRtIncongruent","trialResults","isEndOfStudy"]},"UsageDataDto":{"type":"object","properties":{"sourceName":{"type":"string"},"usageType":{"type":"string","enum":["app","website"]},"usageCategory":{"type":"string"},"platform":{"type":"string"},"deviceId":{"type":"string"},"usageStartDate":{"format":"date-time","type":"string"},"usageEndDate":{"format":"date-time","type":"string"},"minutesUsedTotal":{"type":"number"},"minutesUsedDuringSleepWindow":{"type":"number"}},"required":["sourceName","usageType","usageCategory","platform","deviceId","usageStartDate","usageEndDate","minutesUsedTotal","minutesUsedDuringSleepWindow"]},"SyncUsageDataDto":{"type":"object","properties":{"usageData":{"type":"array","items":{"$ref":"#/components/schemas/UsageDataDto"}}},"required":["usageData"]},"UploadUsageImageDto":{"type":"object","properties":{"imageKey":{"type":"string"},"platform":{"type":"string"},"deviceId":{"type":"string"},"usageStartDate":{"format":"date-time","type":"string"},"usageEndDate":{"format":"date-time","type":"string"}},"required":["imageKey","usageStartDate","usageEndDate"]},"UploadUsageImageResponseDto":{"type":"object","properties":{"asyncTaskId":{"type":"string","description":"The ID of the async task created for processing the usage image","example":"uuid-string-here"}},"required":["asyncTaskId"]},"HealthMetricItem":{"type":"object","properties":{"metricType":{"type":"string","enum":["hours_of_sleep","minutes_of_movement","number_of_steps_moved"]},"dayOfTracking":{"format":"date-time","type":"string"},"metricValue":{"type":"number"}},"required":["metricType","dayOfTracking","metricValue"]},"SyncHealthMetricsDto":{"type":"object","properties":{"healthMetrics":{"type":"array","items":{"$ref":"#/components/schemas/HealthMetricItem"}}},"required":["healthMetrics"]},"WeeklyFocusHoursDto":{"type":"object","properties":{"week_start":{"type":"string"},"week_label":{"type":"string"},"total_focus_seconds":{"type":"number"},"total_focus_hours":{"type":"number"}},"required":["week_start","week_label","total_focus_seconds","total_focus_hours"]},"WeeklyFocusHoursResponseDto":{"type":"object","properties":{"user_id":{"type":"string"},"weeks":{"type":"array","items":{"$ref":"#/components/schemas/WeeklyFocusHoursDto"}}},"required":["user_id","weeks"]},"FocusSessionLogDto":{"type":"object","properties":{"id":{"type":"string"},"start_time":{"format":"date-time","type":"string"},"finish_time":{"format":"date-time","type":"string"},"focus_duration_seconds":{"type":"number"},"intention":{"type":"string","nullable":true},"distractions":{"type":"string","nullable":true},"achievements":{"type":"string","nullable":true},"focus_mode_name":{"type":"string","nullable":true},"is_manual":{"type":"boolean"}},"required":["id","start_time","finish_time","focus_duration_seconds","is_manual"]},"UserFocusSessionLogsDto":{"type":"object","properties":{"user_id":{"type":"string"},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/FocusSessionLogDto"}}},"required":["user_id","sessions"]},"FocusSessionLogsResponseDto":{"type":"object","properties":{"users":{"type":"array","items":{"$ref":"#/components/schemas/UserFocusSessionLogsDto"}}},"required":["users"]},"LogQuantityAnswerDto":{"type":"object","properties":{"logged_value":{"type":"number"},"question_id":{"type":"string","format":"uuid"}},"required":["logged_value","question_id"]},"CreateCompletedActivityDto":{"type":"object","properties":{"activity_id":{"type":"string","format":"uuid"},"choice_id":{"type":"string","format":"uuid"},"quantity_logged":{"type":"number"},"duration_logged":{"type":"number"},"note_logged":{"type":"string"},"device_id":{"type":"string","format":"uuid"},"activity_sequence_id":{"type":"string","format":"uuid"},"start_time":{"format":"date-time","type":"string"},"finish_time":{"format":"date-time","type":"string"},"metadata":{"$ref":"#/components/schemas/CompletedActivityMetadata"},"should_not_update_current_activity":{"type":"boolean"},"log_quantity_answers":{"type":"array","items":{"$ref":"#/components/schemas/LogQuantityAnswerDto"}}},"required":["activity_id","duration_logged","device_id","activity_sequence_id"]},"CompletedActivityResponse":{"type":"object","properties":{"completed_activity_log":{"$ref":"#/components/schemas/CompletedActivity"},"completed_choice_log":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/CompletedActivity"}]},"saved_log_quantity_answers":{"type":"array","items":{"type":"object"}}},"required":["completed_activity_log"]},"CreateSkippedActivityDto":{"type":"object","properties":{"activity_id":{"type":"string","format":"uuid"},"choice_id":{"type":"string","format":"uuid"},"quantity_logged":{"type":"number"},"duration_logged":{"type":"number"},"note_logged":{"type":"string"},"device_id":{"type":"string","format":"uuid"},"activity_sequence_id":{"type":"string","format":"uuid"},"start_time":{"format":"date-time","type":"string"},"finish_time":{"format":"date-time","type":"string"},"metadata":{"$ref":"#/components/schemas/CompletedActivityMetadata"},"should_not_update_current_activity":{"type":"boolean"},"log_quantity_answers":{"type":"array","items":{"$ref":"#/components/schemas/LogQuantityAnswerDto"}}},"required":["activity_id","device_id","activity_sequence_id"]},"OfflineSyncActivitiesDto":{"type":"object","properties":{"completed_activites":{"type":"array","items":{"$ref":"#/components/schemas/CreateSkippedActivityDto"}},"completed_activities":{"type":"array","items":{"$ref":"#/components/schemas/CreateSkippedActivityDto"}}},"required":["completed_activites","completed_activities"]},"CompletedActivityStatItem":{"type":"object","properties":{"date":{"type":"string"},"summary":{"type":"string","description":"Duration in seconds or quantity logged (stringified integer)"},"count":{"type":"string","description":"Number of completions for this day (stringified integer)"}}},"LogQuantityAnswersStats":{"type":"object","properties":{"question":{"$ref":"#/components/schemas/LogQuantityQuestion"},"question_id":{"type":"string"},"timezone":{"type":"string"},"days_number":{"type":"number"},"log_summary_type":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/CompletedActivityStatItem"}}}},"CompletedActivityStats":{"type":"object","properties":{"activity_id":{"type":"string"},"timezone":{"type":"string"},"days_number":{"type":"number"},"log_summary_type":{"type":"string"},"stat_type":{"enum":["quantity","duration"],"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/CompletedActivityStatItem"}},"log_quantity_answers_stats":{"type":"array","items":{"$ref":"#/components/schemas/LogQuantityAnswersStats"}}}},"GetBulkConsistencyStatsDto":{"type":"object","properties":{"days_number":{"type":"number","default":30,"maximum":180,"minimum":1},"activity_ids":{"type":"array","items":{"type":"string","format":"uuid"}},"timezone":{"type":"string","default":"UTC"}},"required":["days_number","activity_ids","timezone"]},"HabitConsistencyStat":{"type":"object","properties":{"activity_id":{"type":"string"},"completed_days":{"type":"number","description":"Number of distinct local days with at least one completion in the window."},"scheduled_days":{"type":"number","description":"Days in the window the habit was due: on or after its creation day, on a weekday in its `days_of_week`. Uses the current schedule for the whole window."},"consistency_percent":{"type":"number","nullable":true,"description":"`completed_days` as a percentage of `scheduled_days`, rounded and capped at 100. Null when the habit had no scheduled days in the window, so it has no score and should be left out of consistency rankings."}},"required":["activity_id","completed_days","scheduled_days","consistency_percent"]},"BulkConsistencyStats":{"type":"object","properties":{"days_number":{"type":"number"},"habits":{"type":"array","items":{"$ref":"#/components/schemas/HabitConsistencyStat"}}},"required":["days_number","habits"]},"GetLogQuantityAnswerLogsDto":{"type":"object","properties":{"question_ids":{"minItems":1,"type":"array","items":{"type":"string","format":"uuid"}}},"required":["question_ids"]},"ReviseCompletedActivityDto":{"type":"object","properties":{"quantity_logged":{"type":"number"},"log_quantity_answers":{"type":"array","items":{"$ref":"#/components/schemas/LogQuantityAnswerDto"}}}},"UndoCompletedActivityResponse":{"type":"object","properties":{"activity_sequence_id":{"type":"string"},"current_activity_id":{"type":"string","nullable":true,"description":"The user's current habit after the undo, or null when the routine is not the active one."},"routine_reopened":{"type":"boolean","description":"Whether a completed routine was reopened because its habit was undone."}},"required":["activity_sequence_id","current_activity_id","routine_reopened"]},"UnskipActivityDto":{"type":"object","properties":{"device_id":{"type":"string","format":"uuid","description":"The calling device. Sent back as leader_device_id in the activity-completed Pusher event so the device that unskipped can ignore its own echo."}}},"UnskipActivityResponse":{"type":"object","properties":{"unskipped":{"type":"boolean","description":"Whether a skip was removed. False, with nothing changed, when the habit has no skip in today's routine: it was never skipped, was already unskipped, or was done after the skip."},"activity_sequence_id":{"type":"string","nullable":true,"description":"The routine the habit was restored to."},"current_activity_id":{"type":"string","nullable":true,"description":"The user's current habit after the unskip, or null when the routine is not the active one."},"routine_reopened":{"type":"boolean","description":"Whether a completed routine was reopened because its habit was unskipped."}},"required":["unskipped","activity_sequence_id","current_activity_id","routine_reopened"]},"FocusModeDaySummaryItem":{"type":"object","properties":{"name":{"type":"string"},"start_time":{"format":"date-time","type":"string"},"duration":{"type":"number"},"achievements":{"type":"string"},"distractions":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"project_id":{"type":"string","nullable":true},"metadata":{"type":"object"}},"required":["name","start_time","duration","achievements","distractions","tags","metadata"]},"ActivityQuantityDaySummaryItem":{"type":"object","properties":{"name":{"type":"string"},"quantity":{"type":"number"}},"required":["name","quantity"]},"ActivityDurationDaySummaryItem":{"type":"object","properties":{"name":{"type":"string"},"duration":{"type":"number"}},"required":["name","duration"]},"DaySummary":{"type":"object","properties":{"focusSummary":{"type":"array","items":{"$ref":"#/components/schemas/FocusModeDaySummaryItem"}},"daySummaryAVG":{"type":"array","items":{"$ref":"#/components/schemas/ActivityQuantityDaySummaryItem"}},"daySummarySUM":{"type":"array","items":{"$ref":"#/components/schemas/ActivityQuantityDaySummaryItem"}},"daySummaryDuration":{"type":"array","items":{"$ref":"#/components/schemas/ActivityDurationDaySummaryItem"}}},"required":["focusSummary","daySummaryAVG","daySummarySUM","daySummaryDuration"]},"DeleteCompletedActivityNotesDto":{"type":"object","properties":{"completed_activity_ids":{"type":"array","items":{"type":"string","format":"uuid"}}},"required":["completed_activity_ids"]},"CompletedActivitySequenceStats":{"type":"object","properties":{"activity_sequence_id":{"type":"string"},"days_number":{"type":"number"},"timezone":{"type":"string"},"daily_durations_minutes":{"type":"array","items":{"$ref":"#/components/schemas/CompletedActivityStatItem"}},"average_completion_percent":{"type":"object"}},"required":["activity_sequence_id","days_number","daily_durations_minutes","average_completion_percent"]},"GenerateActivityImageUploadUrlDto":{"type":"object","properties":{"file_name":{"type":"string","description":"Original file name of the image","maxLength":255},"content_type":{"type":"string","description":"MIME type of the image","example":"image/png","maxLength":100,"enum":["image/jpeg","image/png","image/gif","image/webp"]}},"required":["file_name","content_type"]},"GenerateActivityImageUploadUrlResponseDto":{"type":"object","properties":{"uploadUrl":{"type":"string","description":"Presigned URL the client should PUT the image to"},"fileKey":{"type":"string","description":"Storage key/path of the uploaded image"}},"required":["uploadUrl","fileKey"]},"ActivityImageReadUrlResponseDto":{"type":"object","properties":{"readUrl":{"type":"string","description":"Presigned GET URL to load the image from R2 until it expires"},"expiresInSeconds":{"type":"number","description":"Seconds until readUrl expires"}},"required":["readUrl","expiresInSeconds"]},"UpsertPushNotificationRegistrationDto":{"type":"object","properties":{"installation_id":{"type":"string"},"device_id":{"type":"string","format":"uuid"},"operating_system":{"enum":["iOS","Android"],"type":"string"},"provider":{"type":"string","enum":["fcm"]},"token":{"type":"string"},"app_version":{"type":"string"}},"required":["installation_id","operating_system","provider","token"]},"PushNotificationRegistration":{"type":"object","properties":{"user_id":{"type":"string"},"device_id":{"type":"string","nullable":true},"installation_id":{"type":"string"},"provider":{"type":"string","enum":["fcm"]},"operating_system":{"type":"string","enum":["MacOS","Windows","Android","iOS","Web","Unknown"]},"token":{"type":"string"},"app_version":{"type":"string","nullable":true},"is_active":{"type":"boolean"},"last_seen_at":{"format":"date-time","type":"string"},"invalidated_at":{"format":"date-time","type":"string","nullable":true},"user":{"$ref":"#/components/schemas/User"},"device":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/Device"}]},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"DeletePushNotificationRegistrationDto":{"type":"object","properties":{"installation_id":{"type":"string"},"provider":{"type":"string","enum":["fcm"]}},"required":["installation_id","provider"]},"CreateDeviceDto":{"type":"object","properties":{"operating_system":{"enum":["MacOS","Windows","Android","iOS","Web","Unknown"],"type":"string"},"metadata":{"type":"object"}},"required":["operating_system"]},"UpdateDeviceDto":{"type":"object","properties":{"operating_system":{"enum":["MacOS","Windows","Android","iOS","Web","Unknown"],"type":"string"},"metadata":{"type":"object"}},"required":["operating_system"]},"AnnouncementEntity":{"type":"object","properties":{"id":{"type":"string"},"type":{"enum":["release","event","survey","maintenance"],"type":"string"},"heading":{"type":"string"},"details":{"type":"string"},"details_url":{"type":"string"},"expiry_date":{"type":"string"},"priority":{"enum":["low","medium","high","critical"],"type":"string"},"operating_system":{"enum":["all","ios","android","mac","windows","web","unknown"],"type":"string"},"created_at":{"format":"date-time","type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","type","heading","details","expiry_date","priority","operating_system","created_at","updated_at"]},"GetAnnouncementsResponseDto":{"type":"object","properties":{"announcements":{"description":"List of active, unread announcements for the user","example":[{"id":"ann_2024_11_maintenance","type":"maintenance","heading":"Scheduled Maintenance","details":"We'll be performing system maintenance on Nov 25th from 2-4 AM UTC.","details_url":"https://example.com/maintenance-info","expiry_date":"2024-11-26","priority":"high","operating_system":"ios","created_at":"2024-11-15T10:00:00.000Z","updated_at":"2024-11-15T10:00:00.000Z"}],"type":"array","items":{"$ref":"#/components/schemas/AnnouncementEntity"}}},"required":["announcements"]},"CreateAnnouncementDto":{"type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9_]+$","maxLength":100,"description":"Optional custom announcement ID","example":"ann_2026_04_webinar_registration"},"type":{"enum":["release","event","survey","maintenance"],"type":"string","example":"event"},"heading":{"type":"string","maxLength":255,"example":"Join our next Focus Bear webinar"},"details":{"type":"string","example":"Learn about new productivity workflows and ask questions live."},"details_url":{"type":"string","format":"uri","maxLength":2048,"example":"https://example.com/webinar-signup"},"expiry_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","example":"2026-04-30","description":"Calendar date after which the announcement should no longer be shown"},"operating_system":{"enum":["all","ios","android","mac","windows","web","unknown"],"type":"string","example":"all"},"priority":{"enum":["low","medium","high","critical"],"type":"string","default":"medium","example":"high"}},"required":["type","heading","details","expiry_date","operating_system"]},"PaginationMetaDto":{"type":"object","properties":{"page":{"type":"number"},"take":{"type":"number"},"order":{"enum":["ASC","DESC"],"type":"string"},"itemCount":{"type":"number"},"pageCount":{"type":"number"},"hasPreviousPage":{"type":"boolean"},"hasNextPage":{"type":"boolean"}},"required":["page","take","order","itemCount","pageCount","hasPreviousPage","hasNextPage"]},"ListAnnouncementsResponseDto":{"type":"object","properties":{"data":{"description":"Announcements for the requested page","type":"array","items":{"$ref":"#/components/schemas/AnnouncementEntity"}},"meta":{"$ref":"#/components/schemas/PaginationMetaDto"}},"required":["data","meta"]},"AnnouncementViewStatsResponseDto":{"type":"object","properties":{"announcement_id":{"type":"string","description":"The announcement these stats belong to","example":"ann_2026_06_quarterly_webinar"},"viewed":{"type":"number","description":"Number of users who viewed the announcement"},"dismissed":{"type":"number","description":"Number of users who dismissed the announcement"},"total":{"type":"number","description":"Total users who have seen the announcement (viewed + dismissed)"}},"required":["announcement_id","viewed","dismissed","total"]},"UpdateAnnouncementDto":{"type":"object","properties":{"type":{"enum":["release","event","survey","maintenance"],"type":"string","example":"event"},"heading":{"type":"string","maxLength":255,"example":"Join our next Focus Bear webinar"},"details":{"type":"string","example":"Learn about new productivity workflows and ask questions live."},"details_url":{"type":"string","format":"uri","maxLength":2048,"example":"https://example.com/webinar-signup"},"expiry_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","example":"2026-04-30","description":"Calendar date after which the announcement should no longer be shown"},"operating_system":{"enum":["all","ios","android","mac","windows","web","unknown"],"type":"string","example":"all"},"priority":{"enum":["low","medium","high","critical"],"type":"string","default":"medium","example":"high"}}},"ViewAnnouncementDto":{"type":"object","properties":{"action":{"enum":["viewed","dismissed"],"type":"string","description":"Action type for the announcement view","example":"viewed","default":"viewed"},"source":{"type":"string","description":"Source or context where the announcement was viewed","example":"mobile_app"},"viewed_at":{"format":"date-time","type":"string","description":"Timestamp when the announcement was viewed","example":"2025-12-03T10:30:00Z"}}},"CreateStripeCheckoutSessionDto":{"type":"object","properties":{"price_id":{"type":"string"},"team_id":{"type":"string","format":"uuid"},"team_size":{"type":"number","minimum":1},"team_name":{"type":"string"},"is_school":{"type":"boolean"}},"required":["price_id"]},"CancelSubscriptionSessionDto":{"type":"object","properties":{"cancel_subscription_reason":{"type":"string","minLength":10},"entitlement_id":{"type":"string"}},"required":["cancel_subscription_reason","entitlement_id"]},"BulkDeleteDto":{"type":"object","properties":{"team_id":{"type":"string"},"member_ids":{"type":"array","items":{"type":"string"}},"emails":{"type":"array","items":{"type":"string","format":"email"}}},"required":["team_id"]},"RemoveTeamMemberDto":{"type":"object","properties":{"email":{"type":"string","format":"email"},"member_id":{"type":"string","format":"uuid"},"team_id":{"type":"string","format":"uuid"}},"required":["team_id"]},"InviteTeamMemberDto":{"type":"object","properties":{"email":{"type":"string","format":"email"},"team_id":{"type":"string","format":"uuid"},"first_name":{"type":"string"},"last_name":{"type":"string"},"member_expiry_date":{"format":"date-time","type":"string"},"is_admin":{"type":"boolean"},"role":{"type":"string","enum":["admin","teacher","member"]},"user_id":{"type":"string","format":"uuid"}},"required":["team_id","is_admin"]},"AcceptInvitationDto":{"type":"object","properties":{"token":{"type":"string"}},"required":["token"]},"JoinTeamDto":{"type":"object","properties":{"join_code":{"type":"string"}},"required":["join_code"]},"CreateJoinCodeDto":{"type":"object","properties":{"team_id":{"type":"string","format":"uuid"},"max_redemptions":{"type":"number","minimum":1},"expires_at":{"type":"string"}},"required":["team_id"]},"CreateBatchJoinCodesDto":{"type":"object","properties":{"count":{"type":"number","minimum":1,"maximum":100},"team_id":{"type":"string","format":"uuid"},"expires_at":{"type":"string"}},"required":["count","team_id"]},"AddTeamMemberDto":{"type":"object","properties":{"member_id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"team_id":{"type":"string","format":"uuid"}},"required":["team_id"]},"SetPendingMemberRoleDto":{"type":"object","properties":{"team_id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"role":{"type":"string","enum":["admin","teacher","member"]}},"required":["team_id","email","role"]},"SetSchoolMemberRoleDto":{"type":"object","properties":{"team_id":{"type":"string","format":"uuid"},"member_id":{"type":"string","format":"uuid"},"role":{"type":"string","enum":["admin","teacher","member"]}},"required":["team_id","member_id","role"]},"GetTeamMembersDetailsDto":{"type":"object","properties":{"id":{"type":"string","example":"550e8400-e29b-41d4-a716-446655440001"},"email":{"type":"string","example":"john.doe@example.com"},"last_active_date":{"format":"date-time","type":"string","nullable":true,"example":"2024-01-15T10:30:00.000Z","description":"Latest completed focus mode or routine; null when the member has never been active"},"first_name":{"type":"string","nullable":true,"example":"John"},"last_name":{"type":"string","nullable":true,"example":"Doe"},"member_expiry_date":{"format":"date-time","type":"string","nullable":true,"example":"2024-12-31T23:59:59.999Z"},"created_at":{"type":"string","example":"2024-01-10T09:00:00.000Z"},"morning_routines_streak":{"type":"number","example":5},"evening_routines_streak":{"type":"number","example":3},"focus_modes_streak":{"type":"number","example":12},"morning_percent_number_day_of_stats_completed":{"type":"number","example":85.5},"micro_percent_number_day_of_stats_completed":{"type":"number","example":92.3},"evening_percent_number_day_of_stats_completed":{"type":"number","example":78.9},"focus_modes_percent_number_day_of_stats_completed":{"type":"number","example":67.2},"total_hours_in_focus_sessions":{"type":"number","example":10.5},"morning_number_days_completed":{"type":"number","example":35},"morning_num_days_of_stats":{"type":"number","example":37},"evening_number_days_completed":{"type":"number","example":33},"evening_num_days_of_stats":{"type":"number","example":37},"micro_breaks_number_days_completed":{"type":"number","example":40},"micro_breaks_num_days_of_stats":{"type":"number","example":45},"focus_modes_number_days_completed":{"type":"number","example":55},"focus_modes_num_days_of_stats":{"type":"number","example":60},"num_days_of_stats":{"type":"number","example":90},"number_days_completed":{"type":"number","example":80},"invitation_status":{"enum":["failed","pending","accepted","declined","expired"],"type":"string","example":"pending"},"invited_role":{"nullable":true,"enum":["admin","teacher","member"],"type":"string","description":"Requested role for an invitation that has not yet been accepted"},"invitation_sent_at":{"format":"date-time","type":"string","nullable":true,"example":"2024-01-15T10:30:00.000Z"},"invitation_send_count":{"type":"number","example":2},"invitation_responded_at":{"format":"date-time","type":"string","nullable":true,"example":"2024-01-16T14:45:00.000Z"},"total_focused_hours":{"type":"number","description":"Total focused hours worked by the intern","example":5.5}},"required":["id","email","last_active_date","first_name","last_name","member_expiry_date","created_at","morning_routines_streak","evening_routines_streak","focus_modes_streak","morning_percent_number_day_of_stats_completed","micro_percent_number_day_of_stats_completed","evening_percent_number_day_of_stats_completed","focus_modes_percent_number_day_of_stats_completed","total_hours_in_focus_sessions","morning_number_days_completed","morning_num_days_of_stats","evening_number_days_completed","evening_num_days_of_stats","micro_breaks_number_days_completed","micro_breaks_num_days_of_stats","focus_modes_number_days_completed","focus_modes_num_days_of_stats","num_days_of_stats","number_days_completed","invitation_status","invitation_sent_at","invitation_send_count","invitation_responded_at","total_focused_hours"]},"GetAllTeamMembersResponseDto":{"type":"object","properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/GetTeamMembersDetailsDto"}},"admins":{"type":"array","items":{"type":"string"}},"teachers":{"description":"User ids with a school-level teacher role on this team","type":"array","items":{"type":"string"}},"total_count":{"type":"number","example":25},"team_id":{"type":"string","example":"550e8400-e29b-41d4-a716-446655440000"}},"required":["members","admins","teachers","total_count","team_id"]},"GetStaffUsageResponseDto":{"type":"object","properties":{"team_id":{"type":"string"},"range":{"type":"object","properties":{"from":{"format":"date-time","type":"string"},"to":{"format":"date-time","type":"string"},"days":{"type":"number"}},"required":["from","to","days"]},"summary":{"type":"object"},"staff":{"type":"array","items":{"type":"object"}}},"required":["team_id","range","summary","staff"]},"UpdateTeamNameDto":{"type":"object","properties":{"name":{"type":"string"},"team_id":{"type":"string","format":"uuid"}},"required":["name","team_id"]},"UpdateClassSessionWindowDto":{"type":"object","properties":{"team_id":{"type":"string","format":"uuid"},"window_start":{"type":"string"},"window_end":{"type":"string"}},"required":["team_id","window_start","window_end"]},"UpdateMemberExpiryDateDto":{"type":"object","properties":{"team_id":{"type":"string","format":"uuid"},"member_id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"expiry_date":{"format":"date-time","type":"string"}},"required":["team_id","expiry_date"]},"AddTeamManuallyDto":{"type":"object","properties":{"user_id":{"type":"string","format":"uuid"},"team_id":{"type":"string","format":"uuid"},"role":{"type":"string","enum":["admin","teacher","member"]}},"required":["user_id","team_id"]},"MemberDeviceDto":{"type":"object","properties":{"id":{"type":"string","example":"9b7c6f2d-1234-4e5f-89ab-0123456789cd","format":"uuid"},"operating_system":{"type":"string","example":"MacOS","description":"Operating system label"},"app_version":{"type":"string","nullable":true,"example":"1.2.3"},"is_leader":{"type":"boolean","example":true},"created_at":{"type":"string","example":"2024-01-10T09:00:00.000Z","format":"date-time"},"updated_at":{"type":"string","example":"2024-04-10T09:00:00.000Z","format":"date-time"}},"required":["id","operating_system","is_leader","created_at","updated_at"]},"GetMemberInsightsResponseDto":{"type":"object","properties":{"member":{"$ref":"#/components/schemas/GetTeamMembersDetailsDto"},"devices":{"type":"array","items":{"$ref":"#/components/schemas/MemberDeviceDto"}}},"required":["member","devices"]},"TeamAdminUsageDto":{"type":"object","properties":{"id":{"type":"string","example":"550e8400-e29b-41d4-a716-446655440001"},"last_active_date":{"format":"date-time","type":"string","nullable":true,"example":"2024-01-15T10:30:00.000Z","description":"Latest completed focus mode or routine; null when the member has never been active"},"morning_routines_streak":{"type":"number","example":5},"evening_routines_streak":{"type":"number","example":3},"focus_modes_streak":{"type":"number","example":12},"morning_percent_number_day_of_stats_completed":{"type":"number","example":85.5},"micro_percent_number_day_of_stats_completed":{"type":"number","example":92.3},"evening_percent_number_day_of_stats_completed":{"type":"number","example":78.9},"focus_modes_percent_number_day_of_stats_completed":{"type":"number","example":67.2},"total_hours_in_focus_sessions":{"type":"number","example":10.5},"morning_number_days_completed":{"type":"number","example":35},"morning_num_days_of_stats":{"type":"number","example":37},"evening_number_days_completed":{"type":"number","example":33},"evening_num_days_of_stats":{"type":"number","example":37},"micro_breaks_number_days_completed":{"type":"number","example":40},"micro_breaks_num_days_of_stats":{"type":"number","example":45},"focus_modes_number_days_completed":{"type":"number","example":55},"focus_modes_num_days_of_stats":{"type":"number","example":60},"num_days_of_stats":{"type":"number","example":90},"number_days_completed":{"type":"number","example":80},"total_focused_hours":{"type":"number","description":"Total focused hours worked by the intern","example":5.5}},"required":["id","last_active_date","morning_routines_streak","evening_routines_streak","focus_modes_streak","morning_percent_number_day_of_stats_completed","micro_percent_number_day_of_stats_completed","evening_percent_number_day_of_stats_completed","focus_modes_percent_number_day_of_stats_completed","total_hours_in_focus_sessions","morning_number_days_completed","morning_num_days_of_stats","evening_number_days_completed","evening_num_days_of_stats","micro_breaks_number_days_completed","micro_breaks_num_days_of_stats","focus_modes_number_days_completed","focus_modes_num_days_of_stats","num_days_of_stats","number_days_completed","total_focused_hours"]},"ServiceAccountTeamMembersResponseDto":{"type":"object","properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/GetTeamMembersDetailsDto"}},"admins":{"type":"array","items":{"type":"string"}},"teachers":{"description":"User ids with a school-level teacher role on this team","type":"array","items":{"type":"string"}},"total_count":{"type":"number","example":25},"team_id":{"type":"string","example":"550e8400-e29b-41d4-a716-446655440000"},"admin_members":{"description":"Usage for the team's owner and admins who have no membership row, so aren't in `members`. Not counted in `total_count`.","type":"array","items":{"$ref":"#/components/schemas/TeamAdminUsageDto"}}},"required":["members","admins","teachers","total_count","team_id","admin_members"]},"AdminCreateTeamDto":{"type":"object","properties":{"name":{"type":"string","maxLength":255},"owner_email":{"type":"string","description":"Owner is resolved by email against Auth0 + the users table; they must already be signed up.","format":"email"},"payment_type":{"type":"string","enum":["stripe","offline"]},"team_size_limit":{"type":"number","description":"Max member count for OFFLINE teams; omit for unlimited.","minimum":1},"expires_date":{"type":"string","description":"Required: `expires_date` is NOT NULL on teams and drives the owner's entitlement expiry."},"is_school":{"type":"boolean"}},"required":["name","owner_email","expires_date"]},"AdminUpdateTeamDto":{"type":"object","properties":{"name":{"type":"string","maxLength":255},"team_size_limit":{"type":"number","minimum":1},"expires_date":{"type":"string","description":"Changing this also propagates to member/admin/owner entitlement expiries."},"is_school":{"type":"boolean"},"is_active":{"type":"boolean","description":"Only hides the team from lists / marks it inactive. It does NOT revoke member entitlements\nor cancel a Stripe subscription — a full deactivation cascade is out of scope here."},"payment_type":{"type":"string","enum":["stripe","offline"]},"force":{"type":"boolean","description":"Required to change payment_type on a team with a live Stripe subscription."}}},"UpdateActivityTemplateDto":{"type":"object","properties":{"name":{"type":"string"},"is_office_friendly":{"type":"boolean"},"take_notes":{"enum":["NO_NOTE","DURING_ACTIVITY","END_OF_ACTIVITY"],"type":"string"},"priority":{"enum":["STANDARD","HIGH"],"type":"string"},"allowed_focus_mode_id":{"type":"string","format":"uuid"},"video_urls":{"type":"array","items":{"type":"string"}},"include_in_every_break":{"type":"boolean"},"habit_icon":{"type":"string"},"habit_icon_generation_failed":{"type":"boolean"},"log_quantity_question":{"type":"string"},"choice_type":{"enum":["random","normal","competency","check_list"],"type":"string"},"allowed_apps":{"type":"array","items":{"type":"string"}},"allowed_mobile_apps":{"type":"array","items":{"type":"string"}},"allowed_urls":{"type":"array","items":{"type":"string"}},"break_type":{"enum":["micro","pomodoro"],"type":"string"},"linked_project_ids":{"maxItems":10,"type":"array","items":{"type":"string","format":"uuid"}},"tags":{"type":"array","items":{"type":"string"}},"linked_project_id":{"type":"string","format":"uuid","description":"First of linked_project_ids, for older clients"},"log_quantity":{"type":"boolean"},"duration_seconds":{"type":"number"},"completion_requirements":{"type":"string"},"log_summary_type":{"enum":["SUM","AVG"],"type":"string"},"choices":{"minItems":1,"type":"array","items":{"$ref":"#/components/schemas/ActivityChoiceData"}},"days_of_week":{"minItems":1,"items":{"type":"string","enum":["ALL","MON","TUE","WED","THU","FRI","SAT","SUN"]},"default":["ALL"],"type":"array"},"impact_category":{"enum":["hours_of_sleep","energy_level_upon_awakening","mood","perception_of_productivity","minutes_spent_on_distracting_websites","minutes_spent_postponing_app_blocks","minutes_spent_postponing_habits"],"type":"string"},"geofence_id":{"type":"string","nullable":true,"format":"uuid"},"id":{"type":"string","format":"uuid"},"activity_template_id":{"type":"string","format":"uuid"},"is_default":{"type":"boolean"},"run_micro_breaks":{"type":"boolean"},"log_quantity_questions":{"type":"array","items":{"$ref":"#/components/schemas/LogQuantityQuestion"}},"linked_activity_id":{"type":"string","format":"uuid"},"linked_activity_template_id":{"type":"string","format":"uuid"},"check_list":{"type":"array","items":{"type":"string"}},"activity_type":{"type":"string"},"tutorial":{"type":"string","format":"uuid"},"cutoff_time_for_doing_activity":{"type":"string"},"category":{"type":"string"},"text_instructions":{"type":"string"},"image_urls":{"type":"array","items":{"$ref":"#/components/schemas/ActivityImageData"}},"current_competency_level":{"type":"number"},"competency_level":{"type":"number"},"show_saved_distracting_websites":{"type":"boolean"},"pack_id":{"type":"string","format":"uuid"}},"required":["name","id"]},"UpsertHabitPackDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"pack_name":{"type":"string"},"creator_name":{"type":"string"},"pack_type":{"type":"string","enum":["routine","standalone"]},"description":{"type":"string"},"description_video_url":{"type":"string","format":"uri"},"welcome_message":{"type":"string"},"welcome_video_url":{"type":"string","format":"uri"},"marketplace_request":{"type":"string","enum":["requested","unrequested"]},"marketplace_approval_status":{"type":"boolean"},"is_featured":{"type":"boolean"},"featured_for_onboarding":{"type":"boolean"},"language":{"type":"string"},"morning_activities":{"type":"array","items":{"$ref":"#/components/schemas/UpdateActivityTemplateDto"}},"break_activities":{"type":"array","items":{"$ref":"#/components/schemas/UpdateActivityTemplateDto"}},"evening_activities":{"type":"array","items":{"$ref":"#/components/schemas/UpdateActivityTemplateDto"}},"standalone_activities":{"type":"array","items":{"$ref":"#/components/schemas/UpdateActivityTemplateDto"}}}},"ResponseMessage":{"type":"object","properties":{"message":{"type":"string"},"success":{"type":"boolean"},"timestamp":{"format":"date-time","type":"string"},"statusCode":{"type":"number"}},"required":["message","success","timestamp"]},"UserSettingsResponseDto":{"type":"object","properties":{"morning_activities":{"type":"array","items":{"$ref":"#/components/schemas/UpdateActivityDto"}},"evening_activities":{"type":"array","items":{"$ref":"#/components/schemas/UpdateActivityDto"}},"break_activities":{"type":"array","items":{"$ref":"#/components/schemas/UpdateActivityDto"}},"custom_routines":{"type":"array","items":{"$ref":"#/components/schemas/UpdateCustomRoutineDto"}},"startup_time":{"type":"string"},"shutdown_time":{"type":"string"},"cutoff_time_for_non_high_priority_activities":{"type":"string"},"break_after_minutes":{"type":"number","minimum":1},"has_edited_settings":{"type":"boolean"}}},"InstalledStandalonePackResponse":{"type":"object","properties":{"id":{"type":"string"},"pack_name":{"type":"string"},"pack_id":{"type":"string"},"standalone_activities":{"type":"array","items":{"$ref":"#/components/schemas/UpdateActivityDto"}}},"required":["id","pack_name","pack_id","standalone_activities"]},"CreateFocusModeTagDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"text":{"type":"string"}},"required":["id","text"]},"UpsertFocusModeTemplateDto":{"type":"object","properties":{"allowed_urls":{"type":"array","items":{"type":"string"}},"allowed_apps":{"type":"array","items":{"type":"string"}},"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"author_name":{"type":"string"},"tags":{"type":"array","items":{"$ref":"#/components/schemas/CreateFocusModeTagDto"}},"description":{"type":"string"},"description_video_url":{"type":"string","format":"uri"},"welcome_message":{"type":"string"},"welcome_video_url":{"type":"string","format":"uri"},"marketplace_request":{"type":"string","enum":["requested","unrequested"]},"marketplace_approval_status":{"type":"boolean"},"is_featured":{"type":"boolean"},"featured_for_onboarding":{"type":"boolean"},"language":{"type":"string"}},"required":["id","description","welcome_message"]},"FocusModeCategoryDto":{"type":"object","properties":{"entry":{"type":"string","maxLength":512,"description":"The blocked URL, keyword or app path this category applies to"},"category":{"type":"string","maxLength":64,"description":"Client taxonomy id, e.g. social_media, news, video"}},"required":["entry","category"]},"WindowsAppIdentityDto":{"type":"object","properties":{"exe":{"type":"string","example":"steam.exe"},"exes":{"maxItems":20,"example":["OUTLOOK.EXE","olk.exe"],"description":"Every executable the app ships as, exe included, when it has more than one","type":"array","items":{"type":"string"}},"publisher":{"type":"string","example":"Valve Corp.","description":"Authenticode signer organisation"}},"required":["exe"]},"AppIdentityDto":{"type":"object","properties":{"entry":{"type":"string","description":"The allowed_apps value this identity describes, verbatim"},"name":{"type":"string"},"common_app_id":{"type":"string","description":"Id of the GET /common-apps entry this app was picked from"},"mac_bundle_id":{"type":"string","example":"com.valvesoftware.steam"},"windows_identity":{"$ref":"#/components/schemas/WindowsAppIdentityDto"}},"required":["entry"]},"CreateSharedFocusModeDto":{"type":"object","properties":{"allowed_urls":{"type":"array","items":{"type":"string"}},"allowed_apps":{"type":"array","items":{"type":"string"}},"is_ai_enabled":{"type":"boolean","description":"Enable or disable AI-powered URL and app evaluation for this focus mode","default":true},"categories":{"description":"Category assigned to each blocked URL/app entry in this block list","type":"array","items":{"$ref":"#/components/schemas/FocusModeCategoryDto"}},"app_identities":{"description":"Platform identities for this mode's app entries, keyed by `entry`. Same omit/replace rules as\n`categories`: omitted keeps the stored ones, `[]` clears what the client supplied. Either way\nthe server fills in identities for common apps from the catalog, so a client that only knows\nnames never has to send this.","type":"array","items":{"$ref":"#/components/schemas/AppIdentityDto"}},"team_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"id":{"type":"string","format":"uuid"},"metadata":{"type":"object","description":"Older macOS builds copy every top-level key they receive back into `metadata` on save, so once\na newer client stores `categories` or `app_identities` they would echo a (possibly stale) copy\nhere. The columns are the only home for those; drop the copies so no client can persist them."},"tags":{"type":"array","items":{"$ref":"#/components/schemas/CreateFocusModeTagDto"}}},"required":["team_id","name"]},"UpdateFocusModeDto":{"type":"object","properties":{"allowed_urls":{"type":"array","items":{"type":"string"}},"allowed_apps":{"type":"array","items":{"type":"string"}},"is_ai_enabled":{"type":"boolean","description":"Enable or disable AI-powered URL and app evaluation for this focus mode","default":true},"categories":{"description":"Category assigned to each blocked URL/app entry in this block list","type":"array","items":{"$ref":"#/components/schemas/FocusModeCategoryDto"}},"app_identities":{"description":"Platform identities for this mode's app entries, keyed by `entry`. Same omit/replace rules as\n`categories`: omitted keeps the stored ones, `[]` clears what the client supplied. Either way\nthe server fills in identities for common apps from the catalog, so a client that only knows\nnames never has to send this.","type":"array","items":{"$ref":"#/components/schemas/AppIdentityDto"}},"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"metadata":{"type":"object","description":"Older macOS builds copy every top-level key they receive back into `metadata` on save, so once\na newer client stores `categories` or `app_identities` they would echo a (possibly stale) copy\nhere. The columns are the only home for those; drop the copies so no client can persist them."},"tags":{"type":"array","items":{"$ref":"#/components/schemas/CreateFocusModeTagDto"}}}},"CreateFocusModeDto":{"type":"object","properties":{"allowed_urls":{"type":"array","items":{"type":"string"}},"allowed_apps":{"type":"array","items":{"type":"string"}},"is_ai_enabled":{"type":"boolean","description":"Enable or disable AI-powered URL and app evaluation for this focus mode","default":true},"categories":{"description":"Category assigned to each blocked URL/app entry in this block list","type":"array","items":{"$ref":"#/components/schemas/FocusModeCategoryDto"}},"app_identities":{"description":"Platform identities for this mode's app entries, keyed by `entry`. Same omit/replace rules as\n`categories`: omitted keeps the stored ones, `[]` clears what the client supplied. Either way\nthe server fills in identities for common apps from the catalog, so a client that only knows\nnames never has to send this.","type":"array","items":{"$ref":"#/components/schemas/AppIdentityDto"}},"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"metadata":{"type":"object","description":"Older macOS builds copy every top-level key they receive back into `metadata` on save, so once\na newer client stores `categories` or `app_identities` they would echo a (possibly stale) copy\nhere. The columns are the only home for those; drop the copies so no client can persist them."},"tags":{"type":"array","items":{"$ref":"#/components/schemas/CreateFocusModeTagDto"}}}},"AttachToDoDto":{"type":"object","properties":{"to_do_id":{"type":"string","format":"uuid","description":"ID of the to-do to attach to the active focus session."}},"required":["to_do_id"]},"StartFocusModeDto":{"type":"object","properties":{"intention":{"type":"string","maxLength":255},"finish_time":{"format":"date-time","type":"string"},"start_time":{"format":"date-time","type":"string"},"to_do_ids":{"type":"array","items":{"type":"string","format":"uuid"}},"to_dos":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"}},"required":[]}},"block_level":{"type":"string","enum":["gentle","strict","super-strict"]}},"required":["finish_time","start_time"]},"ToDoTimeLogDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"duration":{"type":"number"},"status":{"type":"string"},"is_billable":{"type":"boolean"},"note":{"type":"string"}},"required":["id","duration","status"]},"FinishFocusModeDto":{"type":"object","properties":{"achievements":{"type":"string","maxLength":255},"distractions":{"type":"string","maxLength":255},"finish_time":{"format":"date-time","type":"string"},"focus_duration_seconds":{"type":"number"},"tags":{"type":"array","items":{"$ref":"#/components/schemas/CreateFocusModeTagDto"}},"to_dos":{"type":"array","items":{"$ref":"#/components/schemas/ToDoTimeLogDto"}},"metadata":{"type":"object"}},"required":["finish_time"]},"UpdateScheduledFinishDto":{"type":"object","properties":{"scheduled_finish_time":{"format":"date-time","type":"string"}},"required":["scheduled_finish_time"]},"UpsertBlockingScheduleDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"start_time":{"type":"string"},"end_time":{"type":"string"},"days_of_week":{"description":"Day numbers using the JS Date.getDay() convention: 0 = Sunday ... 6 = Saturday. Out-of-range or duplicate values are normalised server-side and \"ALL\" expands to all seven days. See days_of_week_text for the string-enum form.","type":"array","items":{"type":"number"}},"focus_mode_id":{"type":"string","format":"uuid"},"pause_friction":{"enum":["none","timer","100_random_chars","password"],"type":"string"},"block_level":{"enum":["gentle","strict","super-strict"],"type":"string"},"is_ai_blocking_enabled":{"type":"boolean"},"emoji":{"type":"string","nullable":true,"maxLength":32,"description":"Optional per-schedule emoji/icon, max 32 chars."},"metadata":{"type":"object","additionalProperties":true}},"required":["name","start_time","end_time","focus_mode_id"]},"SavedViewDueDateFilterDto":{"type":"object","properties":{"kind":{"enum":["any","preset","custom"],"type":"string","description":"`any` = no due-date filter."},"preset":{"enum":["today","thisWeek","nextWeek","next30Days"],"type":"string","description":"Required when kind is `preset`, rejected otherwise. Relative: evaluated when the view is applied."},"start":{"type":"string","example":"2026-10-04","description":"Only with kind `custom`. Inclusive local calendar day; omit for an open start."},"end":{"type":"string","example":"2026-10-18","description":"Only with kind `custom`. Inclusive local calendar day; omit for an open end."}},"required":["kind"]},"ToDoSavedViewFiltersDto":{"type":"object","properties":{"project_ids":{"uniqueItems":true,"description":"A task matches if it belongs to any of these projects. Empty or absent = all projects.","type":"array","items":{"type":"string","format":"uuid"}},"energy_level":{"enum":["low","full"],"type":"string","description":"`low` = perspiration 0–3, `full` = 4–10."},"due_date":{"$ref":"#/components/schemas/SavedViewDueDateFilterDto"}}},"ToDoSavedViewResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"filters":{"$ref":"#/components/schemas/ToDoSavedViewFiltersDto"},"sort_mode":{"enum":["SMART","CHRONOLOGICAL","DUE_DATE"],"type":"string"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","name","filters","sort_mode","created_at","updated_at"]},"ToDoSavedViewListResponseDto":{"type":"object","properties":{"data":{"description":"Oldest first (created_at ascending).","type":"array","items":{"$ref":"#/components/schemas/ToDoSavedViewResponseDto"}}},"required":["data"]},"CreateToDoSavedViewDto":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"example":"Due for next PhD supervisor meeting","description":"Trimmed. Unique per user, case-insensitively."},"filters":{"$ref":"#/components/schemas/ToDoSavedViewFiltersDto"},"sort_mode":{"enum":["SMART","CHRONOLOGICAL","DUE_DATE"],"type":"string","default":"SMART"}},"required":["name","filters"]},"UpdateToDoSavedViewDto":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"filters":{"$ref":"#/components/schemas/ToDoSavedViewFiltersDto"},"sort_mode":{"enum":["SMART","CHRONOLOGICAL","DUE_DATE"],"type":"string"}}},"CreateToDoDto":{"type":"object","properties":{"eisenhower_quadrant":{"type":"number","minimum":1,"maximum":4},"assignee_id":{"type":"string","nullable":true,"description":"Id of the user to assign this task to, or null to unassign it.","format":"uuid"},"planned_block_key":{"type":"string","nullable":true,"description":"Day Plan: opaque time-box key (`event:` / `deepwork:` / `habit:`).","pattern":"\\S","maxLength":256},"recurrence_rule":{"type":"string","nullable":true,"description":"One unfolded RFC 5545 RRULE content line. Supports DAILY, plain-weekday WEEKLY, constrained MONTHLY, and non-leap-day YEARLY rules, with INTERVAL and either COUNT or a UTC UNTIL. Null stops the todo repeating.","maxLength":2048,"example":"RRULE:FREQ=WEEKLY;INTERVAL=2"},"recurrence_timezone":{"type":"string","description":"IANA timezone the recurrence rule is evaluated in.","maxLength":255,"example":"Australia/Melbourne"},"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"details":{"type":"string"},"due_date":{"format":"date-time","type":"string"},"focus_type":{"type":"string","format":"uuid"},"status":{"type":"string"},"tags":{"type":"array","items":{"$ref":"#/components/schemas/CreateFocusModeTagDto"}},"subtasks":{"type":"array","items":{"$ref":"#/components/schemas/SubtaskDto"}},"objective":{"type":"string"},"duration":{"type":"number"},"icon":{"type":"string"},"perspiration_level":{"type":"number","minimum":1,"maximum":10},"outcome":{"type":"number","minimum":1,"maximum":10},"project_id":{"type":"string","format":"uuid"},"synced_project_id":{"type":"string","format":"uuid"},"external_status_id":{"type":"string"},"assigned_mcp_token_id":{"type":"string","format":"uuid"},"custom_status_id":{"type":"string"},"planned_date":{"type":"string","nullable":true,"description":"Day Plan: the day this todo is planned for (yyyy-MM-dd). Pass `null` to\nremove the todo from the Day Plan (the todo itself is not deleted)."},"planned_order":{"type":"number","nullable":true,"description":"Day Plan: manual ordering within the planned day.","minimum":0}},"required":["eisenhower_quadrant","title"]},"BulkUpdateToDoItemDto":{"type":"object","properties":{"eisenhower_quadrant":{"type":"number","minimum":1,"maximum":4},"assignee_id":{"type":"string","nullable":true,"description":"Id of the user to assign this task to, or null to unassign it.","format":"uuid"},"planned_block_key":{"type":"string","nullable":true,"description":"Day Plan: opaque time-box key (`event:` / `deepwork:` / `habit:`).","pattern":"\\S","maxLength":256},"recurrence_rule":{"type":"string","nullable":true,"description":"One unfolded RFC 5545 RRULE content line. Supports DAILY, plain-weekday WEEKLY, constrained MONTHLY, and non-leap-day YEARLY rules, with INTERVAL and either COUNT or a UTC UNTIL. Null stops the todo repeating.","maxLength":2048,"example":"RRULE:FREQ=WEEKLY;INTERVAL=2"},"recurrence_timezone":{"type":"string","description":"IANA timezone the recurrence rule is evaluated in.","maxLength":255,"example":"Australia/Melbourne"},"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"details":{"type":"string"},"due_date":{"format":"date-time","type":"string"},"focus_type":{"type":"string","format":"uuid"},"status":{"type":"string"},"tags":{"type":"array","items":{"$ref":"#/components/schemas/CreateFocusModeTagDto"}},"subtasks":{"type":"array","items":{"$ref":"#/components/schemas/SubtaskDto"}},"objective":{"type":"string"},"duration":{"type":"number"},"icon":{"type":"string"},"perspiration_level":{"type":"number","minimum":1,"maximum":10},"outcome":{"type":"number","minimum":1,"maximum":10},"project_id":{"type":"string","format":"uuid"},"synced_project_id":{"type":"string","format":"uuid"},"external_status_id":{"type":"string"},"assigned_mcp_token_id":{"type":"string","format":"uuid"},"custom_status_id":{"type":"string"},"planned_date":{"type":"string","nullable":true,"description":"Day Plan: the day this todo is planned for (yyyy-MM-dd). Pass `null` to\nremove the todo from the Day Plan (the todo itself is not deleted)."},"planned_order":{"type":"number","nullable":true,"description":"Day Plan: manual ordering within the planned day.","minimum":0}},"required":["eisenhower_quadrant","id","title"]},"BulkUpdateToDosDto":{"type":"object","properties":{"todos":{"minItems":1,"uniqueItems":true,"maxItems":50,"type":"array","items":{"$ref":"#/components/schemas/BulkUpdateToDoItemDto"}}},"required":["todos"]},"BulkUpdateToDoResult":{"type":"object","properties":{"id":{"type":"string"},"success":{"type":"boolean"},"todo":{"type":"object","description":"The saved todo, exactly as `PUT /to-do` returns it. Only on success."},"status_code":{"type":"number","description":"The HTTP status the same body would have got from `PUT /to-do`. Only on failure."},"message":{"type":"string"}},"required":["id","success"]},"BulkUpdateToDosResponse":{"type":"object","properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/BulkUpdateToDoResult"}}},"required":["results"]},"UpdateToDoPlanningDto":{"type":"object","properties":{"planned_date":{"type":"string","nullable":true,"description":"The day this todo is planned for (yyyy-MM-dd). Passing `null` removes the todo\nfrom the Day Plan and clears the whole plan slot: `planned_block_key` and\n`planned_order` are also nulled in the same write (the todo itself is not deleted).\n\nUnplanning and time-boxing are contradictory, so `planned_date: null` may only\nbe combined with explicit `null` clears of the other fields. A non-null\n`planned_block_key` or `planned_order` in the same payload is rejected (400).","example":"2026-06-20"},"planned_block_key":{"type":"string","nullable":true,"pattern":"\\S","maxLength":256,"example":"event:calendar-event-id"},"planned_order":{"type":"number","nullable":true,"minimum":0,"example":0}}},"TaskCommentUserDto":{"type":"object","properties":{"id":{"type":"string"},"username":{"type":"string"}},"required":["id"]},"TaskCommentReactionResponseDto":{"type":"object","properties":{"id":{"type":"string"},"comment_id":{"type":"string"},"user_id":{"type":"string"},"emoji":{"type":"string","example":"👍"},"user":{"$ref":"#/components/schemas/TaskCommentUserDto"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","comment_id","user_id","emoji","created_at","updated_at"]},"TaskCommentWithReactionsDto":{"type":"object","properties":{"id":{"type":"string"},"task_id":{"type":"string"},"user_id":{"type":"string"},"content":{"type":"string"},"user":{"$ref":"#/components/schemas/TaskCommentUserDto"},"created_at":{"type":"string"},"updated_at":{"type":"string"},"reactions":{"type":"array","items":{"$ref":"#/components/schemas/TaskCommentReactionResponseDto"}}},"required":["id","task_id","user_id","content","created_at","updated_at"]},"TaskReactionResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Reaction ID"},"task_id":{"type":"string","description":"Task ID"},"user_id":{"type":"string","description":"User ID"},"emoji":{"type":"string","description":"Emoji reaction"},"created_at":{"type":"string","description":"Creation timestamp"},"updated_at":{"type":"string","description":"Last update timestamp"}},"required":["id","task_id","user_id","emoji","created_at","updated_at"]},"ToDoResponse":{"type":"object","properties":{"assignee_id":{"type":"string","nullable":true,"description":"Id of the user this task is assigned to, or null when it is unassigned."},"external_task_status":{"type":"string","description":"Cached external task status label used by task list endpoints.","example":"In Progress"},"external_statuses":{"type":"object","description":"Available external statuses on the linked project, when the todo is synced."},"top_score":{"type":"number","nullable":true,"description":"@brief Materialised priority score, written by application code.\n@details Mirrors the SQL expression that previously computed the\n         \"top score\" inside `ORDER BY` on every page load. Persisting\n         the value allows the planner to satisfy `ORDER BY ... LIMIT`\n         with the `(user_id, top_score DESC)` index instead of a\n         parallel sequential scan + in-memory sort. The score depends\n         on the user's local \"today\", so it is refreshed daily by the\n         off-thread top-score worker as well as on every write that\n         touches `due_date`, `outcome`, or `perspiration_level`.\n\n         PostgreSQL's `numeric` type round-trips through node-postgres\n         as a string; the transformer below converts it to `number`\n         on read so the application can treat it as a plain numeric\n         value."},"comments":{"type":"array","items":{"$ref":"#/components/schemas/TaskCommentWithReactionsDto"}},"reactions":{"type":"array","items":{"$ref":"#/components/schemas/TaskReactionResponseDto"}},"assigned_mcp_token_id":{"type":"string","description":"ID of the MCP agent token assigned to this task"},"attachment_count":{"type":"number","description":"Number of files attached to this task. Present on list reads (GET /to-do, Day Plan, recent).","example":0},"user_id":{"type":"string"},"focus_type":{"type":"string"},"synced_project_id":{"type":"string"},"project_id":{"type":"string"},"custom_status_id":{"type":"string"},"title":{"type":"string"},"details":{"type":"string"},"objective":{"type":"string"},"external_task_id":{"type":"string"},"external_task_metadata":{"type":"object"},"subtasks":{"type":"array","items":{"$ref":"#/components/schemas/SubtaskDto"}},"due_date":{"format":"date-time","type":"string","nullable":true},"eisenhower_quadrant":{"type":"number"},"outcome":{"type":"number"},"perspiration_level":{"type":"number"},"status":{"type":"string"},"duration":{"type":"number"},"icon":{"type":"string"},"current_external_status_id":{"type":"string","nullable":true,"description":"@brief Materialised external status identifier from the linked platform.\n@details Populated by the integration sync worker so list-view rendering\n         no longer needs to decrypt/parse the `external_task_metadata`\n         JSONB on the request path."},"current_external_status_label":{"type":"string","nullable":true,"description":"@brief Materialised external status label from the linked platform.\n@details See `current_external_status_id`. The label is exposed via the\n         API as the human-readable status text."},"planned_date":{"type":"string","nullable":true,"description":"@brief Day Plan pointer: the day this todo is planned for (YYYY-MM-DD).\n@details NULL means the todo is not in any Day Plan. A planned task is a\n         pointer into `to_do` by date, not a copy; the Day Plan panel reads\n         todos by `planned_date` and writes planning changes through\n         `PATCH /to-do/:id`."},"planned_block_key":{"type":"string","nullable":true,"description":"@brief Day Plan time-box assignment within the planned day.\n@details Opaque, never parsed by the backend. One of `event:<id>`,\n         `deepwork:<unix-epoch>`, `habit:<title>`, or NULL when planned but\n         not yet time-boxed onto a block. Encrypted at rest because the\n         `habit:<title>` form can embed a habit name, matching `title`/\n         `details`. The column stays unbounded `varchar` (ciphertext is\n         longer than plaintext); the DTO caps plaintext input at 256 chars."},"planned_order":{"type":"number","nullable":true,"description":"@brief Manual ordering within the planned day (drag-to-reorder)."},"recurrence_rule":{"type":"string","nullable":true,"description":"@brief Recurrence: canonical RFC 5545 RRULE content line, e.g.\n       `RRULE:FREQ=WEEKLY;INTERVAL=2` for a fortnightly chore.\n@details NULL means the todo is a one-off and takes no recurrence code path,\n         which is every todo that existed before this column. Set together\n         with the other three `recurrence_*` columns (a DB CHECK enforces\n         all-or-none). Validated and canonicalised through the same RFC 5545\n         subset the Day Plan's event series use."},"recurrence_timezone":{"type":"string","nullable":true,"description":"@brief Recurrence: IANA zone the rule is evaluated in (keeps the local time of day across DST)."},"recurrence_dtstart":{"format":"date-time","type":"string","nullable":true,"description":"@brief Recurrence: the series DTSTART — the first occurrence's due date.\n@details Copied unchanged onto every occurrence so the next due date is\n         always computed from the series anchor. Completing an occurrence\n         late therefore does not shift the schedule."},"recurrence_series_id":{"type":"string","nullable":true,"description":"@brief Recurrence: groups every occurrence of one repeating todo.\n@details Equal to the first occurrence's own id. Lets history be read per\n         series and `DELETE /to-do?scope=series` remove the whole thing."},"user":{"$ref":"#/components/schemas/User"},"synced_project":{"$ref":"#/components/schemas/SyncedProject"},"project":{"$ref":"#/components/schemas/Project"},"assignee":{"$ref":"#/components/schemas/User"},"focus_mode":{"$ref":"#/components/schemas/FocusMode"},"task_time_logs":{"type":"array","items":{"$ref":"#/components/schemas/TaskTimeLog"}},"tags":{"type":"array","items":{"$ref":"#/components/schemas/FocusModeTag"}},"completedFocusBlocks":{"type":"array","items":{"$ref":"#/components/schemas/CompletedFocusBlock"}},"attachments":{"type":"array","items":{"$ref":"#/components/schemas/TaskAttachment"}},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["title","details","objective","eisenhower_quadrant","outcome","perspiration_level","status","completedFocusBlocks"]},"GenerateSubtasksDto":{"type":"object","properties":{"task":{"type":"string"},"language":{"type":"string"},"existing_subtasks":{"type":"array","items":{"$ref":"#/components/schemas/SubtaskDto"}}},"required":["task","language"]},"SubtasksDto":{"type":"object","properties":{"task":{"type":"string"},"subtasks":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"is_completed":{"type":"boolean"},"estimated_minutes":{"type":"number"}},"required":["name","is_completed"]}}},"required":["task","subtasks"]},"AdminTaskResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the task"},"title":{"type":"string","description":"Task title"},"status":{"type":"string","description":"Current status of the task"},"due_date":{"format":"date-time","type":"string","nullable":true,"description":"Due date for the task"},"eisenhower_quadrant":{"type":"number","nullable":true,"description":"Eisenhower matrix quadrant (1-4)"},"duration":{"type":"number","nullable":true,"description":"Duration in seconds"},"outcome":{"type":"number","nullable":true,"description":"Outcome/importance level for TOP priority (1-9)"},"perspiration_level":{"type":"number","nullable":true,"description":"Perspiration/effort level for TOP priority (1-10)"},"created_at":{"type":"string","description":"When the task was created"},"updated_at":{"type":"string","description":"When the task was last updated"}},"required":["id","title","status","due_date","eisenhower_quadrant","duration","outcome","perspiration_level","created_at","updated_at"]},"ConvertBrainDump":{"type":"object","properties":{"contents":{"type":"string","maxLength":1000}},"required":["contents"]},"BraindumpTaskDto":{"type":"object","properties":{"task_name":{"type":"string"},"estimated_time":{"type":"number"},"subtasks":{"type":"array","items":{"type":"string"}},"outcome":{"type":"number","minimum":1,"maximum":10},"perspiration_level":{"type":"number","minimum":1,"maximum":10},"due_date":{"type":"string","nullable":true},"top_score":{"type":"number"}},"required":["task_name","estimated_time","subtasks"]},"TodoImageUploadedDto":{"type":"object","properties":{"imageKey":{"type":"string"}},"required":["imageKey"]},"GenerateUploadAudioUrlDto":{"type":"object","properties":{"fileExtension":{"type":"string","enum":["mp3","m4a","wav","mp4"]}},"required":["fileExtension"]},"TodoAudioUploadedDto":{"type":"object","properties":{"audioKey":{"type":"string"}},"required":["audioKey"]},"CreateTaskCommentDto":{"type":"object","properties":{"content":{"type":"string","description":"Comment content","maxLength":10000}},"required":["content"]},"TaskCommentResponseDto":{"type":"object","properties":{"id":{"type":"string"},"task_id":{"type":"string"},"user_id":{"type":"string"},"content":{"type":"string"},"user":{"$ref":"#/components/schemas/TaskCommentUserDto"},"reactions":{"type":"array","items":{"$ref":"#/components/schemas/TaskCommentReactionResponseDto"}},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","task_id","user_id","content","reactions","created_at","updated_at"]},"UpdateTaskCommentDto":{"type":"object","properties":{"content":{"type":"string","description":"Comment content","maxLength":10000}},"required":["content"]},"CreateTaskCommentReactionDto":{"type":"object","properties":{"emoji":{"type":"string","maxLength":10,"description":"Emoji for the reaction (single emoji character)","example":"👍"}},"required":["emoji"]},"GenerateUploadAttachmentUrlDto":{"type":"object","properties":{"file_name":{"type":"string","description":"Original file name","maxLength":500},"content_type":{"type":"string","description":"MIME type of the file","maxLength":100}},"required":["file_name","content_type"]},"CreateTaskAttachmentDto":{"type":"object","properties":{"file_name":{"type":"string","description":"Original file name","maxLength":500},"file_key":{"type":"string","description":"R2 storage key for the file","maxLength":1000},"content_type":{"type":"string","description":"MIME type of the file","maxLength":100},"file_size":{"type":"number","minimum":1,"description":"File size in bytes"}},"required":["file_name","file_key","content_type","file_size"]},"TaskAttachmentResponseDto":{"type":"object","properties":{"id":{"type":"string"},"task_id":{"type":"string"},"user_id":{"type":"string"},"file_name":{"type":"string"},"file_key":{"type":"string"},"content_type":{"type":"string"},"file_size":{"type":"number"},"download_url":{"type":"string"},"user":{"$ref":"#/components/schemas/TaskCommentUserDto"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","task_id","user_id","file_name","file_key","content_type","file_size","created_at","updated_at"]},"GenerateUploadCommentAttachmentUrlDto":{"type":"object","properties":{"file_name":{"type":"string","description":"Original file name","maxLength":500},"content_type":{"type":"string","description":"MIME type of the file","maxLength":100}},"required":["file_name","content_type"]},"CreateCommentAttachmentDto":{"type":"object","properties":{"file_name":{"type":"string","description":"Original file name","maxLength":500},"file_key":{"type":"string","description":"R2 storage key for the file","maxLength":1000},"content_type":{"type":"string","description":"MIME type of the file","maxLength":100},"file_size":{"type":"number","minimum":1,"description":"File size in bytes"}},"required":["file_name","file_key","content_type","file_size"]},"CommentAttachmentResponseDto":{"type":"object","properties":{"id":{"type":"string"},"comment_id":{"type":"string"},"user_id":{"type":"string"},"file_name":{"type":"string"},"file_key":{"type":"string"},"content_type":{"type":"string"},"file_size":{"type":"number"},"download_url":{"type":"string"},"user":{"$ref":"#/components/schemas/TaskCommentUserDto"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","comment_id","user_id","file_name","file_key","content_type","file_size","created_at","updated_at"]},"CreateTaskReactionDto":{"type":"object","properties":{"emoji":{"type":"string","maxLength":10,"description":"Emoji reaction (single emoji character)","example":"👍"}},"required":["emoji"]},"MapExternalStatusToCompleteDto":{"type":"object","properties":{"project_id":{"type":"string"},"external_statuses":{"type":"object"}},"required":["project_id","external_statuses"]},"SyncedProjectDto":{"type":"object","properties":{"name":{"type":"string"},"project_id":{"type":"string"},"portal_id":{"type":"string"},"is_synced":{"type":"boolean"},"external_statuses":{"type":"array","items":{"$ref":"#/components/schemas/ExternalTaskStatus"}},"synced_at":{"type":"string","nullable":true},"have_tasks_been_synced":{"type":"boolean"}},"required":["name","project_id","portal_id","is_synced","external_statuses","have_tasks_been_synced"]},"SyncProjectDto":{"type":"object","properties":{"platform":{"enum":["zoho","clickup","trello","jira","asana","monday","google","microsoft"],"type":"string"},"portal_id":{"type":"string"},"project_id":{"type":"string"}}},"TrackEventDto":{"type":"object","properties":{"event_type":{"type":"string"},"user_properties":{"type":"object","additionalProperties":true},"event_data":{"type":"object","properties":{"data":{"type":"object","properties":{"quantity":{"type":"number"},"quitReason":{"type":"string"},"feedback":{"type":"string"},"uninstallDescription":{"type":"string"}},"selfRequired":false}},"required":["data"]}},"required":["event_type"]},"AdminTrackEventResponseDto":{"type":"object","properties":{"id":{"type":"string"},"event_name":{"type":"string"},"event_data":{"type":"object","additionalProperties":true,"nullable":true},"created_at":{"type":"string"}},"required":["id","event_name","event_data","created_at"]},"AsyncTaskResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the async task","example":"uuid-string"},"status":{"enum":["pending","processing","completed","failed"],"type":"string","description":"Status of the async task","example":"pending"},"metadata":{"type":"object","additionalProperties":true,"description":"Metadata associated with the async task","example":{"taskType":"data-processing","progress":50}},"createdAt":{"format":"date-time","type":"string","description":"Creation timestamp","example":"2025-06-13T10:00:00Z"},"updatedAt":{"format":"date-time","type":"string","description":"Last update timestamp","example":"2025-06-13T10:30:00Z"}},"required":["id","status","createdAt","updatedAt"]},"InviteBuddyDto":{"type":"object","properties":{"partner_email":{"type":"string","format":"email"}},"required":["partner_email"]},"BuddyInfoDto":{"type":"object","properties":{"id":{"type":"string","nullable":true},"email":{"type":"string"},"first_name":{"type":"string"},"last_name":{"type":"string"}},"required":["email"]},"InviterInfoDto":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"first_name":{"type":"string"},"last_name":{"type":"string"}},"required":["id","email"]},"AccountabilityBuddyResponseDto":{"type":"object","properties":{"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"},"invitation_status":{"type":"string","enum":["pending","accepted","rejected","expired"]},"invitation_sent_at":{"type":"string"},"invitation_responded_at":{"type":"string","nullable":true},"buddy_info":{"$ref":"#/components/schemas/BuddyInfoDto"},"inviter_info":{"$ref":"#/components/schemas/InviterInfoDto"}},"required":["id","created_at","updated_at","invitation_status","buddy_info","inviter_info"]},"CreateUnlockRequestDto":{"type":"object","properties":{"reason":{"type":"string","maxLength":1000},"unlock_duration_minutes":{"type":"number","maximum":1440,"minimum":1},"accountability_buddy_user_id":{"type":"string","format":"uuid"}},"required":["unlock_duration_minutes","accountability_buddy_user_id"]},"RequesterInfoDto":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"first_name":{"type":"string"},"last_name":{"type":"string"}},"required":["id","email"]},"UnlockRequestResponseDto":{"type":"object","properties":{"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"},"reason":{"type":"string","nullable":true},"status":{"type":"string","enum":["pending","approved","rejected","expired"]},"approved_at":{"type":"string","nullable":true},"unlock_duration_minutes":{"type":"number","nullable":true},"requester_info":{"$ref":"#/components/schemas/RequesterInfoDto"}},"required":["id","created_at","updated_at","status","requester_info"]},"ApproveUnlockRequestByTokenDto":{"type":"object","properties":{"token":{"type":"string","description":"JWT token for unlock request approval from email","example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}},"required":["token"]},"ProjectStatusDto":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"color":{"type":"string"},"order":{"type":"number"},"should_complete_task":{"type":"boolean"}},"required":["id","label","color","order","should_complete_task"]},"CreateProjectDto":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"custom_statuses":{"type":"array","items":{"$ref":"#/components/schemas/ProjectStatusDto"}},"due_date":{"type":"string"},"importance":{"type":"number","minimum":1,"maximum":4},"outcome":{"type":"number","nullable":true,"description":"Outcome significance, 1..10. Omitted/null means unrated; independent of importance (1..4).","minimum":1,"maximum":10},"metadata":{"type":"object","additionalProperties":true,"nullable":true,"description":"Open per-project bag; `metadata.tags` is the reserved, validated, queryable key.\n\nStored **unencrypted** so the server can index and filter it — do not put anything sensitive here.\nCapped at 8KB serialized."}},"required":["name"]},"ProjectMemberResponseDto":{"type":"object","properties":{"id":{"type":"string"},"user_id":{"type":"string"},"email":{"type":"string"},"role":{"enum":["owner","admin","member"],"type":"string"},"invitation_status":{"enum":["pending","accepted","declined","failed"],"type":"string"},"invitation_sent_at":{"format":"date-time","type":"string"},"invitation_responded_at":{"format":"date-time","type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","role","invitation_status","created_at","updated_at"]},"TopPriorityTaskDto":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"top_score":{"type":"number","nullable":true,"description":"Materialised TOP score. Null for todos not yet scored by the daily cron."}},"required":["id","title","top_score"]},"ProjectResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"For native projects: the project UUID.\nFor synced (ClickUp) projects: the focus_mode_tags.id when a tag exists,\notherwise the synced_projects.id. Use synced_project_id to reliably\nidentify the synced project record regardless of tag presence.\n\nNot normalized to synced_project_id as mobile/web clients use this id for\nGET /projects/:id lookups and routing. A swap to synced_project_id requires a coordinated client release."},"name":{"type":"string"},"description":{"type":"string"},"owner_id":{"type":"string"},"custom_statuses":{"type":"array","items":{"type":"object"}},"icon":{"type":"string","nullable":true,"description":"One emoji character, or `null` when the project has no icon yet — which is what a clear\nreturns, and what a project awaiting generation carries. This is the schema clients decode,\nso the nullability belongs here rather than only in the tests that assert it."},"members":{"type":"array","items":{"$ref":"#/components/schemas/ProjectMemberResponseDto"}},"task_count":{"type":"number"},"uncompleted_task_count":{"type":"number"},"synced_project_id":{"type":"string"},"synced_platform":{"type":"string","nullable":true,"description":"Stored integration platform for synced projects; null when the legacy source is unknown. Read only."},"due_date":{"type":"string","nullable":true},"importance":{"type":"number"},"outcome":{"type":"number","nullable":true,"description":"Outcome significance on the 1..10 wire scale; null for unrated or synced projects."},"status":{"description":"Lifecycle state: active (default), completed, or archived.","enum":["active","completed","archived"],"type":"string"},"top_priority_task":{"nullable":true,"description":"Highest-TOP incomplete task (SMART order), or null when the project has none.","type":"object","allOf":[{"$ref":"#/components/schemas/TopPriorityTaskDto"}]},"metadata":{"type":"object","additionalProperties":true,"nullable":true,"description":"Open per-project bag; `metadata.tags` holds the project's tags, lower-cased. Null when unset, and\nalways null for synced projects, which have no row in `projects` to carry it."},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","name","owner_id","custom_statuses","outcome","status","created_at","updated_at"]},"GetProjectsResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"type":"array"}},"meta":{"$ref":"#/components/schemas/PaginationMetaDto"},"projects":{"deprecated":true,"description":"Deprecated alias for data","type":"array","items":{"$ref":"#/components/schemas/ProjectResponseDto"}},"total_count":{"type":"number","deprecated":true,"description":"Deprecated alias for meta.itemCount"}},"required":["data","meta","projects","total_count"]},"UpdateProjectDto":{"type":"object","properties":{"name":{"type":"string","description":"Omit to keep the name. Not `@IsOptional()`: that would also skip validation for `null`, which then\nreached the duplicate-name check as a non-string (a 500) — and `\"\"` would blank the name."},"description":{"type":"string"},"custom_statuses":{"type":"array","items":{"$ref":"#/components/schemas/ProjectStatusDto"}},"due_date":{"type":"string"},"importance":{"type":"number","minimum":1,"maximum":4},"outcome":{"type":"number","nullable":true,"description":"Outcome significance, 1..10. Omit to preserve the rating; null clears it.","minimum":1,"maximum":10},"status":{"type":"string","enum":["active","completed","archived"]},"icon":{"type":"string","nullable":true,"description":"The project's emoji, e.g. \"🎯\" — the literal character, which is what the icon generator\nitself stores. Either `\"\"` or `null` clears it back to the automatic icon; both are accepted\nso a client whose model is a nullable string (e.g. a Swift `String?`) needs no special case.\n\nDeclared here deliberately: the global pipe runs with `whitelist: true`, so before this\nexisted an icon-only `PUT` arrived as an empty patch and TypeORM threw on the empty `SET`\n(a 500, not a validation error) — report 2026-09-14_20-07-42."},"metadata":{"type":"object","additionalProperties":true,"nullable":true,"description":"Open per-project bag; `metadata.tags` is the reserved, validated, queryable key.\n\nStored **unencrypted** so the server can index and filter it — do not put anything sensitive here.\nCapped at 8KB serialized.\n\nShallow-merged over the stored bag one level deep (in SQL, so concurrent writes cannot clobber each\nother), so a client that only knows about `tags` cannot wipe a key another client added. Set a key\nto `null` to delete it, or send `metadata: null` to clear the bag entirely.\n\nThe cost of merge semantics: there is no single-request way to *replace* the whole bag — that is\n`metadata: null` followed by a second write.\n\nMUST stay declared here: the global pipe runs `whitelist: true`, so an undeclared field is stripped\nbefore the service sees it, leaving an empty `SET` and a bare 500 (`UpdateValuesMissingError`) —\nhow the project `icon` save broke (#2404)."}}},"InviteProjectMemberDto":{"type":"object","properties":{"role":{"enum":["admin","member"],"type":"string"},"email":{"type":"string","format":"email"}},"required":["email"]},"UpdateProjectMemberDto":{"type":"object","properties":{"role":{"enum":["admin","member"],"type":"string"}},"required":["role"]},"GetProjectToDosResponseDto":{"type":"object","properties":{"data":{"type":"array","items":{"type":"array"}},"meta":{"$ref":"#/components/schemas/PaginationMetaDto"}},"required":["data","meta"]},"LessonPlanTaskDto":{"type":"object","properties":{"duration_minutes":{"type":"number","nullable":true,"description":"Stated activity duration in minutes, or null"},"title":{"type":"string"}},"required":["duration_minutes","title"]},"LessonPlanPreviewResponseDto":{"type":"object","properties":{"title":{"type":"string"},"tasks":{"type":"array","items":{"$ref":"#/components/schemas/LessonPlanTaskDto"}},"allowed_urls":{"type":"array","items":{"type":"string"}}},"required":["title","tasks","allowed_urls"]},"CreateClassDto":{"type":"object","properties":{"name":{"type":"string","maxLength":255},"parent_team_id":{"type":"string","description":"Required parent (school) team. A class always belongs to a parent team: it inherits the\nparent's expiry and enrols only from the parent's members. Missing/empty/non-UUID values are\nrejected here (400) before the request reaches the service.","format":"uuid"}},"required":["name","parent_team_id"]},"RenameClassDto":{"type":"object","properties":{"name":{"type":"string","maxLength":255}},"required":["name"]},"ClassMemberEntryDto":{"type":"object","properties":{"user_id":{"type":"string","description":"Registered Focus Bear user id (only registered parent-team members are addable).","format":"uuid"},"role":{"type":"string","enum":["student","teacher"]}},"required":["user_id","role"]},"AddClassMembersDto":{"type":"object","properties":{"members":{"minItems":1,"type":"array","items":{"$ref":"#/components/schemas/ClassMemberEntryDto"}}},"required":["members"]},"UpdateConcernCriteriaDto":{"type":"object","properties":{"focus_threshold_pct":{"type":"number","maximum":100,"minimum":0},"lookback_sessions":{"type":"number","maximum":20,"minimum":1}},"required":["focus_threshold_pct","lookback_sessions"]},"SessionTaskDto":{"type":"object","properties":{"title":{"type":"string","maxLength":200},"duration_minutes":{"type":"number","minimum":1,"maximum":720},"order":{"type":"number","minimum":0,"maximum":29}},"required":["title"]},"StartClassSessionDto":{"type":"object","properties":{"name":{"type":"string","maxLength":255},"allowed_apps":{"type":"array","items":{"type":"string","maxLength":512}},"allowed_urls":{"type":"array","items":{"type":"string","maxLength":512}},"app_identities":{"description":"Platform identities for `allowed_apps` entries, keyed by `entry`. Optional: the server fills in\ncommon apps from the catalog, and on amend an omitted list keeps the stored identities.","type":"array","items":{"$ref":"#/components/schemas/AppIdentityDto"}},"team_id":{"type":"string","format":"uuid"},"timezone":{"type":"string","description":"Client-asserted IANA timezone for the session-window check. Ambiguous UTC/GMT aliases remain\nvalid input but defer to the stored timezone. This request-scoped value is not persisted."},"focus_mode_id":{"type":"string","description":"Start from an existing shared focus mode (its allow-list is snapshotted into the session).\nWhen omitted, allowed_apps/allowed_urls are required and a team-shared focus mode\n(team_id = class) is created and linked for reuse.","format":"uuid"},"block_level":{"type":"string","enum":["gentle","strict","super-strict"]},"ai_blocking_enabled":{"type":"boolean","description":"When true, student apps run their (slow) AI relevance check before blocking a non-listed\nsite; when false/omitted they block immediately (defaults false — Mac-App#2092)."},"ai_contest_enabled":{"type":"boolean","description":"Whether a student may explain an AI block and have the server re-run the AI (defaults true;\nonly meaningful when `ai_blocking_enabled` is on)."},"block_bypass_sites":{"type":"boolean","description":"Whether students' apps block Focus Bear's bypass-site list during the class (defaults true)."},"scheduled_finish_time":{"format":"date-time","type":"string"},"tasks":{"description":"Optional teacher-assigned checklist shown to every invited student (capped, snapshotted).","type":"array","items":{"$ref":"#/components/schemas/SessionTaskDto"}}},"required":["team_id"]},"AmendAllowlistDto":{"type":"object","properties":{"allowed_apps":{"type":"array","items":{"type":"string","maxLength":512}},"allowed_urls":{"type":"array","items":{"type":"string","maxLength":512}},"app_identities":{"description":"Platform identities for `allowed_apps` entries, keyed by `entry`. Optional: the server fills in\ncommon apps from the catalog, and on amend an omitted list keeps the stored identities.","type":"array","items":{"$ref":"#/components/schemas/AppIdentityDto"}},"ai_blocking_enabled":{"type":"boolean","description":"Hot-toggle for the student-side AI relevance check (Mac-App#2092). When present the\nsession field is updated in the same transactional write as the allow-list; when\nomitted the current value is kept."},"ai_contest_enabled":{"type":"boolean","description":"Hot-toggle for student AI contests, same semantics as `ai_blocking_enabled` (omitted = keep)."},"block_bypass_sites":{"type":"boolean","description":"Hot-toggle for blocking bypass sites, same semantics as `ai_blocking_enabled` (omitted = keep)."},"expected_allowlist_version":{"type":"number","description":"Optimistic concurrency token: when set and stale, the request fails with 409 Conflict\nso concurrent teacher tabs don't silently clobber each other.","minimum":1}},"required":["allowed_apps","allowed_urls"]},"AmendSessionTaskDto":{"type":"object","properties":{"title":{"type":"string","maxLength":200},"duration_minutes":{"type":"number","minimum":1,"maximum":720},"order":{"type":"number","minimum":0,"maximum":29},"id":{"type":"string","description":"Must already belong to the session: mid-session add/delete is out of scope for v1.","format":"uuid"}},"required":["title","id"]},"AmendSessionTasksDto":{"type":"object","properties":{"tasks":{"description":"Full replacement of the mutable fields for the session's EXISTING task set — every current\ntask must appear exactly once (same simplicity as the allow-list amend). Task rows are\nupdated in place, never recreated, so student completions survive the amendment.","minItems":1,"type":"array","items":{"$ref":"#/components/schemas/AmendSessionTaskDto"}},"expected_tasks_version":{"type":"number","description":"Optimistic concurrency token: when set and stale, the request fails with 409 Conflict\nso concurrent teacher tabs don't silently clobber each other.","minimum":1}},"required":["tasks"]},"ResolveUnlockRequestsByStudentDto":{"type":"object","properties":{"student_id":{"type":"string","format":"uuid"}},"required":["student_id"]},"ClassSessionParticipant":{"type":"object","properties":{"class_session_id":{"type":"string"},"student_id":{"type":"string"},"join_status":{"type":"string","enum":["invited","joined","declined","left"]},"joined_at":{"format":"date-time","type":"string"},"left_at":{"format":"date-time","type":"string"},"in_focus_seconds":{"type":"number","description":"Seconds the student self-reported being in focus (heartbeat-credited, gap-capped)."},"joined_seconds":{"type":"number","description":"Seconds the student has spent joined across all join/leave episodes in this session."},"last_heartbeat_at":{"format":"date-time","type":"string"},"last_heartbeat_in_focus":{"type":"boolean"},"blocking_permissions_enabled":{"type":"boolean","nullable":true,"description":"Latest explicit client report; null means the client has not reported permissions."},"missing_blocking_permissions":{"nullable":true,"description":"Platform permission names the client reported missing with its latest explicit `false`.","type":"array","items":{"type":"string"}},"linked_completed_focus_block_id":{"type":"string","description":"The enforced personal focus block created when the student joined."},"class_session":{"$ref":"#/components/schemas/ClassFocusSession"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["class_session_id","student_id","join_status","in_focus_seconds","joined_seconds"]},"ClassSessionTaskCompletion":{"type":"object","properties":{"class_session_task_id":{"type":"string"},"student_id":{"type":"string"},"completed_at":{"format":"date-time","type":"string"},"class_session_task":{"$ref":"#/components/schemas/ClassSessionTask"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["class_session_task_id","student_id","completed_at"]},"ClassSessionTask":{"type":"object","properties":{"class_session_id":{"type":"string"},"title":{"type":"string"},"duration_minutes":{"type":"number","nullable":true,"description":"Optional teacher-suggested time budget for the task, in minutes."},"order":{"type":"number","description":"Display order within the session's checklist (ascending)."},"class_session":{"$ref":"#/components/schemas/ClassFocusSession"},"completions":{"type":"array","items":{"$ref":"#/components/schemas/ClassSessionTaskCompletion"}},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["class_session_id","order"]},"ClassFocusSession":{"type":"object","properties":{"team_id":{"type":"string"},"initiated_by":{"type":"string","description":"Teacher (team admin) who started the session."},"focus_mode_id":{"type":"string","nullable":true,"description":"The team-shared focus mode behind this session. Every joined student's enforced block\npoints at this ONE row; the mode persists after the session for reuse (school/class-wide).\nThe session's own allow-list fields stay the live source of truth for amendments."},"focus_mode":{"$ref":"#/components/schemas/FocusMode"},"name":{"type":"string"},"allowed_apps":{"type":"array","items":{"type":"string"}},"allowed_urls":{"type":"array","items":{"type":"string"}},"app_identities":{"nullable":true,"description":"Platform identities for the app entries (`allowed_apps`, and on focus modes the Windows app's\n`metadata.allowed_apps_win`), keyed by `entry` like `categories`. Clients match the running app\nby these instead of a renameable name; entries with none are matched by name as before. Filled\nfrom the common-apps catalog on every write, so older clients that send names only still get\nthem. Encrypted and nullable with no SQL default for the same reason as `categories`.","type":"array","items":{"type":"object"}},"block_level":{"type":"string","enum":["gentle","strict","super-strict"]},"ai_blocking_enabled":{"type":"boolean","description":"When true, student apps run their (slow, ~3-4s) AI relevance check before blocking a\nnon-listed site; when false they block immediately. Clients default to false when the\nfield is absent, so this column is additive-safe (Mac-App#2092)."},"ai_contest_enabled":{"type":"boolean","description":"When true (default), a student whose site/app the AI blocked can explain why they need it and\nhave the SERVER re-run the AI (POST /class-session/:id/ai-contest). Defaults on because the\nteacher already opted into AI judgement via `ai_blocking_enabled`; a contest only lets that AI\nreconsider its own verdict (never the teacher's allow-list) and every AI allow is shown to the\nteacher. Inert while `ai_blocking_enabled` is false."},"block_bypass_sites":{"type":"boolean","description":"When true (default), student apps block Focus Bear's bypass-site list (GET\n/managed-blocking/bypass-sites: web proxies, translation proxies, web archives, cloud browsers,\nremote-desktop portals) unless the teacher listed that site itself. It applies even with the AI\ncheck on: a proxy's own page says nothing about the site it is showing."},"status":{"type":"string","enum":["live","ended"]},"start_time":{"format":"date-time","type":"string"},"scheduled_finish_time":{"format":"date-time","type":"string"},"ended_at":{"format":"date-time","type":"string"},"allowlist_version":{"type":"number","description":"Bumped on every allow-list amendment so clients can drop stale/duplicate deliveries."},"tasks_version":{"type":"number","description":"Bumped on every mid-session task amendment (title/duration/order). Independent of\n`allowlist_version`: clients gate `class-session-tasks-updated` deliveries on THIS counter,\nand a task amend never touches the allow-list counter (or vice versa)."},"team":{"$ref":"#/components/schemas/Team"},"participants":{"type":"array","items":{"$ref":"#/components/schemas/ClassSessionParticipant"}},"tasks":{"type":"array","items":{"$ref":"#/components/schemas/ClassSessionTask"}},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["team_id","initiated_by","block_level","ai_blocking_enabled","ai_contest_enabled","block_bypass_sites","status","start_time","allowlist_version","tasks_version"]},"ClassSessionUnlockRequest":{"type":"object","properties":{"class_session_id":{"type":"string"},"student_id":{"type":"string"},"requested_domain":{"type":"string"},"requested_app":{"type":"string"},"reason":{"type":"string"},"ai_reason":{"type":"string","description":"The AI's reply on an AI-contest verdict row; null on teacher requests."},"status":{"type":"object"},"resolved_by":{"type":"string","description":"Teacher who approved/denied the request; null for AI-contest verdicts (the AI resolved them)."},"resolved_at":{"format":"date-time","type":"string"},"class_session":{"$ref":"#/components/schemas/ClassFocusSession"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["class_session_id","student_id","status"]},"SubmitUnlockRequestDto":{"type":"object","properties":{"requested_domain":{"type":"string","maxLength":512},"requested_app":{"type":"string","maxLength":512},"reason":{"type":"string","maxLength":1000}}},"SubmitAiContestDto":{"type":"object","properties":{"requested_domain":{"type":"string","maxLength":512},"requested_app":{"type":"string","maxLength":512},"url":{"type":"string","description":"The blocked page; must be on requested_domain. Clients strip the query string; the server\nstrips it again before the AI sees it.","maxLength":2048},"tab_title":{"type":"string","maxLength":500},"current_task":{"type":"string","description":"The teacher-assigned checklist task the student is working on.","maxLength":500},"explanation":{"type":"string","maxLength":1000}},"required":["explanation"]},"HeartbeatDto":{"type":"object","properties":{"in_focus":{"type":"boolean"},"blocking_permissions_enabled":{"type":"boolean"},"missing_blocking_permissions":{"description":"Platform-specific names (e.g. `accessibility`); only read when blocking_permissions_enabled is false.","type":"array","items":{"type":"string"}},"device_id":{"type":"string"}},"required":["in_focus"]},"CreateWebhookSubscriptionDto":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255,"description":"A friendly name for the webhook subscription","example":"My Zapier Webhook"},"url":{"type":"string","format":"uri","maxLength":2048,"description":"The URL to send webhook events to","example":"https://hooks.zapier.com/hooks/catch/123456/abcdef/"},"event_types":{"minItems":1,"type":"array","items":{"type":"string","enum":["habit.completed","routine.completed","focus_session.started","focus_session.completed","break.started","break.completed"]},"description":"The event types to subscribe to","example":["habit.completed","routine.completed"]},"secret":{"type":"string","maxLength":64,"description":"Optional secret for webhook signature verification","example":"my-webhook-secret"}},"required":["name","url","event_types"]},"WebhookSubscriptionResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier of the webhook subscription","example":"123e4567-e89b-12d3-a456-426614174000"},"name":{"type":"string","description":"A friendly name for the webhook subscription","example":"My Zapier Webhook"},"url":{"type":"string","description":"The URL to send webhook events to","example":"https://hooks.zapier.com/hooks/catch/123456/abcdef/"},"event_types":{"type":"array","items":{"type":"string","enum":["habit.completed","routine.completed","focus_session.started","focus_session.completed","break.started","break.completed"]},"description":"The event types subscribed to","example":["habit.completed","routine.completed"]},"is_active":{"type":"boolean","description":"Whether the webhook subscription is active","example":true},"last_triggered_at":{"type":"string","description":"The last time the webhook was triggered","example":"2024-01-15T10:30:00Z"},"failure_count":{"type":"number","description":"The number of consecutive failures","example":0},"created_at":{"type":"string","description":"When the webhook subscription was created","example":"2024-01-01T00:00:00Z"}},"required":["id","name","url","event_types","is_active","failure_count","created_at"]},"UpdateWebhookSubscriptionDto":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255,"description":"A friendly name for the webhook subscription","example":"My Zapier Webhook"},"url":{"type":"string","format":"uri","maxLength":2048,"description":"The URL to send webhook events to","example":"https://hooks.zapier.com/hooks/catch/123456/abcdef/"},"event_types":{"minItems":1,"type":"array","items":{"type":"string","enum":["habit.completed","routine.completed","focus_session.started","focus_session.completed","break.started","break.completed"]},"description":"The event types to subscribe to","example":["habit.completed","routine.completed"]},"secret":{"type":"string","maxLength":64,"description":"Optional secret for webhook signature verification","example":"my-webhook-secret"},"is_active":{"type":"boolean","description":"Whether the webhook subscription is active","example":true}}},"StartFocusSessionDto":{"type":"object","properties":{"focus_mode_name":{"type":"string","description":"Name of the focus mode to start"},"duration_minutes":{"type":"number","minimum":1,"description":"Duration in minutes (default: 25)"},"intention":{"type":"string","description":"Intention for this focus session"}},"required":["focus_mode_name"]},"CompleteHabitDto":{"type":"object","properties":{"habit_name":{"type":"string","description":"Name of the habit to complete"},"routine_name":{"type":"string","description":"Name of the routine containing the habit (e.g., \"morning\", \"evening\", \"break\")"},"duration_seconds":{"type":"number","minimum":1,"description":"Duration in seconds (default: activity duration or 60)"}},"required":["habit_name"]},"Portal":{"type":"object","properties":{"id":{"type":"string"}},"required":["id"]},"IntegrationProject":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"key":{"type":"string"},"description":{"type":"string"},"portal_id":{"type":"string"}},"required":["id","name","key","description"]},"Task":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"key":{"type":"string"},"description":{"type":"string"},"project_id":{"type":"string"},"portal_id":{"type":"string"},"status":{"type":"string"},"external_status":{"type":"string"},"external_metadata":{"type":"object"},"subtasks":{"type":"array","items":{"type":"object"}}},"required":["id","name","key","description","status","external_metadata"]},"CreateTimeLog":{"type":"object","properties":{"bill_status":{"type":"string","enum":["Billable","Non Billable"]},"date":{"type":"string"},"owner":{"type":"string"},"hours":{"type":"string","pattern":"^([01]\\d|2[0-3]):([0-5]\\d)$"},"notes":{"type":"string"},"custom_fields":{"type":"object"},"cost_per_hour":{"type":"number"}},"required":["bill_status","date","owner","hours","notes","custom_fields","cost_per_hour"]},"UpdateCalendarEventDto":{"type":"object","properties":{"dismiss_reason":{"type":"string","maxLength":255},"id":{"type":"string","format":"uuid"},"summary":{"type":"string"},"description":{"type":"string"},"event_begins":{"format":"date-time","type":"string"},"event_ends":{"format":"date-time","type":"string"},"is_dismissed":{"type":"boolean"},"external_id":{"type":"string"},"received":{"type":"boolean"},"platform":{"enum":["google","microsoft"],"type":"string"},"platform_account":{"type":"string"},"calendar_id":{"type":"string"},"external_metadata":{"type":"object"},"device_id":{"type":"string","description":"The device reporting the change. Never persisted — it only rides along on the dismissal\nbroadcast so the sender can ignore its own event, keeping this endpoint at the parity with\n`POST calendar-events/dismiss` that its description promises.","format":"uuid"}}},"DismissCalendarEventDto":{"type":"object","properties":{"summary":{"type":"string","maxLength":2500},"dismiss_reason":{"type":"string","maxLength":255},"event_begins":{"format":"date-time","type":"string"},"device_id":{"type":"string","description":"The device reporting the dismissal. Echoed back in the broadcast so the sender can ignore its\nown event — the same convention every other `private-<userId>` trigger follows\n(`settings-updated`, `blocking-schedule-updated`). Optional: a client that does not send it\nsimply has to tolerate its own echo.","format":"uuid"}},"required":["summary","event_begins"]},"UserGoalDto":{"type":"object","properties":{"goal":{"type":"string","pattern":"^[^<>{}`\\p{Cc}]+$","maxLength":200},"isCustom":{"type":"boolean"}},"required":["goal"]},"GetRoutineSuggestionsDto":{"type":"object","properties":{"habit_theme":{"type":"string","maxLength":100},"user_goals":{"minItems":1,"type":"array","items":{"$ref":"#/components/schemas/UserGoalDto"}},"routine_duration":{"type":"number"},"routine":{"type":"string"},"groupByGoals":{"type":"boolean"},"language":{"enum":["en","es","de","ja","vi","pt-BR","pt-PT","zh-CN","zh-TW","nl","tl","fr","it","pl","ru","ar","ro"],"type":"string"}},"required":["user_goals","routine_duration"]},"AdjustHabitDto":{"type":"object","properties":{"name":{"type":"string"},"is_office_friendly":{"type":"boolean"},"take_notes":{"enum":["NO_NOTE","DURING_ACTIVITY","END_OF_ACTIVITY"],"type":"string"},"priority":{"enum":["STANDARD","HIGH"],"type":"string"},"allowed_focus_mode_id":{"type":"string","format":"uuid"},"video_urls":{"type":"array","items":{"type":"string"}},"include_in_every_break":{"type":"boolean"},"habit_icon":{"type":"string"},"habit_icon_generation_failed":{"type":"boolean"},"log_quantity_question":{"type":"string"},"choice_type":{"enum":["random","normal","competency","check_list"],"type":"string"},"allowed_apps":{"type":"array","items":{"type":"string"}},"allowed_mobile_apps":{"type":"array","items":{"type":"string"}},"allowed_urls":{"type":"array","items":{"type":"string"}},"break_type":{"enum":["micro","pomodoro"],"type":"string"},"linked_project_ids":{"maxItems":10,"type":"array","items":{"type":"string","format":"uuid"}},"tags":{"type":"array","items":{"type":"string"}},"linked_project_id":{"type":"string","format":"uuid","description":"First of linked_project_ids, for older clients"},"log_quantity":{"type":"boolean"},"duration_seconds":{"type":"number"},"completion_requirements":{"type":"string"},"log_summary_type":{"enum":["SUM","AVG"],"type":"string"},"choices":{"minItems":1,"type":"array","items":{"$ref":"#/components/schemas/ActivityChoiceData"}},"days_of_week":{"minItems":1,"items":{"type":"string","enum":["ALL","MON","TUE","WED","THU","FRI","SAT","SUN"]},"default":["ALL"],"type":"array"},"impact_category":{"enum":["hours_of_sleep","energy_level_upon_awakening","mood","perception_of_productivity","minutes_spent_on_distracting_websites","minutes_spent_postponing_app_blocks","minutes_spent_postponing_habits"],"type":"string"},"geofence_id":{"type":"string","nullable":true,"format":"uuid"},"id":{"type":"string","format":"uuid"},"activity_template_id":{"type":"string","format":"uuid"},"is_default":{"type":"boolean"},"run_micro_breaks":{"type":"boolean"},"log_quantity_questions":{"type":"array","items":{"$ref":"#/components/schemas/LogQuantityQuestion"}},"linked_activity_id":{"type":"string","format":"uuid"},"linked_activity_template_id":{"type":"string","format":"uuid"},"check_list":{"type":"array","items":{"type":"string"}},"activity_type":{"type":"string"},"tutorial":{"type":"string","format":"uuid"},"cutoff_time_for_doing_activity":{"type":"string"},"category":{"type":"string"},"text_instructions":{"type":"string"},"image_urls":{"type":"array","items":{"$ref":"#/components/schemas/ActivityImageData"}},"current_competency_level":{"type":"number"},"competency_level":{"type":"number"},"show_saved_distracting_websites":{"type":"boolean"},"pack_id":{"type":"string","format":"uuid"},"emoji":{"type":"string"}},"required":["name","id"]},"AdjustHabitsWithAiDto":{"type":"object","properties":{"current_habits":{"minItems":1,"type":"array","items":{"$ref":"#/components/schemas/AdjustHabitDto"}},"user_feedback":{"type":"string"},"user_goals":{"type":"array","items":{"type":"string"}},"routine_duration":{"type":"number"},"groupByGoals":{"type":"boolean"},"language":{"enum":["en","es","de","ja","vi","pt-BR","pt-PT","zh-CN","zh-TW","nl","tl","fr","it","pl","ru","ar","ro"],"type":"string"}},"required":["current_habits","user_feedback"]},"CreateHabitWithAiDto":{"type":"object","properties":{"prompt":{"type":"string","maxLength":300},"user_goals":{"type":"array","items":{"type":"string"}},"routine_duration":{"type":"number"},"routine":{"type":"string"},"language":{"type":"string","enum":["en","es","de","ja","vi","pt-BR","pt-PT","zh-CN","zh-TW","nl","tl","fr","it","pl","ru","ar","ro"]}},"required":["prompt"]},"GenerateImportUploadUrlDto":{"type":"object","properties":{"mediaType":{"type":"string","enum":["audio","image"]},"fileExtension":{"type":"string"}},"required":["mediaType","fileExtension"]},"HabitImportUploadedDto":{"type":"object","properties":{"routineDurationMinutes":{"type":"number","maximum":120,"minimum":1},"mediaKey":{"type":"string"},"mediaType":{"type":"string","enum":["audio","image"]},"routineType":{"type":"string","enum":["morning","evening","break"]}},"required":["mediaKey","mediaType"]},"CreateSupportRequestDto":{"type":"object","properties":{"type":{"type":"string","enum":["financial_assistance","contact"]},"contact_email":{"type":"string","format":"email"},"category":{"type":"string","enum":["low_income","student","unemployed","health_disability","non_profit","other"]},"reason":{"type":"string","enum":["temporary_hardship","out_of_reach","keep_pro_features","other"]},"message":{"type":"string","maxLength":5000},"app_platform":{"type":"string","enum":["ios","android"]},"app_version":{"type":"string","maxLength":50}},"required":["type","contact_email","message","app_platform","app_version"]},"RequestStudentDiscountCodeDto":{"type":"object","properties":{"email":{"type":"string","format":"email"}},"required":["email"]},"VerifyStudentDiscountCodeDto":{"type":"object","properties":{"email":{"type":"string","format":"email"},"code":{"type":"string","pattern":"^\\d{6}$"}},"required":["email","code"]},"VideoMetadataBodyDto":{"type":"object","properties":{"video_urls":{"type":"array","items":{"type":"string"}}},"required":["video_urls"]},"VideoMetadataDto":{"type":"object","properties":{"id":{"type":"string"},"video_url":{"type":"string"},"title":{"type":"string"},"duration":{"type":"string"},"thumbnail_url":{"type":"string","nullable":true,"default":null},"thumbnail_width":{"type":"number","nullable":true,"default":null},"thumbnail_height":{"type":"number","nullable":true,"default":null}},"required":["id","video_url","title","duration","thumbnail_url","thumbnail_width","thumbnail_height"]},"VideoMetadataResponseDto":{"type":"object","properties":{"videos_metadata":{"type":"array","items":{"$ref":"#/components/schemas/VideoMetadataDto"}}},"required":["videos_metadata"]},"TrackResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"artist":{"type":"string"},"description":{"type":"string"},"download_url":{"type":"string"},"thumbnail_download_url":{"type":"string"},"duration":{"type":"number"}},"required":["id","name","download_url"]},"UpsertTrackDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"artist":{"type":"string"},"description":{"type":"string"},"file_name":{"type":"string"},"thumbnail_file_name":{"type":"string"},"duration":{"type":"number"}},"required":["name","file_name"]},"Track":{"type":"object","properties":{"name":{"type":"string"},"artist":{"type":"string"},"description":{"type":"string"},"file_name":{"type":"string"},"duration":{"type":"number"},"thumbnail_file_name":{"type":"string"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["file_name"]},"CreateCourseDto":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"platform":{"type":"string","enum":["web","mac","win","ios","android"]},"language":{"type":"string","enum":["en","es","de","ja","vi","pt-BR","pt-PT","zh-CN","zh-TW","nl","tl","fr","it","pl","ru","ar","ro"]},"category":{"type":"string","enum":["focus","productivity","wellbeing","habits","adhd","other"]}},"required":["name","description"]},"CourseRating":{"type":"object","properties":{"user_id":{"type":"string"},"course_id":{"type":"string"},"rating":{"type":"number"},"review":{"type":"string"},"course":{"$ref":"#/components/schemas/Course"},"user":{"$ref":"#/components/schemas/User"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["user_id","course_id","rating"]},"CourseEnrolment":{"type":"object","properties":{"finished":{"type":"boolean"},"user_id":{"type":"string"},"course_id":{"type":"string"},"user":{"$ref":"#/components/schemas/User"},"course":{"$ref":"#/components/schemas/Course"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["finished","user_id","course_id"]},"Course":{"type":"object","properties":{"author_id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"is_hidden":{"type":"boolean"},"deleted":{"type":"boolean"},"language":{"enum":["en","es","de","ja","vi","pt-BR","pt-PT","zh-CN","zh-TW","nl","tl","fr","it","pl","ru","ar","ro"],"type":"string"},"platform":{"enum":["web","mac","win","ios","android"],"type":"string"},"category":{"enum":["focus","productivity","wellbeing","habits","adhd","other"],"type":"string"},"author":{"$ref":"#/components/schemas/User"},"lessonCompletions":{"type":"array","items":{"$ref":"#/components/schemas/LessonCompletion"}},"lessons":{"type":"array","items":{"$ref":"#/components/schemas/Lesson"}},"ratings":{"type":"array","items":{"$ref":"#/components/schemas/CourseRating"}},"enrollments":{"type":"array","items":{"$ref":"#/components/schemas/CourseEnrolment"}},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["author_id","name","description","is_hidden","deleted","language","platform","category"]},"Lesson":{"type":"object","properties":{"course_id":{"type":"string"},"title":{"type":"string"},"content":{"type":"string"},"url":{"type":"string"},"sort_order":{"type":"number"},"deleted":{"type":"boolean"},"course":{"$ref":"#/components/schemas/Course"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["course_id","title","content","url","sort_order","deleted"]},"LessonCompletion":{"type":"object","properties":{"status":{"type":"string","enum":["SELF_TAUGHT","TUTORIAL"]},"lesson_id":{"type":"string"},"course_id":{"type":"string"},"user_id":{"type":"string"},"lesson":{"$ref":"#/components/schemas/Lesson"},"course":{"$ref":"#/components/schemas/Course"},"user":{"$ref":"#/components/schemas/User"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["status","lesson_id","course_id","user_id"]},"UpdateCourseDto":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"language":{"type":"string","enum":["en","es","de","ja","vi","pt-BR","pt-PT","zh-CN","zh-TW","nl","tl","fr","it","pl","ru","ar","ro"]}},"required":["name","description"]},"DeleteCourseDto":{"type":"object","properties":{"deleted":{"type":"boolean"}},"required":["deleted"]},"UpdateCourseHideDto":{"type":"object","properties":{"should_hide":{"type":"boolean"}},"required":["should_hide"]},"CreateCourseRatingDto":{"type":"object","properties":{"rating":{"type":"number","maximum":5,"minimum":1},"review":{"type":"string","maxLength":500},"course_id":{"type":"string"}},"required":["rating","course_id"]},"CreateCourseEnrolmentDto":{"type":"object","properties":{"course_id":{"type":"string"}},"required":["course_id"]},"UpdateCourseEnrolmentDto":{"type":"object","properties":{"course_id":{"type":"string"},"finished":{"type":"boolean"}},"required":["course_id","finished"]},"SyncPlatformCoursesDto":{"type":"object","properties":{"platform":{"enum":["web","mac","win","ios","android"],"type":"string","default":"web"},"is_internal_tester":{"type":"boolean","description":"Set by the mobile app on internal-tester builds only. Only ever flips the user flag false -> true."},"internal_tester_source":{"enum":["build_flag","ios_testflight","android_non_play"],"type":"string","description":"Why the mobile app considers this install an internal tester. Persisted when the flag first flips."}},"required":["platform"]},"CreateDiscussionThreadDto":{"type":"object","properties":{"title":{"type":"string","maxLength":255,"example":"How do I schedule a routine across time zones?"},"body":{"type":"string","maxLength":5000,"example":"I travel a lot and my morning routine keeps firing at the wrong local time."}},"required":["title"]},"CreateDiscussionReplyDto":{"type":"object","properties":{"body":{"type":"string","maxLength":5000,"example":"Set your routine to follow device time and it will re-anchor when you land."}},"required":["body"]},"UpsertLessonDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"content":{"type":"string"},"url":{"type":"string"},"sort_order":{"type":"number","minimum":0}},"required":["title","content","url","sort_order"]},"UpsertLessonsDto":{"type":"object","properties":{"course_id":{"type":"string"},"lessons":{"type":"array","items":{"$ref":"#/components/schemas/UpsertLessonDto"}}},"required":["course_id","lessons"]},"CreateLessonCompletionDto":{"type":"object","properties":{"status":{"enum":["SELF_TAUGHT","TUTORIAL"],"type":"string","default":"TUTORIAL"},"course_id":{"type":"string"},"lesson_id":{"type":"string"}},"required":["course_id","lesson_id"]},"DeleteLessonDto":{"type":"object","properties":{"course_id":{"type":"string"},"lesson_id":{"type":"string"}},"required":["course_id","lesson_id"]},"CommonAppsResponseDto":{"type":"object","properties":{"version":{"type":"number","description":"Bumped whenever an entry changes, so clients can refresh a cached copy"},"apps":{"description":"Well-known apps and their platform identities","type":"array","items":{"type":"object"}}},"required":["version","apps"]},"NotifyLogsUploadSuccessDto":{"type":"object","properties":{"feedback_message":{"type":"string"},"app_platform":{"type":"string"},"app_version":{"type":"string"},"contact_email":{"type":"string","format":"email","maxLength":254},"uploaded_file_url":{"type":"string","format":"uri"}},"required":["feedback_message","app_platform","app_version","uploaded_file_url"]},"BrowserBookmarkResponseDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"parent_id":{"type":"string","nullable":true,"format":"uuid","description":"Null for a top-level item"},"kind":{"enum":["bookmark","folder"],"type":"string"},"client_id":{"type":"string","nullable":true},"title":{"type":"string"},"url":{"type":"string","nullable":true,"description":"Null exactly when kind is folder"},"position":{"type":"number","description":"Sort key among siblings; order by position, then id"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"deleted_at":{"type":"string","nullable":true,"format":"date-time","description":"Set on a deleted item; only the sync feed returns deleted items"}},"required":["id","parent_id","kind","client_id","title","url","position","created_at","updated_at","deleted_at"]},"BrowserBookmarkSyncResponseDto":{"type":"object","properties":{"items":{"description":"Oldest change first","type":"array","items":{"$ref":"#/components/schemas/BrowserBookmarkResponseDto"}},"next_cursor":{"type":"string","description":"Pass as `cursor` on the next request; store it once has_more is false"},"has_more":{"type":"boolean","description":"True when another page is waiting; request it straight away with next_cursor"}},"required":["items","next_cursor","has_more"]},"ImportBrowserBookmarkItemDto":{"type":"object","properties":{"client_id":{"type":"string","maxLength":255,"description":"The client's own id for the item (e.g. Chrome's node GUID). Unique among the user's live items."},"client_parent_id":{"type":"string","nullable":true,"minLength":1,"maxLength":255,"description":"client_id of the folder this item sits in: an item in this request, or one imported by an earlier request. Omit or null to place it directly in the import target."},"kind":{"enum":["bookmark","folder"],"type":"string"},"title":{"type":"string","maxLength":1024,"description":"May be empty, as in Chrome. Stored encrypted."},"url":{"type":"string","maxLength":8192,"description":"Required for a bookmark, rejected for a folder. Any scheme. Stored encrypted.","example":"https://example.com/"},"position":{"type":"number","minimum":-1000000000000,"maximum":1000000000000,"description":"Sort key among siblings; omitted means after the folder's live children and any earlier explicit position, in request order"}},"required":["client_id","kind","title"]},"ImportBrowserBookmarksDto":{"type":"object","properties":{"parent_id":{"type":"string","nullable":true,"format":"uuid","description":"Existing folder to import into; omit or null for the top level"},"items":{"minItems":1,"maxItems":500,"type":"array","items":{"$ref":"#/components/schemas/ImportBrowserBookmarkItemDto"}}},"required":["items"]},"ImportBrowserBookmarksResponseDto":{"type":"object","properties":{"created":{"type":"number","description":"Items this request inserted"},"existing":{"type":"number","description":"Items skipped because a live item with the same client_id already existed"},"items":{"description":"Every requested item as stored, in request order","type":"array","items":{"$ref":"#/components/schemas/BrowserBookmarkResponseDto"}}},"required":["created","existing","items"]},"CreateBrowserBookmarkDto":{"type":"object","properties":{"kind":{"enum":["bookmark","folder"],"type":"string"},"title":{"type":"string","maxLength":1024,"description":"May be empty, as in Chrome. Stored encrypted."},"url":{"type":"string","maxLength":8192,"description":"Required for a bookmark, rejected for a folder. Any scheme. Stored encrypted.","example":"https://example.com/"},"parent_id":{"type":"string","nullable":true,"format":"uuid","description":"Folder to create the item in; omit or null for the top level"},"position":{"type":"number","minimum":-1000000000000,"maximum":1000000000000,"description":"Sort key among siblings; omitted means after the last sibling"},"client_id":{"type":"string","maxLength":255,"description":"The client's own id for the item (e.g. Chrome's node GUID). Unique among the user's live items."}},"required":["kind","title"]},"UpdateBrowserBookmarkDto":{"type":"object","properties":{"title":{"type":"string","maxLength":1024,"description":"May be empty, as in Chrome. Stored encrypted."},"url":{"type":"string","maxLength":8192,"description":"Required for a bookmark, rejected for a folder. Any scheme. Stored encrypted.","example":"https://example.com/"},"parent_id":{"type":"string","nullable":true,"format":"uuid","description":"Move into this folder; null moves to the top level, omitted leaves it where it is"},"position":{"type":"number","minimum":-1000000000000,"maximum":1000000000000,"description":"New sort key among siblings"}}},"GenerateChatBotResponseDto":{"type":"object","properties":{"chat":{"type":"object"},"language":{"type":"string"}},"required":["chat","language"]},"ManagedWindowDto":{"type":"object","properties":{"days_of_week":{"type":"array","items":{"type":"object"}},"start_time":{"type":"string"},"end_time":{"type":"string"},"all_day":{"type":"boolean"}},"required":["days_of_week","start_time","end_time"]},"ManagedExceptionDto":{"type":"object","properties":{"url":{"type":"string"},"include_subdomains":{"type":"boolean"},"reason":{"type":"string"},"expires_at":{"type":"string"}},"required":["url","include_subdomains"]},"ManagedBlockedSiteDto":{"type":"object","properties":{"value":{"type":"string"},"include_subdomains":{"type":"boolean"},"reason":{"type":"string"}},"required":["value","include_subdomains"]},"ManagedBlockedAppDto":{"type":"object","properties":{"platform":{"enum":["macos","windows","android","ios"],"type":"string"},"identifier":{"type":"string","minLength":1},"name":{"type":"string"}},"required":["platform","identifier","name"]},"ManagedExcludedDateRangeDto":{"type":"object","properties":{"start_date":{"type":"string"},"end_date":{"type":"string"}},"required":["start_date","end_date"]},"ManagedPolicyDto":{"type":"object","properties":{"name":{"type":"string","maxLength":120},"time_zone":{"type":"string","maxLength":80},"is_enabled":{"type":"boolean"},"windows":{"maxItems":28,"type":"array","items":{"$ref":"#/components/schemas/ManagedWindowDto"}},"blocked_categories":{"uniqueItems":true,"type":"array","items":{"type":"string"}},"allowlist":{"maxItems":250,"type":"array","items":{"$ref":"#/components/schemas/ManagedExceptionDto"}},"blocklist":{"type":"array","items":{"$ref":"#/components/schemas/ManagedBlockedSiteDto"}},"blocked_apps":{"type":"array","items":{"$ref":"#/components/schemas/ManagedBlockedAppDto"}},"block_ip_address_urls":{"type":"boolean"},"excluded_dates":{"maxItems":120,"type":"array","items":{"$ref":"#/components/schemas/ManagedExcludedDateRangeDto"}},"unknown_action":{"type":"string","enum":["allow","block"]},"unavailable_action":{"type":"string","enum":["allow","block"]}},"required":["name","time_zone","is_enabled","windows","blocked_categories","allowlist","blocklist","blocked_apps","block_ip_address_urls","excluded_dates","unknown_action","unavailable_action"]},"UpdateManagedPolicyDto":{"type":"object","properties":{"name":{"type":"string","maxLength":120},"time_zone":{"type":"string","maxLength":80},"is_enabled":{"type":"boolean"},"windows":{"maxItems":28,"type":"array","items":{"$ref":"#/components/schemas/ManagedWindowDto"}},"blocked_categories":{"uniqueItems":true,"type":"array","items":{"type":"string"}},"allowlist":{"maxItems":250,"type":"array","items":{"$ref":"#/components/schemas/ManagedExceptionDto"}},"blocklist":{"type":"array","items":{"$ref":"#/components/schemas/ManagedBlockedSiteDto"}},"blocked_apps":{"type":"array","items":{"$ref":"#/components/schemas/ManagedBlockedAppDto"}},"block_ip_address_urls":{"type":"boolean"},"excluded_dates":{"maxItems":120,"type":"array","items":{"$ref":"#/components/schemas/ManagedExcludedDateRangeDto"}},"unknown_action":{"enum":["allow","block"],"type":"string"},"unavailable_action":{"enum":["allow","block"],"type":"string"},"expected_revision":{"type":"number","minimum":1}},"required":["name","time_zone","is_enabled","windows","blocked_categories","allowlist","blocklist","blocked_apps","block_ip_address_urls","excluded_dates","unknown_action","unavailable_action","expected_revision"]},"RevisionDto":{"type":"object","properties":{"expected_revision":{"type":"number","minimum":1}},"required":["expected_revision"]},"UpdateManagedYearLevelDto":{"type":"object","properties":{"year_level":{"type":"string","nullable":true,"maxLength":40},"student_ids":{"uniqueItems":true,"minItems":1,"type":"array","items":{"type":"string","format":"uuid"}}},"required":["year_level","student_ids"]},"AssignManagedPolicyDto":{"type":"object","properties":{"policy_id":{"type":"string","format":"uuid"},"student_ids":{"uniqueItems":true,"minItems":1,"maxItems":500,"type":"array","items":{"type":"string","format":"uuid"}},"replace_existing":{"type":"boolean"}},"required":["policy_id","student_ids"]},"InviteManagedParentDto":{"type":"object","properties":{"email":{"type":"string","maxLength":255,"format":"email"}},"required":["email"]},"CreateSettingsEditDto":{"type":"object","properties":{"device_id":{"type":"string","format":"uuid"},"scope":{"uniqueItems":true,"minItems":1,"type":"array","items":{"type":"string"}},"base_revision":{"type":"number","minimum":1}},"required":["device_id","scope","base_revision"]},"ProposeSettingsEditDto":{"type":"object","properties":{"device_id":{"type":"string","format":"uuid"},"changes":{"type":"object"}},"required":["device_id","changes"]},"CommitSettingsEditDto":{"type":"object","properties":{"expected_revision":{"type":"number","minimum":1},"changes_hash":{"type":"string","pattern":"^[a-f0-9]{64}$"}},"required":["expected_revision","changes_hash"]},"TestManagedUrlDto":{"type":"object","properties":{"url":{"type":"string","minLength":1,"maxLength":4096},"tab_title":{"type":"string","maxLength":1000},"at":{"type":"string"}},"required":["url"]},"CheckManagedUrlDto":{"type":"object","properties":{"url":{"type":"string","minLength":1,"maxLength":4096},"tab_title":{"type":"string","maxLength":1000},"page_text":{"type":"string","maxLength":12000},"device_id":{"type":"string","format":"uuid"},"event_id":{"type":"string","format":"uuid"}},"required":["url"]},"TestManagedAppDto":{"type":"object","properties":{"platform":{"enum":["macos","windows","android","ios"],"type":"string"},"at":{"type":"string"},"identifier":{"type":"string","minLength":1}},"required":["platform","identifier"]},"CheckManagedAppDto":{"type":"object","properties":{"platform":{"enum":["macos","windows","android","ios"],"type":"string"},"identifier":{"type":"string","minLength":1}},"required":["platform","identifier"]},"OfflineViolationDto":{"type":"object","properties":{"event_id":{"type":"string","format":"uuid"},"device_id":{"type":"string","format":"uuid"},"policy_id":{"type":"string","format":"uuid"},"policy_revision":{"type":"number","minimum":1},"url":{"type":"string","minLength":1,"maxLength":4096},"category_ids":{"type":"array","items":{"type":"string"}},"observed_at":{"type":"string"}},"required":["event_id","device_id","policy_id","policy_revision","url","category_ids","observed_at"]},"OfflineViolationsDto":{"type":"object","properties":{"events":{"minItems":1,"maxItems":50,"type":"array","items":{"$ref":"#/components/schemas/OfflineViolationDto"}}},"required":["events"]},"CreateManagedAppealDto":{"type":"object","properties":{"explanation":{"type":"string","minLength":10,"maxLength":2000}},"required":["explanation"]},"AppliedManagedPolicyDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["school","home"]},"revision":{"type":"number","minimum":1}},"required":["id","kind","revision"]},"ManagedDeviceReceiptDto":{"type":"object","properties":{"permission_status":{"enum":["ready","missing","unknown"],"type":"string"},"sync_status":{"enum":["online","offline","error"],"type":"string"},"enforcement_status":{"enum":["enforcing","inactive","recovery","error"],"type":"string"},"device_id":{"type":"string","format":"uuid"},"snapshot_id":{"type":"string","pattern":"^[a-f0-9]{64}$"},"applied_policies":{"maxItems":2,"type":"array","items":{"$ref":"#/components/schemas/AppliedManagedPolicyDto"}},"client_version":{"type":"string","minLength":1,"maxLength":80},"platform":{"type":"string","enum":["macos","windows"]},"clock_status":{"type":"string","enum":["trusted","uncertain","rollback_detected"]},"observed_at":{"type":"string"}},"required":["permission_status","sync_status","enforcement_status","device_id","snapshot_id","applied_policies","client_version","platform","clock_status","observed_at"]},"MinimalOfflineViolationDto":{"type":"object","properties":{"kind":{"description":"`app`: an attempt to open a blocked app. `domain` then carries the app identifier (bundle id,\npackage name or .exe name) and `resource_hash` is sha256(\"app:\" + lowercased identifier).\nOmitted means `website`, so older clients keep working.","enum":["website","app"],"type":"string","default":"website"},"app_platform":{"description":"Optional app details for `kind: 'app'`, shown in school history (\"Tried to open Steam\").","enum":["macos","windows","android","ios"],"type":"string"},"reason":{"description":"Why the device blocked it, when that is not a category. `ip_address_url`: the policy's\n`block_ip_address_urls` option blocked a website opened by IP address; only valid for a website\nwhose `domain` is a blockable IP with no `category_ids`, and recorded as that decision. Omitted\nrecords the generic `device_reported_block`.","enum":["ip_address_url"],"type":"string"},"event_id":{"type":"string","format":"uuid"},"device_id":{"type":"string","format":"uuid"},"policy_id":{"type":"string","format":"uuid"},"policy_revision":{"type":"number","minimum":1},"domain":{"type":"string","minLength":1,"maxLength":253},"resource_hash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"url":{"type":"string","minLength":1,"maxLength":4096},"category_ids":{"type":"array","items":{"type":"string"}},"observed_at":{"type":"string"},"app_name":{"type":"string"}},"required":["event_id","device_id","policy_id","policy_revision","domain","resource_hash","category_ids","observed_at"]},"MinimalOfflineViolationsDto":{"type":"object","properties":{"events":{"minItems":1,"maxItems":50,"type":"array","items":{"$ref":"#/components/schemas/MinimalOfflineViolationDto"}}},"required":["events"]},"CreateSurveyDto":{"type":"object","properties":{"answer_type":{"enum":["CHOICES_NUMBER","CHOICES_BOOLEAN","TEXT","TEXT_AND_RATING"],"type":"string","default":"TEXT"},"question":{"type":"string"},"choices":{"type":"array","items":{"type":"string"}}},"required":["answer_type","question"]},"UpdateSurveyDto":{"type":"object","properties":{"survey_id":{"type":"string","format":"uuid"},"question":{"type":"string"},"choices":{"type":"array","items":{"type":"string"}}},"required":["survey_id","question"]},"CreateSurveyAnswerMetaDto":{"type":"object","properties":{"feature":{"type":"string"},"device":{"type":"string"},"operating_system":{"type":"string"},"version":{"type":"string"}},"required":["feature","device","operating_system","version"]},"CreateSurveyAnswerDto":{"type":"object","properties":{"rating":{"type":"number","minimum":1,"maximum":5},"metadata":{"$ref":"#/components/schemas/CreateSurveyAnswerMetaDto"},"reply":{"type":"string"},"completed":{"type":"boolean"}},"required":["metadata","reply"]},"Survey":{"type":"object","properties":{"question":{"type":"string"},"choices":{"type":"array","items":{"type":"string"}},"answer_type":{"enum":["CHOICES_NUMBER","CHOICES_BOOLEAN","TEXT","TEXT_AND_RATING"],"type":"string"},"creator":{"type":"string"},"user":{"$ref":"#/components/schemas/User"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["question","answer_type","creator"]},"SurveyAnswer":{"type":"object","properties":{"reply":{"type":"string"},"rating":{"type":"number"},"survey_id":{"type":"string"},"user_id":{"type":"string"},"completed":{"type":"boolean"},"survey":{"$ref":"#/components/schemas/Survey"},"user":{"$ref":"#/components/schemas/User"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["reply","survey_id","user_id","completed"]},"CustomerLookupDto":{"type":"object","properties":{"ticketId":{"type":"string"}},"required":["ticketId"]},"ActionTokenDto":{"type":"object","properties":{"ticketId":{"type":"string"},"operation":{"type":"string","enum":["cancel_subscription"]}},"required":["ticketId","operation"]},"CancelSubscriptionDto":{"type":"object","properties":{"actionToken":{"type":"string"},"reason":{"type":"string","enum":["customer_request","duplicate_subscription","billing_error","other"]}},"required":["actionToken","reason"]},"CreateNoteTagDto":{"type":"object","properties":{"text":{"type":"string","maxLength":255},"id":{"type":"string","format":"uuid"},"color":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["text"]},"CreateProjectNoteDto":{"type":"object","properties":{"title":{"type":"string","maxLength":255},"is_private":{"type":"boolean","default":false,"description":"True keeps the note visible only to its author. Omitted creates a shared note."},"content":{"type":"object","additionalProperties":true,"description":"TipTap/ProseMirror document JSON. Optional — a note can start empty."},"tags":{"description":"Tags as personal notes take them: an existing tag of this project by id, or a new one by text.","type":"array","items":{"$ref":"#/components/schemas/CreateNoteTagDto"}}},"required":["title"]},"ProjectNoteTagResponseDto":{"type":"object","properties":{"id":{"type":"string"},"text":{"type":"string"},"color":{"type":"string"}},"required":["id","text"]},"ProjectNoteResponseDto":{"type":"object","properties":{"id":{"type":"string"},"project_id":{"type":"string"},"created_by":{"type":"string"},"title":{"type":"string"},"content":{"type":"object","additionalProperties":true,"nullable":true,"description":"TipTap/ProseMirror document JSON. Present on single-note responses; omitted\nfrom list responses (which only return metadata)."},"is_private":{"type":"boolean","description":"True when only the author (`created_by`) can see the note. Only the author may change it."},"archived_at":{"format":"date-time","type":"string","nullable":true,"description":"Set while the note is archived (filed away, still readable); null when active."},"pinned_at":{"format":"date-time","type":"string","nullable":true,"description":"When the requesting user pinned the note; null when they haven't. Pins are per user."},"created_at":{"type":"string"},"updated_at":{"type":"string"},"tags":{"description":"The note's tags, in the same shape as a personal note's.","type":"array","items":{"$ref":"#/components/schemas/ProjectNoteTagResponseDto"}}},"required":["id","project_id","title","is_private","tags"]},"UpdateProjectNoteDto":{"type":"object","properties":{"title":{"type":"string","maxLength":255},"content":{"type":"object","additionalProperties":true,"description":"TipTap/ProseMirror document JSON snapshot from the editor's autosave."},"archived":{"type":"boolean","description":"True archives the note, false restores it. The timestamp stays\nserver-authoritative — clients never send `archived_at`."},"tags":{"description":"Replaces the note's tags when present (an empty list removes them all); omitted leaves them.","type":"array","items":{"$ref":"#/components/schemas/CreateNoteTagDto"}},"pinned":{"type":"boolean","description":"True pins the note for the caller, false unpins it. Pins are per user, so this never reorders a\nteammate's list, and the timestamp is the server's — clients never send `pinned_at`."},"is_private":{"type":"boolean","description":"True makes the note visible only to its author, false shares it with the project again. Only the\nauthor may change it; sending the note's current value is a no-op anyone can make."}}},"NoteDocResponseDto":{"type":"object","properties":{"yjs_state":{"type":"string","nullable":true,"description":"Base64-encoded Y.Doc, or null if the note has no CRDT state yet."},"content":{"type":"object","additionalProperties":true,"nullable":true,"description":"Rendered ProseMirror JSON snapshot, used to seed a fresh Y.Doc."},"updated_at":{"type":"string","description":"When the document was last persisted."}},"required":["yjs_state","content"]},"SaveNoteDocDto":{"type":"object","properties":{"yjs_state":{"type":"string","format":"base64","maxLength":6990508},"content":{"type":"object","additionalProperties":true}},"required":["yjs_state"]},"RealtimeAuthDto":{"type":"object","properties":{"socket_id":{"type":"string","description":"The Pusher connection's socket id, supplied by the client SDK."}},"required":["socket_id"]},"RealtimeAuthResponseDto":{"type":"object","properties":{"auth":{"type":"string","description":"Signed Pusher auth token for the requested channel.","example":"app-key:signature"},"channel_data":{"type":"string","description":"JSON-encoded Pusher presence metadata.","example":"{\"user_id\":\"123e4567-e89b-12d3-a456-426614174000\",\"user_info\":{}}"}},"required":["auth"]},"CreateNoteCommentDto":{"type":"object","properties":{"body":{"type":"string","maxLength":10000}},"required":["body"]},"NoteCommentResponseDto":{"type":"object","properties":{"id":{"type":"string"},"note_id":{"type":"string"},"created_by":{"type":"string"},"body":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","note_id","body"]},"EmbeddableTaskResponseDto":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"status":{"type":"string"},"due_date":{"type":"string"},"custom_status_id":{"type":"string"},"icon":{"type":"string"}},"required":["id","title","status"]},"CreateNoteImageUploadDto":{"type":"object","properties":{"content_type":{"type":"string","maxLength":100,"description":"MIME type the client will upload with","enum":["image/png","image/jpeg","image/gif","image/webp"]},"file_size":{"type":"number","minimum":1,"description":"File size in bytes","maximum":10485760}},"required":["content_type","file_size"]},"NoteImageUploadResponseDto":{"type":"object","properties":{"image_id":{"type":"string","description":"Id the image will have once confirmed; use it in the complete call"},"reference":{"type":"string","description":"Embed reference to write into the note body once the upload is confirmed"},"upload_url":{"type":"string","description":"Presigned URL to PUT the raw file bytes to"},"upload_headers":{"type":"object","additionalProperties":{"type":"string"},"description":"Headers the PUT must send exactly (the signature covers them)","example":{"Content-Type":"image/png"}},"upload_url_expires_at":{"type":"string","description":"When upload_url stops working (ISO 8601)"}},"required":["image_id","reference","upload_url","upload_headers","upload_url_expires_at"]},"CompleteNoteImageUploadDto":{"type":"object","properties":{"file_name":{"type":"string","maxLength":255,"description":"Original file name, for display and \"save image\""}}},"NoteImageResponseDto":{"type":"object","properties":{"id":{"type":"string"},"note_id":{"type":"string","nullable":true,"description":"Set for an image in a personal note, otherwise null"},"project_note_id":{"type":"string","nullable":true,"description":"Set for an image in a project note, otherwise null"},"kind":{"enum":["image","audio","pdf"],"type":"string","description":"image, audio or pdf; matches the endpoints it was uploaded to"},"reference":{"type":"string","description":"Embed reference used in the note body: fb-note-image://<id>, fb-note-audio://<id> or fb-note-pdf://<id>"},"file_name":{"type":"string","nullable":true},"content_type":{"type":"string","description":"Detected from the file signature: image/png, image/jpeg, image/gif or image/webp for images; audio/mp4, audio/mpeg, audio/webm, audio/ogg or audio/wav for audio; application/pdf for PDFs"},"file_size":{"type":"number","description":"Size in bytes"},"uploaded_by":{"type":"string","nullable":true,"description":"Null when the uploader has since deleted their account"},"url":{"type":"string","description":"Short-lived signed GET URL for the file bytes"},"url_expires_at":{"type":"string","description":"When url stops working (ISO 8601)"},"created_at":{"type":"string"}},"required":["id","note_id","project_note_id","kind","reference","file_name","content_type","file_size","uploaded_by","url","url_expires_at","created_at"]},"CreateNoteAudioUploadDto":{"type":"object","properties":{"content_type":{"type":"string","maxLength":100,"description":"MIME type the client will upload with","enum":["audio/mp4","audio/mpeg","audio/webm","audio/ogg","audio/wav","audio/x-m4a","audio/m4a","audio/x-wav","audio/wave","audio/vnd.wave"]},"file_size":{"type":"number","minimum":1,"description":"File size in bytes","maximum":78643200}},"required":["content_type","file_size"]},"CreateNotePdfUploadDto":{"type":"object","properties":{"content_type":{"type":"string","maxLength":100,"description":"MIME type the client will upload with","enum":["application/pdf"]},"file_size":{"type":"number","minimum":1,"description":"File size in bytes","maximum":104857600}},"required":["content_type","file_size"]},"PortfolioProjectResponseDto":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"due_date":{"type":"string","nullable":true,"description":"ISO timestamp of the deadline the risk is judged against, or null when undated. For a date-only\ndue date this is the end of that day in the user's zone, which can differ from the stored\ninstant (GET /projects) when the row was saved in a stale device offset."},"importance":{"type":"number"},"outcome":{"type":"number","nullable":true,"description":"Outcome significance on the 1..10 wire scale; null until explicitly rated."},"required_hours":{"type":"number"},"risk_score":{"type":"number"},"bucket":{"type":"string","enum":["critical","at_risk","on_track","no_deadline"]},"deficit_hours":{"type":"number","description":"Hours that won't fit before the due date. When the due date is inside the planning horizon this is\nthe simulated per-day deficit (hours landing after the deadline plus hours that never fit); beyond\nthe horizon it is the aggregate shortfall of all work due by then, which can include other projects'."},"days_until_due":{"type":"number","nullable":true},"latest_start":{"type":"string","nullable":true},"badges":{"type":"array","items":{"type":"string","enum":["overcommitted","start_now","sacrifice","unscheduled","pushed_back"]}},"top_priority_task":{"nullable":true,"description":"Highest-TOP incomplete task (SMART order), or null when the project has none.","type":"object","allOf":[{"$ref":"#/components/schemas/TopPriorityTaskDto"}]},"scheduled_hours":{"type":"number"},"unscheduled_hours":{"type":"number"},"projected_completion_date":{"type":"string","nullable":true,"description":"Local 'YYYY-MM-DD' the project is likely done, or null when it spills past the horizon. Always\nafter the due date when `plan_feasible` is false: an overrun later on the due day itself reports the\nday after, even when that is the day after the last simulated day or differs from\n`pushed_tasks[].projected_date`. A project due beyond the horizon can show a positive aggregate\n`deficit_hours` without moving this date."},"plan_feasible":{"type":"boolean"},"pushed_task_ids":{"type":"array","items":{"type":"string"}}},"required":["id","name","due_date","importance","outcome","required_hours","risk_score","bucket","deficit_hours","days_until_due","latest_start","badges","top_priority_task","scheduled_hours","unscheduled_hours","projected_completion_date","plan_feasible","pushed_task_ids"]},"PortfolioPushedTaskDto":{"type":"object","properties":{"id":{"type":"string"},"project_id":{"type":"string","nullable":true},"planned_date":{"type":"string"},"projected_date":{"type":"string","nullable":true,"description":"Local 'YYYY-MM-DD' the task is projected to finish, or null when it spills past the horizon."}},"required":["id","project_id","planned_date","projected_date"]},"PortfolioResponseDto":{"type":"object","properties":{"projects":{"type":"array","items":{"$ref":"#/components/schemas/PortfolioProjectResponseDto"}},"due_this_week":{"type":"array","items":{"type":"string"}},"start_now":{"type":"array","items":{"type":"string"}},"overcommitted":{"type":"boolean"},"total_required_hours":{"type":"number"},"total_available_hours":{"type":"number"},"plan_feasible":{"type":"boolean"},"pushed_tasks":{"type":"array","items":{"$ref":"#/components/schemas/PortfolioPushedTaskDto"}}},"required":["projects","due_this_week","start_now","overcommitted","total_required_hours","total_available_hours","plan_feasible","pushed_tasks"]},"ForecastProjectAllocation":{"type":"object","properties":{"project_id":{"type":"string","nullable":true,"description":"Null for to-dos that belong to no project."},"project_name":{"type":"string","nullable":true},"hours":{"type":"number"}},"required":["project_id","project_name","hours"]},"ForecastDay":{"type":"object","properties":{"date":{"type":"string","description":"Local date (YYYY-MM-DD) in the user's timezone."},"awake_hours":{"type":"number","description":"Waking hours still ahead. 0 unless has_capacity_breakdown."},"sleep_hours":{"type":"number","description":"24 − awake_hours (on day 0 this includes the part of today already elapsed). 0 unless has_capacity_breakdown."},"events_hours":{"type":"number","description":"Busy calendar hours (synced and client-reported), clipped to the waking window in dynamic mode."},"habits_hours":{"type":"number","description":"Morning + evening routine hours still ahead. 0 unless has_capacity_breakdown."},"available_hours":{"type":"number","description":"Free hours for project work: awake − events − habits (dynamic) or grid − events − elapsed (manual)."},"allocated_hours":{"type":"number","description":"Hours of available time the Day Plan places on this day (projects and project-less to-dos)."},"unallocated_hours":{"type":"number","description":"available_hours − allocated_hours."},"allocations":{"type":"array","items":{"$ref":"#/components/schemas/ForecastProjectAllocation"}}},"required":["date","awake_hours","sleep_hours","events_hours","habits_hours","available_hours","allocated_hours","unallocated_hours","allocations"]},"ForecastProjectSummary":{"type":"object","properties":{"project_id":{"type":"string"},"project_name":{"type":"string"},"due_date":{"type":"string","nullable":true,"description":"ISO timestamp of the resolved deadline (same as GET /portfolio's `due_date`), or null when undated."},"required_hours":{"type":"number","description":"Outstanding hours across the project's not-completed to-dos."},"planned_hours":{"type":"number","description":"Hours of to-dos that have a planned_date (in the Day Plan)."},"allocated_hours":{"type":"number","description":"Hours placed within the horizon."},"remaining_hours":{"type":"number","description":"required_hours − allocated_hours: work that did not fit inside the horizon."},"unschedulable_hours":{"type":"number","description":"Hours that land after the due date, plus hours that never fit when the due date is inside the\nhorizon — the \"you cannot finish this in time\" signal. 0 for undated projects and for projects\ndue after the horizon."}},"required":["project_id","project_name","due_date","required_hours","planned_hours","allocated_hours","remaining_hours","unschedulable_hours"]},"PortfolioForecastResponseDto":{"type":"object","properties":{"days":{"type":"array","items":{"$ref":"#/components/schemas/ForecastDay"}},"projects":{"type":"array","items":{"$ref":"#/components/schemas/ForecastProjectSummary"}},"total_available_hours":{"type":"number"},"total_required_hours":{"type":"number"},"total_allocated_hours":{"type":"number"},"total_unschedulable_hours":{"type":"number"},"has_capacity_breakdown":{"type":"boolean","description":"Whether the breakdown fields (awake/sleep/habits) are populated — true only in dynamic mode."},"horizon_days":{"type":"number","description":"Number of days covered by the forecast (the resolved horizon)."}},"required":["days","projects","total_available_hours","total_required_hours","total_allocated_hours","total_unschedulable_hours","has_capacity_breakdown","horizon_days"]},"PortfolioSettingsResponseDto":{"type":"object","properties":{"weekly_capacity_hours":{"description":"Stored manual override grid (Mon=0..Sun=6). Used only when use_dynamic_capacity is false.","type":"array","items":{"type":"number"}},"planning_horizon_days":{"type":"number"},"use_dynamic_capacity":{"type":"boolean"},"effective_weekly_capacity_hours":{"description":"Capacity actually used by the portfolio: dynamic (awake window − routines − events) or the grid.","type":"array","items":{"type":"number"}},"current_week_capacity":{"description":"This week's per-day breakdown for the summary + day drilldown; empty when dynamic is off.","type":"array","items":{"type":"object"}}},"required":["weekly_capacity_hours","planning_horizon_days","use_dynamic_capacity","effective_weekly_capacity_hours","current_week_capacity"]},"UpdatePortfolioSettingsDto":{"type":"object","properties":{"planning_horizon_days":{"type":"number","maximum":90,"minimum":7},"weekly_capacity_hours":{"type":"array","items":{"type":"number","maximum":24,"minimum":0}},"use_dynamic_capacity":{"type":"boolean"}},"required":["planning_horizon_days","weekly_capacity_hours"]},"ReportedBusyIntervalDto":{"type":"object","properties":{"start":{"type":"string"},"end":{"type":"string"}},"required":["start","end"]},"ReportBusyHoursDto":{"type":"object","properties":{"source":{"type":"string","maxLength":64},"intervals":{"type":"array","items":{"$ref":"#/components/schemas/ReportedBusyIntervalDto"}}},"required":["source","intervals"]},"LatestAppVersionResponseDto":{"type":"object","properties":{"minimum_supported_app_version":{"type":"string","nullable":true,"example":"2.0.0","description":"Minimum supported version"},"latest_app_version":{"type":"string","nullable":true,"example":"2.1.0","description":"Latest available version"},"release_notes":{"type":"string","nullable":true,"example":"Bug fixes and performance improvements","description":"Release notes"}},"required":["minimum_supported_app_version","latest_app_version","release_notes"]},"CreateAppVersionDto":{"type":"object","properties":{"operating_system":{"enum":["iOS","Android","MacOS","Windows","Web"],"type":"string","description":"Operating system","example":"iOS"},"semver_string":{"type":"string","pattern":"^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9]+(\\.[a-zA-Z0-9]+)*)?$","example":"2.9.0","description":"Semantic version string"},"is_supported":{"type":"boolean","default":false,"description":"Mark as minimum supported version"},"is_beta_only":{"type":"boolean","default":false,"description":"Only available to beta testers"},"release_notes":{"type":"string","example":"Bug fixes and performance improvements","description":"Release notes"}},"required":["operating_system","semver_string"]},"NoteFolderResponseDto":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"parent_id":{"type":"string","nullable":true},"system_key":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","name","parent_id","system_key","created_at","updated_at"]},"UpsertNoteFolderDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"The folder to rename or move. Omitted to create one."},"name":{"type":"string","description":"Required when creating a folder."},"parent_id":{"type":"object","nullable":true,"description":"The parent folder; null moves the folder to the top level.","format":"uuid"},"system_key":{"type":"string","description":"A client's stable key for a folder it makes itself. Creating with a key the user already has returns that folder unchanged, so every device finds one folder. Only read when creating."}}},"CreateNoteDto":{"type":"object","properties":{"title":{"type":"string","maxLength":500},"body":{"type":"string","maxLength":2000000},"id":{"type":"string","format":"uuid"},"completed_activity_id":{"type":"string","format":"uuid"},"tags":{"type":"array","items":{"$ref":"#/components/schemas/CreateNoteTagDto"}},"embedded_todo_ids":{"type":"array","items":{"type":"string","format":"uuid"}},"is_brain_dump":{"type":"boolean","description":"Marks the user's single brain-dump note. An upsert with is_brain_dump=true and no (known) id updates\nthe existing brain dump rather than creating another one."},"pinned":{"type":"boolean","description":"True pins the note to the top of the owner's list, false unpins it. The timestamp is the server's:\nclients never send `pinned_at`, and pinning a note that is already pinned keeps its original time."},"folder_id":{"type":"string","nullable":true,"description":"Files the note in one of the owner's folders; null takes it out of its folder. Omitted leaves it where it\nis. Read on a create and on a request that only files (or pins) the note, which is not an edit to it; an\nedit's folder_id is ignored, since a client saving the whole note it fetched may send a stale one.","format":"uuid"}}},"NoteFolder":{"type":"object","properties":{"user_id":{"type":"string"},"name":{"type":"string","description":"Encrypted like a note's title: a folder is often named after a meeting or a person."},"parent_id":{"type":"string","nullable":true,"description":"Null for a top-level folder."},"system_key":{"type":"string","nullable":true,"description":"The client's stable key for a folder it makes itself; null for a folder the user made."},"user":{"$ref":"#/components/schemas/User"},"parent":{"description":"Declared only so schema diffs keep the composite ownership key. Never assign it: it shares `user_id`\nwith `user`, so saving through it would write `user_id` from the parent. Set `parent_id` directly.","allOf":[{"$ref":"#/components/schemas/NoteFolder"}]},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["user_id","name","parent_id","system_key"]},"Note":{"type":"object","properties":{"user_id":{"type":"string"},"title":{"type":"string"},"body":{"type":"string"},"completed_activity_id":{"type":"string"},"is_brain_dump":{"type":"boolean"},"pinned_at":{"format":"date-time","type":"string","nullable":true,"description":"When the owner pinned the note to the top of their list; null when it isn't pinned."},"folder_id":{"type":"string","nullable":true,"description":"The folder the note is filed in; null for the user's unfiled notes."},"user":{"$ref":"#/components/schemas/User"},"folder":{"$ref":"#/components/schemas/NoteFolder"},"completed_activity":{"$ref":"#/components/schemas/CompletedActivity"},"tags":{"type":"array","items":{"$ref":"#/components/schemas/NoteTag"}},"embedded_todos":{"type":"array","items":{"$ref":"#/components/schemas/ToDo"}},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["title","is_brain_dump"]},"NoteTag":{"type":"object","properties":{"user_id":{"type":"string"},"user":{"$ref":"#/components/schemas/User"},"text":{"type":"string"},"color":{"type":"string"},"notes":{"type":"array","items":{"$ref":"#/components/schemas/Note"}},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["text"]},"NoteResponseDto":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"body":{"type":"string"},"completed_activity_id":{"type":"string"},"tags":{"type":"array","items":{"$ref":"#/components/schemas/NoteTag"}},"embedded_todo_ids":{"type":"array","items":{"type":"string"}},"is_brain_dump":{"type":"boolean"},"pinned_at":{"format":"date-time","type":"string","nullable":true,"description":"When the note was pinned; null when it isn't."},"folder_id":{"type":"string","nullable":true,"description":"The folder the note is filed in; null when it is in none."},"activity_name":{"type":"string"},"activity_emoji":{"type":"string"},"logged_at":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","title","is_brain_dump","pinned_at","folder_id","created_at","updated_at"]},"CreateNoteGenerationUploadDto":{"type":"object","properties":{"content_type":{"type":"string","maxLength":100,"description":"MIME type of the photo the client will upload","enum":["image/png","image/jpeg","image/webp"]},"file_size":{"type":"number","minimum":1,"description":"File size in bytes, up to 10 MB"}},"required":["content_type","file_size"]},"NoteGenerationUploadResponseDto":{"type":"object","properties":{"image_id":{"type":"string","description":"Id of the uploaded photo; pass it to POST /note/generate"},"upload_url":{"type":"string","description":"Presigned URL to PUT the raw file bytes to"},"upload_headers":{"type":"object","additionalProperties":{"type":"string"},"description":"Headers the PUT must send exactly (the signature covers them)","example":{"Content-Type":"image/jpeg"}},"upload_url_expires_at":{"type":"string","description":"When upload_url stops working (ISO 8601)"}},"required":["image_id","upload_url","upload_headers","upload_url_expires_at"]},"GenerateNoteFromImageDto":{"type":"object","properties":{"image_id":{"type":"string","format":"uuid","description":"image_id returned by POST /note/generate/upload-url"}},"required":["image_id"]},"GenerateNoteFromImageResponseDto":{"type":"object","properties":{"asyncTaskId":{"type":"string","description":"Poll GET /async-task/{id}. When COMPLETED, metadata.aiResponse is the draft note ({ title, body }, body as HTML) for the client to review and save with PUT /note; when FAILED, metadata.failureReason says why."}},"required":["asyncTaskId"]},"ReviseDeckResponseDto":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"note_id":{"type":"string","nullable":true},"project_id":{"type":"string","nullable":true},"card_count":{"type":"number","description":"Live cards in the deck"},"due_count":{"type":"number","description":"Live cards due for review now, plus imported cards never reviewed"},"created_at":{"type":"string"},"updated_at":{"type":"string"},"deleted_at":{"type":"string","nullable":true}},"required":["id","name","note_id","project_id","card_count","due_count","created_at","updated_at","deleted_at"]},"ReviseDeckListResponseDto":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ReviseDeckResponseDto"}},"server_time":{"type":"string","description":"Use as the next updated_since watermark (minus a safety overlap)"}},"required":["items","server_time"]},"CreateReviseDeckDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Client-generated id, so an offline client can create the deck first"},"name":{"type":"string","maxLength":200},"note_id":{"type":"string","nullable":true,"format":"uuid","description":"One of the user's notes this deck belongs to"},"project_id":{"type":"string","nullable":true,"format":"uuid","description":"A project the user owns or is an accepted member of"}},"required":["name"]},"UpdateReviseDeckDto":{"type":"object","properties":{"name":{"type":"string","maxLength":200},"note_id":{"type":"string","nullable":true,"format":"uuid","description":"null unlinks the note"},"project_id":{"type":"string","nullable":true,"format":"uuid","description":"null unlinks the project"}}},"RevisePreviewDueAtDto":{"type":"object","properties":{"no_idea":{"type":"string"},"again":{"type":"string"},"hard":{"type":"string"},"good":{"type":"string"},"easy":{"type":"string"}},"required":["no_idea","again","hard","good","easy"]},"ReviseCardResponseDto":{"type":"object","properties":{"id":{"type":"string"},"deck_id":{"type":"string","nullable":true},"front":{"type":"string"},"back":{"type":"string"},"source_type":{"enum":["manual","note","pdf","anki","algoapp","file"],"type":"string"},"source_note_id":{"type":"string","nullable":true},"source_label":{"type":"string","nullable":true},"created_by":{"enum":["user","ai"],"type":"string"},"needs_rewrite":{"type":"boolean"},"rewrite_flagged_at":{"type":"string","nullable":true},"rewrite_resolved_at":{"type":"string","nullable":true},"state":{"enum":["learning","review","relearning"],"type":"string"},"step":{"type":"number","nullable":true},"stability":{"type":"number","nullable":true},"difficulty":{"type":"number","nullable":true},"due_at":{"type":"string"},"last_reviewed_at":{"type":"string","nullable":true},"first_reviewed_at":{"type":"string","nullable":true},"review_count":{"type":"number"},"lapse_count":{"type":"number"},"is_new":{"type":"boolean","description":"Never reviewed"},"preview_due_at":{"nullable":true,"description":"When each button would make the card due if pressed now; null for a deleted card","type":"object","allOf":[{"$ref":"#/components/schemas/RevisePreviewDueAtDto"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"deleted_at":{"type":"string","nullable":true}},"required":["id","deck_id","front","back","source_type","source_note_id","source_label","created_by","needs_rewrite","rewrite_flagged_at","rewrite_resolved_at","state","step","stability","difficulty","due_at","last_reviewed_at","first_reviewed_at","review_count","lapse_count","is_new","preview_due_at","created_at","updated_at","deleted_at"]},"ReviseCardPageResponseDto":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ReviseCardResponseDto"}},"next_cursor":{"type":"string","nullable":true,"description":"Pass back as cursor; null on the last page"},"server_time":{"type":"string","description":"Keep from the first page as the next updated_since watermark"}},"required":["items","next_cursor","server_time"]},"ReviseCardListResponseDto":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ReviseCardResponseDto"}}},"required":["items"]},"CreateReviseCardDto":{"type":"object","properties":{"front":{"type":"string","maxLength":5000},"back":{"type":"string","maxLength":5000},"id":{"type":"string","format":"uuid","description":"Client-generated id; repeating it returns the existing card"},"source_type":{"description":"Import sources are accepted too: the Mac reads Anki and AlgoApp files itself (preview mode) and\ncopies those cards to the account, and they must stay imported cards, due at once and outside the\ndaily new-card allowance. Refusing them failed every 100-card batch of a copy with a 400.","enum":["manual","note","pdf","anki","algoapp","file"],"type":"string","default":"manual"},"source_note_id":{"type":"string","format":"uuid","description":"The user's note the card came from"},"source_label":{"type":"string","maxLength":255,"description":"PDF file name or note title"},"created_by":{"enum":["user","ai"],"type":"string","default":"user"},"deck_id":{"type":"string","format":"uuid"}},"required":["front","back"]},"ReviseCardFieldsDto":{"type":"object","properties":{"front":{"type":"string","maxLength":5000},"back":{"type":"string","maxLength":5000},"id":{"type":"string","format":"uuid","description":"Client-generated id; repeating it returns the existing card"},"source_type":{"description":"Import sources are accepted too: the Mac reads Anki and AlgoApp files itself (preview mode) and\ncopies those cards to the account, and they must stay imported cards, due at once and outside the\ndaily new-card allowance. Refusing them failed every 100-card batch of a copy with a 400.","enum":["manual","note","pdf","anki","algoapp","file"],"type":"string","default":"manual"},"source_note_id":{"type":"string","format":"uuid","description":"The user's note the card came from"},"source_label":{"type":"string","maxLength":255,"description":"PDF file name or note title"},"created_by":{"enum":["user","ai"],"type":"string","default":"user"}},"required":["front","back"]},"BatchCreateReviseCardsDto":{"type":"object","properties":{"deck_id":{"type":"string","format":"uuid","description":"Deck for every card in the batch"},"cards":{"minItems":1,"maxItems":100,"type":"array","items":{"$ref":"#/components/schemas/ReviseCardFieldsDto"}}},"required":["cards"]},"UpdateReviseCardDto":{"type":"object","properties":{"front":{"type":"string","maxLength":5000},"back":{"type":"string","maxLength":5000},"deck_id":{"type":"string","nullable":true,"format":"uuid","description":"null moves the card out of its deck"},"needs_rewrite":{"type":"boolean","description":"true flags the card for rewriting; false is the same as keep"},"expected_updated_at":{"type":"string","description":"The card's updated_at the edit was based on; a mismatch returns 409"}}},"ReviseCardContentDto":{"type":"object","properties":{"front":{"type":"string","maxLength":5000},"back":{"type":"string","maxLength":5000}},"required":["front","back"]},"ReviseReviewLogResponseDto":{"type":"object","properties":{"id":{"type":"string"},"card_id":{"type":"string"},"response":{"enum":["no_idea","again","hard","good","easy"],"type":"string"},"rating":{"type":"number"},"reviewed_at":{"type":"string"},"duration_ms":{"type":"number","nullable":true},"session_id":{"type":"string","nullable":true},"imported":{"type":"boolean","description":"True for history brought in by an import (docs section 10.3)"},"created_at":{"type":"string"}},"required":["id","card_id","response","rating","reviewed_at","duration_ms","session_id","imported","created_at"]},"CreateReviseCardImageUploadDto":{"type":"object","properties":{"content_type":{"type":"string","maxLength":100,"enum":["image/png","image/jpeg","image/gif","image/webp"]},"file_size":{"type":"number","minimum":1,"maximum":10485760,"description":"Bytes"}},"required":["content_type","file_size"]},"ReviseCardImageUploadResponseDto":{"type":"object","properties":{"image_id":{"type":"string"},"reference":{"type":"string","description":"`fb-revise-image://<image_id>`, for the card text"},"upload_url":{"type":"string"},"upload_headers":{"type":"object","additionalProperties":{"type":"string"}},"upload_url_expires_at":{"type":"string"}},"required":["image_id","reference","upload_url","upload_headers","upload_url_expires_at"]},"CompleteReviseCardImageUploadDto":{"type":"object","properties":{"file_name":{"type":"string","maxLength":255}}},"ReviseCardImageResponseDto":{"type":"object","properties":{"id":{"type":"string"},"card_id":{"type":"string"},"reference":{"type":"string"},"file_name":{"type":"string","nullable":true},"content_type":{"type":"string","enum":["image/png","image/jpeg","image/gif","image/webp"]},"file_size":{"type":"number"},"rotation":{"enum":[0,90,180,270],"type":"number","description":"Degrees clockwise to turn the image when drawing it"},"url":{"type":"string","description":"Signed GET URL; send no Authorization header"},"url_expires_at":{"type":"string"},"created_at":{"type":"string"}},"required":["id","card_id","reference","file_name","content_type","file_size","rotation","url","url_expires_at","created_at"]},"UpdateReviseCardImageDto":{"type":"object","properties":{"rotation":{"enum":[0,90,180,270],"type":"number","description":"Degrees clockwise to turn the image when drawing it"}},"required":["rotation"]},"StartReviseSessionDto":{"type":"object","properties":{"deck_id":{"type":"string","format":"uuid","description":"Review one deck; omit for every deck"},"review_limit":{"type":"number","minimum":1,"maximum":500},"new_cards_per_day":{"type":"number","minimum":0,"maximum":200}}},"StartReviseSessionResponseDto":{"type":"object","properties":{"cards":{"description":"Due review cards first, then imported cards never reviewed, then new cards","type":"array","items":{"$ref":"#/components/schemas/ReviseCardResponseDto"}},"due_count":{"type":"number","description":"Review cards due now plus imported cards never reviewed, in scope, before the limit"},"new_count":{"type":"number","description":"Never-reviewed cards made in Revise, in scope, before the daily limit"}},"required":["cards","due_count","new_count"]},"ReviseReviewItemDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Client-generated review id; the idempotency key"},"card_id":{"type":"string","format":"uuid"},"response":{"enum":["no_idea","again","hard","good","easy"],"type":"string"},"reviewed_at":{"type":"string","description":"When the user answered, on the client clock (ISO 8601)"},"duration_ms":{"type":"number","minimum":0,"maximum":3600000},"session_id":{"type":"string","format":"uuid","description":"Client-generated session id, for stats"}},"required":["id","card_id","response","reviewed_at"]},"SubmitReviseReviewsDto":{"type":"object","properties":{"reviews":{"minItems":1,"maxItems":200,"type":"array","items":{"$ref":"#/components/schemas/ReviseReviewItemDto"}}},"required":["reviews"]},"ReviseReviewResultDto":{"type":"object","properties":{"id":{"type":"string"},"status":{"enum":["applied","duplicate","card_not_found","invalid_time"],"type":"string"},"card":{"$ref":"#/components/schemas/ReviseCardResponseDto"}},"required":["id","status"]},"SubmitReviseReviewsResponseDto":{"type":"object","properties":{"results":{"description":"In request order","type":"array","items":{"$ref":"#/components/schemas/ReviseReviewResultDto"}}},"required":["results"]},"ReviseStatsResponseDto":{"type":"object","properties":{"due_count":{"type":"number"},"new_count":{"type":"number"},"needs_rewrite_count":{"type":"number"},"reviewed_today":{"type":"number","description":"Reviews since the start of today in the user's timezone"}},"required":["due_count","new_count","needs_rewrite_count","reviewed_today"]},"CreateRevisePdfUploadUrlDto":{"type":"object","properties":{"content_type":{"type":"string","enum":["application/pdf"]},"file_size":{"type":"number","minimum":1,"maximum":10485760,"description":"Bytes"}},"required":["content_type","file_size"]},"RevisePdfUploadUrlResponseDto":{"type":"object","properties":{"upload_url":{"type":"string","description":"PUT the raw PDF here, with exactly upload_headers and no Authorization header"},"upload_headers":{"type":"object","additionalProperties":{"type":"string"}},"file_key":{"type":"string","description":"Pass to POST /revise/ai/generate/pdf"},"expires_at":{"type":"string"}},"required":["upload_url","upload_headers","file_key","expires_at"]},"GenerateFromPdfDto":{"type":"object","properties":{"max_cards":{"type":"number","minimum":1,"maximum":50},"instructions":{"type":"string","maxLength":500,"example":"Definitions from chapter 3 only"},"language":{"type":"string","maxLength":35,"example":"en","description":"BCP-47 tag of the language to write the cards in, translating from the source when needed. Defaults to the user's profile language, then English"},"keep_source_language":{"type":"boolean","default":false,"description":"Write each card in the language of its source instead of `language` (e.g. for language practice)"},"file_key":{"type":"string","maxLength":512}},"required":["file_key"]},"ReviseMnemonicDto":{"type":"object","properties":{"type":{"enum":["acronym","acrostic","association","rhyme","chunking"],"type":"string"},"text":{"type":"string","description":"The acronym, the acrostic sentence, or the association, rhyme or chunking"},"expansion":{"description":"What an acronym or acrostic encodes, in letter order; empty otherwise","type":"array","items":{"type":"string"}},"reordered":{"type":"boolean","description":"The items were rearranged to make the word because their order does not matter"},"is_english_word":{"type":"boolean","nullable":true,"description":"Acronyms: the letters spell a common English word"},"hook":{"type":"string","description":"The line shown under the answer, in the card's language"}},"required":["type","text","expansion","reordered","is_english_word","hook"]},"ReviseDraftCardDto":{"type":"object","properties":{"front":{"type":"string"},"back":{"type":"string","description":"Ends with the memory hook when there is one"},"source_note_id":{"type":"string","description":"Set for drafts generated from notes"},"mnemonic":{"description":"Set when the card has a checked memory hook","allOf":[{"$ref":"#/components/schemas/ReviseMnemonicDto"}]}},"required":["front","back"]},"ReviseGenerationResponseDto":{"type":"object","properties":{"drafts":{"type":"array","items":{"$ref":"#/components/schemas/ReviseDraftCardDto"}},"truncated":{"type":"boolean","description":"The model offered more drafts than max_cards"}},"required":["drafts","truncated"]},"GenerateFromNotesDto":{"type":"object","properties":{"max_cards":{"type":"number","minimum":1,"maximum":50},"instructions":{"type":"string","maxLength":500,"example":"Definitions from chapter 3 only"},"language":{"type":"string","maxLength":35,"example":"en","description":"BCP-47 tag of the language to write the cards in, translating from the source when needed. Defaults to the user's profile language, then English"},"keep_source_language":{"type":"boolean","default":false,"description":"Write each card in the language of its source instead of `language` (e.g. for language practice)"},"note_ids":{"minItems":1,"maxItems":10,"type":"array","items":{"type":"string","format":"uuid"}}},"required":["note_ids"]},"ReviseChatTurnDto":{"type":"object","properties":{"role":{"enum":["user","assistant"],"type":"string"},"content":{"type":"string","maxLength":30000}},"required":["role","content"]},"GenerateFromChatDto":{"type":"object","properties":{"max_cards":{"type":"number","minimum":1,"maximum":50},"instructions":{"type":"string","maxLength":500,"example":"Definitions from chapter 3 only"},"language":{"type":"string","maxLength":35,"example":"en","description":"BCP-47 tag of the language to write the cards in, translating from the source when needed. Defaults to the user's profile language, then English"},"keep_source_language":{"type":"boolean","default":false,"description":"Write each card in the language of its source instead of `language` (e.g. for language practice)"},"reasoning_effort":{"type":"string","enum":["low","high"]},"turns":{"minItems":1,"maxItems":200,"type":"array","items":{"$ref":"#/components/schemas/ReviseChatTurnDto"}}},"required":["turns"]},"ReviseAssistTurnDto":{"type":"object","properties":{"role":{"enum":["user","assistant"],"type":"string"},"content":{"type":"string","maxLength":2000}},"required":["role","content"]},"ReviseConversationDto":{"type":"object","properties":{"reasoning_effort":{"type":"string","enum":["low","high"]},"message":{"type":"string","maxLength":2000},"history":{"maxItems":10,"type":"array","items":{"$ref":"#/components/schemas/ReviseAssistTurnDto"}}},"required":["message"]},"ReviseConversationResponseDto":{"type":"object","properties":{"reply":{"type":"string"}},"required":["reply"]},"ReviseDraftAssistDto":{"type":"object","properties":{"reasoning_effort":{"type":"string","enum":["low","high"]},"mode":{"enum":["explain","rewrite"],"type":"string"},"message":{"type":"string","maxLength":2000},"history":{"maxItems":10,"type":"array","items":{"$ref":"#/components/schemas/ReviseAssistTurnDto"}},"card":{"$ref":"#/components/schemas/ReviseCardContentDto"}},"required":["mode","card"]},"ReviseCardSuggestionDto":{"type":"object","properties":{"front":{"type":"string","maxLength":5000},"back":{"type":"string","maxLength":5000},"mnemonic":{"description":"Set when the card has a checked memory hook","allOf":[{"$ref":"#/components/schemas/ReviseMnemonicDto"}]}},"required":["front","back"]},"ReviseAssistResponseDto":{"type":"object","properties":{"reply":{"type":"string"},"suggestion":{"nullable":true,"description":"Set in rewrite mode, and in explain mode when the message asks for a change to the card","type":"object","allOf":[{"$ref":"#/components/schemas/ReviseCardSuggestionDto"}]}},"required":["reply","suggestion"]},"ReviseAssistDto":{"type":"object","properties":{"reasoning_effort":{"type":"string","enum":["low","high"]},"mode":{"enum":["explain","rewrite"],"type":"string"},"message":{"type":"string","maxLength":2000},"history":{"maxItems":10,"type":"array","items":{"$ref":"#/components/schemas/ReviseAssistTurnDto"}}},"required":["mode"]},"CreateReviseImportUploadUrlDto":{"type":"object","properties":{"file_name":{"type":"string","maxLength":255,"description":"The file's name; must end in .apkg, .colpkg, .zip, .xml, .csv, .tsv, .txt"},"file_size":{"type":"number","minimum":1,"maximum":209715200,"description":"Bytes"},"deck_id":{"type":"string","format":"uuid","description":"One of the user's live decks to put every card in, whatever decks the file names; no decks are created. Omit to make decks from the file"}},"required":["file_name","file_size"]},"ReviseImportResponseDto":{"type":"object","properties":{"id":{"type":"string"},"file_name":{"type":"string"},"status":{"enum":["awaiting_upload","queued","processing","completed","failed"],"type":"string"},"source":{"nullable":true,"enum":["anki","algoapp","file"],"type":"string"},"format":{"nullable":true,"enum":["anki2","anki21","anki21b","algoapp","csv","tsv"],"type":"string"},"progress_included":{"type":"boolean","description":"False when the file had no scheduling, so every card arrived new"},"decks_imported":{"type":"number"},"deck_ids":{"type":"array","items":{"type":"string"}},"cards_imported":{"type":"number","description":"New cards"},"cards_updated":{"type":"number","description":"Cards already imported, updated to the file (progress kept)"},"cards_unchanged":{"type":"number","description":"Cards already imported and identical to the file"},"cards_with_progress":{"type":"number"},"reviews_imported":{"type":"number"},"images_imported":{"type":"number","description":"Images stored on the imported cards"},"total_cards":{"type":"number","nullable":true,"description":"Cards in the file; null until it has been read"},"processed_cards":{"type":"number","nullable":true,"description":"Cards ready to be written so far, while processing"},"total_images":{"type":"number","nullable":true,"description":"Images to store; null until the file has been read"},"processed_images":{"type":"number","nullable":true,"description":"Images stored or skipped so far, while processing"},"skipped":{"type":"object","additionalProperties":{"type":"integer"},"description":"Counts by reason: already_imported, suspended, empty_front, empty_back, unsupported_note_type, missing_note_type, card_limit, deck_limit, malformed_row"},"warnings":{"type":"object","additionalProperties":{"type":"integer"},"description":"Counts by warning: media_not_imported, text_truncated, history_not_stored"},"error_code":{"type":"string","nullable":true},"error_message":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"},"finished_at":{"type":"string","nullable":true}},"required":["id","file_name","status","source","format","progress_included","decks_imported","deck_ids","cards_imported","cards_updated","cards_unchanged","cards_with_progress","reviews_imported","images_imported","total_cards","processed_cards","total_images","processed_images","skipped","warnings","error_code","error_message","created_at","updated_at","finished_at"]},"ReviseImportUploadUrlResponseDto":{"type":"object","properties":{"import":{"$ref":"#/components/schemas/ReviseImportResponseDto"},"upload_url":{"type":"string","description":"PUT the raw file here, with exactly upload_headers and no Authorization header"},"upload_headers":{"type":"object","additionalProperties":{"type":"string"}},"expires_at":{"type":"string"}},"required":["import","upload_url","upload_headers","expires_at"]},"CreateGeofenceDto":{"type":"object","properties":{"name":{"type":"string","maxLength":255},"latitude":{"type":"number","maximum":90,"minimum":-90},"longitude":{"type":"number","maximum":180,"minimum":-180},"radius":{"type":"number","maximum":10000,"minimum":10},"trigger_after_time":{"type":"string","pattern":"^([01]\\d|2[0-3]):([0-5]\\d)$"},"associated_routine_id":{"type":"string","format":"uuid"}},"required":["name","latitude","longitude"]},"UpdateGeofenceDto":{"type":"object","properties":{"name":{"type":"string","maxLength":255},"latitude":{"type":"number","maximum":90,"minimum":-90},"longitude":{"type":"number","maximum":180,"minimum":-180},"radius":{"type":"number","maximum":10000,"minimum":10},"trigger_after_time":{"type":"string","pattern":"^([01]\\d|2[0-3]):([0-5]\\d)$"},"associated_routine_id":{"type":"string","nullable":true,"format":"uuid"}}},"CreateExternalApiTokenDto":{"type":"object","properties":{"scopes":{"type":"array","items":{"type":"string","enum":["tasks:read","tasks:write"]},"description":"Scopes granted to this token","example":["tasks:read","tasks:write"]},"label":{"type":"string","description":"Human-readable label for this token (e.g. \"My MCP Client\")","example":"My MCP Client"},"agent_name":{"type":"string","maxLength":100,"description":"Name of the AI agent this token belongs to (e.g. \"Captain Codebeard\")","example":"Captain Codebeard"}},"required":["scopes"]},"ExternalApiTokenIssuedResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Token UUID"},"label":{"type":"string","description":"Human-readable label"},"agent_name":{"type":"string","description":"Name of the AI agent this token belongs to"},"scopes":{"description":"Scopes granted to this token","type":"array","items":{"type":"string"}},"last_used_at":{"format":"date-time","type":"string","description":"When the token was last used"},"expires_at":{"format":"date-time","type":"string","description":"When the token expires (null = never)"},"created_at":{"type":"string","description":"When the token was created"},"token":{"type":"string","description":"The raw token — shown ONCE at issuance, never retrievable again. Store it securely."}},"required":["id","scopes","created_at","token"]},"ExternalApiTokenResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Token UUID"},"label":{"type":"string","description":"Human-readable label"},"agent_name":{"type":"string","description":"Name of the AI agent this token belongs to"},"scopes":{"description":"Scopes granted to this token","type":"array","items":{"type":"string"}},"last_used_at":{"format":"date-time","type":"string","description":"When the token was last used"},"expires_at":{"format":"date-time","type":"string","description":"When the token expires (null = never)"},"created_at":{"type":"string","description":"When the token was created"}},"required":["id","scopes","created_at"]},"McpAgentResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Token ID — use this as assigned_mcp_token_id when assigning tasks to this agent"},"agent_name":{"type":"string","description":"Agent name"},"label":{"type":"string","description":"Human-readable label for this token"},"scopes":{"description":"Scopes granted to this token","type":"array","items":{"type":"string"}},"created_at":{"type":"string","description":"When the token was created"}},"required":["id","scopes","created_at"]},"UpdateTaskStatusDto":{"type":"object","properties":{"status":{"enum":["NOT_STARTED","IN_PROGRESS","COMPLETED"],"type":"string","description":"New core status for the task (use for standard state transitions)","example":"IN_PROGRESS"},"custom_status_id":{"type":"string","maxLength":100,"description":"Custom project status ID (use to set project-level statuses such as \"Ready for human review\"). Must be a valid status ID from the task's project.","example":"ready-for-human-review"}}},"AddTaskNoteDto":{"type":"object","properties":{"content":{"type":"string","minLength":1,"description":"Note content to add to the task","example":"Working on this now — will complete by EOD.","maxLength":10000}},"required":["content"]},"TaskComment":{"type":"object","properties":{"task_id":{"type":"string"},"user_id":{"type":"string"},"content":{"type":"string"},"task":{"$ref":"#/components/schemas/ToDo"},"user":{"$ref":"#/components/schemas/User"},"reactions":{"type":"array","items":{"$ref":"#/components/schemas/TaskCommentReaction"}},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["task_id","user_id","content"]},"TaskCommentReaction":{"type":"object","properties":{"comment_id":{"type":"string"},"user_id":{"type":"string"},"emoji":{"type":"string"},"comment":{"$ref":"#/components/schemas/TaskComment"},"user":{"$ref":"#/components/schemas/User"},"id":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["comment_id","user_id","emoji"]},"EnsureProjectStatusDto":{"type":"object","properties":{"project_id":{"type":"string","format":"uuid","description":"UUID of the project to add the status to","example":"123e4567-e89b-12d3-a456-426614174000"},"label":{"type":"string","description":"Display label for the status (case-insensitive deduplication)","example":"Ready for human review","maxLength":100},"color":{"type":"string","pattern":"^#[0-9A-Fa-f]{6}$","description":"Hex color code for the status badge","example":"#F59E0B"},"should_complete_task":{"type":"boolean","description":"Whether tasks assigned this status should be marked as completed","default":false}},"required":["project_id","label","color"]},"EnsureProjectStatusResponseDto":{"type":"object","properties":{"id":{"type":"string","description":"Status ID (UUID for new statuses; original id for existing ones)"},"label":{"type":"string","description":"Display label"},"color":{"type":"string","description":"Hex color code"},"order":{"type":"number","description":"Sort order within the project"},"should_complete_task":{"type":"boolean","description":"Whether tasks assigned this status are considered completed"},"already_existed":{"type":"boolean","description":"Whether this status already existed (true) or was just created (false)"}},"required":["id","label","color","order","should_complete_task","already_existed"]},"DayPlanDayResponseDto":{"type":"object","properties":{"day":{"type":"string"},"tasks":{"description":"Real todos planned for this day (pointed via `to_do.planned_date`), in panel\norder, in the same `ToDoResponse` shape as `GET /to-do`.","type":"array","items":{"$ref":"#/components/schemas/ToDoResponse"}},"dismissed_event_ids":{"type":"array","items":{"type":"string"}}},"required":["day","tasks","dismissed_event_ids"]},"CreateDayPlanEventItemDto":{"type":"object","properties":{"title":{"type":"string","maxLength":2500},"description":{"type":"string","maxLength":10000},"location":{"type":"string","maxLength":1000,"description":"Where the event is: an address, a room, or a call link"},"url":{"type":"string","maxLength":2048,"description":"The event's URL field, typically the meeting's join link"},"dtstart_local":{"type":"string","description":"Local event start without an offset. Ambiguous and nonexistent times follow the same RFC 5545 timezone behavior as recurring event series.","example":"2026-08-10T09:00:00"},"dtend_local":{"type":"string","description":"Local event end without an offset. The nominal wall-clock duration must be positive and no more than 24 hours.","example":"2026-08-10T10:00:00"},"timezone":{"type":"string","maxLength":255,"description":"IANA timezone used to interpret the local start and end","example":"Asia/Singapore"},"external_id":{"type":"string","description":"Opaque client identifier for one event occurrence. Posting an event whose external_id matches an existing one-off event of the current user updates that event in place instead of creating a duplicate.","example":"ABCD-1234:5678@2026-10-19","maxLength":512},"is_all_day":{"type":"boolean","default":false,"description":"Whether the event spans the whole day"}},"required":["title","dtstart_local","dtend_local","timezone"]},"CreateDayPlanEventsDto":{"type":"object","properties":{"events":{"uniqueItems":true,"minItems":1,"type":"array","items":{"$ref":"#/components/schemas/CreateDayPlanEventItemDto"}}},"required":["events"]},"DayPlanEventResponseDto":{"type":"object","properties":{"external_id":{"type":"string","nullable":true,"description":"Client identifier supplied when the event was created, or null when none was supplied"},"is_all_day":{"type":"boolean","description":"Whether the event spans the whole day"},"id":{"type":"string"},"title":{"type":"string"},"description":{"type":"string","nullable":true},"location":{"type":"string","nullable":true},"url":{"type":"string","nullable":true},"event_begins":{"type":"string"},"event_ends":{"type":"string"},"timezone":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["external_id","is_all_day","id","title","description","location","url","event_begins","event_ends","timezone","created_at","updated_at"]},"CreateDayPlanEventsResponseDto":{"type":"object","properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/DayPlanEventResponseDto"}}},"required":["events"]},"DayPlanEventsForDayResponseDto":{"type":"object","properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/DayPlanEventResponseDto"}},"has_more":{"type":"boolean","description":"True when more than 1000 events remain from the requested page"},"content_encrypted":{"type":"boolean","description":"Always true: event titles, descriptions, locations and URLs are encrypted at rest. Clients that upload device calendar content wait for this before sending any, and it is present even when the day has no events."},"day":{"type":"string"}},"required":["events","has_more","content_encrypted","day"]},"CreateEventSeriesItemDto":{"type":"object","properties":{"title":{"type":"string","maxLength":2500},"description":{"type":"string","maxLength":10000},"dtstart_local":{"type":"string","description":"Local DTSTART without an offset. RFC 5545 timezone rules apply when this time is ambiguous or falls in a DST gap.","example":"2026-08-10T09:00:00"},"dtend_local":{"type":"string","description":"Local DTEND without an offset. Its difference from DTSTART is stored as a wall-clock duration of at most 24 hours, independent of timezone-offset changes. If a generated end falls in a DST gap, event_ends is normalized to a real instant.","example":"2026-08-10T10:00:00"},"timezone":{"type":"string","maxLength":255,"description":"IANA timezone used to interpret DTSTART, DTEND, and recurrences","example":"Asia/Singapore"},"rrule":{"type":"string","maxLength":2048,"description":"One unfolded RFC 5545 RRULE content line. Supports DAILY, plain-weekday WEEKLY, constrained MONTHLY, and non-leap-day YEARLY rules. COUNT and UTC UNTIL are optional but cannot be combined.","example":"RRULE:FREQ=WEEKLY;BYDAY=MO,WE;UNTIL=20261231T235959Z"}},"required":["title","dtstart_local","dtend_local","timezone","rrule"]},"CreateEventSeriesDto":{"type":"object","properties":{"events":{"minItems":1,"type":"array","items":{"$ref":"#/components/schemas/CreateEventSeriesItemDto"}}},"required":["events"]},"EventSeriesResponseDto":{"type":"object","properties":{"dtend_local":{"type":"string","description":"Nominal local end derived from DTSTART and wall-clock duration; it can name a nonexistent wall time during a DST gap"},"rrule":{"type":"string","description":"Canonical unfolded RFC 5545 RRULE content line","example":"RRULE:FREQ=WEEKLY;BYDAY=MO,WE;UNTIL=20261231T235959Z"},"id":{"type":"string"},"title":{"type":"string"},"description":{"type":"string","nullable":true},"dtstart_local":{"type":"string"},"timezone":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["dtend_local","rrule","id","title","description","dtstart_local","timezone","created_at","updated_at"]},"CreateEventSeriesResponseDto":{"type":"object","properties":{"series":{"type":"array","items":{"$ref":"#/components/schemas/EventSeriesResponseDto"}}},"required":["series"]},"EventSeriesListResponseDto":{"type":"object","properties":{"series":{"type":"array","items":{"$ref":"#/components/schemas/EventSeriesResponseDto"}}},"required":["series"]},"EventSeriesOccurrenceResponseDto":{"type":"object","properties":{"event_ends":{"type":"string","description":"UTC end instant after wall-clock duration and DST-gap normalization are applied"},"occurrence_id":{"type":"string"},"series_id":{"type":"string"},"summary":{"type":"string"},"description":{"type":"string","nullable":true},"event_begins":{"type":"string"},"timezone":{"type":"string"}},"required":["event_ends","occurrence_id","series_id","summary","description","event_begins","timezone"]},"EventSeriesOccurrencesResponseDto":{"type":"object","properties":{"day":{"type":"string"},"events":{"type":"array","items":{"$ref":"#/components/schemas/EventSeriesOccurrenceResponseDto"}}},"required":["day","events"]},"DayPlanEventIdDto":{"type":"object","properties":{"event_id":{"type":"string","maxLength":512}},"required":["event_id"]},"EventColourResponseDto":{"type":"object","properties":{"event_id":{"type":"string"},"colour":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["event_id","colour"]},"UpsertEventColourDto":{"type":"object","properties":{"event_id":{"type":"string","maxLength":512},"colour":{"type":"string","maxLength":32}},"required":["event_id","colour"]},"GenerateFileImportUploadUrlDto":{"type":"object","properties":{"content_type":{"type":"string","description":"MIME type of the calendar image or document to upload","example":"application/pdf","maxLength":100,"enum":["image/jpeg","image/png","image/webp","application/pdf","application/vnd.openxmlformats-officedocument.wordprocessingml.document"]}},"required":["content_type"]},"GenerateFileImportUploadUrlResponseDto":{"type":"object","properties":{"uploadUrl":{"type":"string","description":"Presigned URL the client should PUT the calendar file to"},"fileKey":{"type":"string","description":"Transient R2 object key of the uploaded file (pass back to POST /day-plan/import/file)"}},"required":["uploadUrl","fileKey"]},"ImportFileDto":{"type":"object","properties":{"key":{"type":"string","description":"R2 object key returned by a Day Plan calendar import upload-url endpoint","maxLength":512},"client_datetime_iso":{"type":"string","description":"Client-local ISO 8601 datetime used to resolve relative calendar entries","example":"2026-07-20T09:30:00+08:00","maxLength":64},"repeated_events_end_on":{"type":"string","description":"ISO calendar date (yyyy-MM-dd). Providing it enables recurrence detection and sets the requested inclusive end date for recurring drafts.","example":"2026-09-30"}},"required":["key"]},"DayPlanImportUnscheduledEntryDto":{"type":"object","properties":{"title":{"type":"string","description":"Short label for the entry"},"date":{"type":"string","description":"ISO calendar date (yyyy-MM-dd)","example":"2026-07-16"},"start_time":{"type":"string","nullable":true,"description":"24-hour start time (HH:mm), or null if not shown","example":"09:00"},"end_time":{"type":"string","nullable":true,"description":"24-hour end time (HH:mm), or null if not shown","example":"10:00"},"confidence":{"type":"number","description":"Model confidence for this row, 0..1","minimum":0,"maximum":1},"repeat":{"enum":["none","daily","weekly","fortnightly"],"type":"string","description":"Detected recurrence frequency to retain while the dashboard collects missing times"},"repeat_end_on":{"type":"string","nullable":true,"description":"Effective inclusive recurrence end date, or null for a non-recurring entry","example":"2026-09-30"}},"required":["title","date","start_time","end_time","confidence","repeat","repeat_end_on"]},"DayPlanImportEventDto":{"type":"object","properties":{"title":{"type":"string","description":"Short label for the entry"},"date":{"type":"string","description":"ISO calendar date (yyyy-MM-dd)","example":"2026-07-16"},"start_time":{"type":"string","nullable":true,"description":"24-hour start time (HH:mm), or null if not shown","example":"09:00"},"end_time":{"type":"string","nullable":true,"description":"24-hour end time (HH:mm), or null if not shown","example":"10:00"},"confidence":{"type":"number","description":"Model confidence for this row, 0..1","minimum":0,"maximum":1}},"required":["title","date","start_time","end_time","confidence"]},"DayPlanImportEventSeriesDto":{"type":"object","properties":{"title":{"type":"string","description":"Short label for the recurring entry"},"date":{"type":"string","description":"First occurrence date (yyyy-MM-dd)","example":"2026-07-16"},"start_time":{"type":"string","description":"First occurrence start time (HH:mm)","example":"09:00"},"end_time":{"type":"string","description":"First occurrence end time (HH:mm)","example":"10:00"},"confidence":{"type":"number","description":"Model confidence for this draft, 0..1","minimum":0,"maximum":1},"repeat":{"type":"string","description":"Detected recurrence frequency for dashboard review and later RRULE conversion","enum":["daily","weekly","fortnightly"]},"repeat_end_on":{"type":"string","description":"Effective inclusive recurrence end date, capped at 366 days after the first occurrence","example":"2026-09-30"}},"required":["title","date","start_time","end_time","confidence","repeat","repeat_end_on"]},"DayPlanImportResponseDto":{"type":"object","properties":{"unscheduled_entries":{"description":"Drafts missing a complete time range. Let the user add times or discard them; do not create todos automatically.","type":"array","items":{"$ref":"#/components/schemas/DayPlanImportUnscheduledEntryDto"}},"events":{"description":"Timed non-recurring drafts to review before POST /day-plan/events","type":"array","items":{"$ref":"#/components/schemas/DayPlanImportEventDto"}},"event_series":{"description":"Editable timed recurrence drafts to review before calling POST /day-plan/event-series","type":"array","items":{"$ref":"#/components/schemas/DayPlanImportEventSeriesDto"}},"truncated":{"type":"boolean","description":"True when unique model drafts exceeded the shared 500-draft response limit."}},"required":["unscheduled_entries","events","event_series","truncated"]},"EventProjectLinkResponseDto":{"type":"object","properties":{"event_key":{"type":"string"},"alias_keys":{"type":"array","items":{"type":"string"}},"occurrence_date":{"type":"string","nullable":true},"project_ids":{"type":"array","items":{"type":"string"}},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["event_key","alias_keys","occurrence_date","project_ids"]},"UpsertEventProjectLinkDto":{"type":"object","properties":{"event_key":{"type":"string","description":"The client key the link is stored under, e.g. series:<iCalUID> or event:<id>"},"occurrence_date":{"type":"string","nullable":true,"description":"YYYY-MM-DD: this occurrence only. Absent or null: the whole event, every occurrence of a series"},"alias_keys":{"maxItems":10,"description":"Other keys the same event is known by on the user's devices","type":"array","items":{"type":"string"}},"project_ids":{"maxItems":10,"description":"Project ids in the user order. Empty on an occurrence: no projects that day, whatever the series has","type":"array","items":{"type":"string","format":"uuid"}}},"required":["event_key","project_ids"]},"EventProjectLinkScopeDto":{"type":"object","properties":{"event_key":{"type":"string","description":"The client key the link is stored under, e.g. series:<iCalUID> or event:<id>"},"occurrence_date":{"type":"string","nullable":true,"description":"YYYY-MM-DD: this occurrence only. Absent or null: the whole event, every occurrence of a series"}},"required":["event_key"]},"CanvasCourseInputDto":{"type":"object","properties":{"course_id":{"type":"string","description":"Canvas's course id (from `/courses/<id>` in the event link), or whatever named the course."},"name":{"type":"string","description":"The name the course's project gets: its code (\"COMP1010\") or Canvas's category."}},"required":["course_id","name"]},"CanvasImportPreviewDto":{"type":"object","properties":{"courses":{"uniqueItems":true,"type":"array","items":{"$ref":"#/components/schemas/CanvasCourseInputDto"}},"feed_host":{"type":"string","description":"The school's Canvas host, e.g. `school.instructure.com`."}},"required":["courses","feed_host"]},"CanvasProjectRefDto":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"]},"CanvasCourseMatchDto":{"type":"object","properties":{"project_id":{"type":"string"},"project_name":{"type":"string"},"confidence":{"type":"number","minimum":0,"maximum":1},"reason":{"enum":["exact","same_code","same_name","similar_name"],"type":"string"}},"required":["project_id","project_name","confidence","reason"]},"CanvasCoursePreviewDto":{"type":"object","properties":{"course_id":{"type":"string"},"name":{"type":"string"},"linked_project":{"nullable":true,"type":"object","allOf":[{"$ref":"#/components/schemas/CanvasProjectRefDto"}]},"suggestion":{"nullable":true,"description":"The student's likely existing project for this course, when there is no linked one.","type":"object","allOf":[{"$ref":"#/components/schemas/CanvasCourseMatchDto"}]},"default_action":{"enum":["use_linked","use_existing","create","skip_deleted"],"type":"string"}},"required":["course_id","name","default_action"]},"CanvasImportPreviewResponseDto":{"type":"object","properties":{"courses":{"type":"array","items":{"$ref":"#/components/schemas/CanvasCoursePreviewDto"}}},"required":["courses"]},"CanvasAssignmentInputDto":{"type":"object","properties":{"uid":{"type":"string","description":"The event UID (`event-assignment-<id>`): stable across feed refreshes, so it keys the to-do."},"title":{"type":"string","description":"The title without Canvas's \"[COURSE]\" suffix."},"details":{"type":"string","description":"The to-do's details as the app writes them: the description's start, then the link back to Canvas."},"due_day":{"type":"string","description":"Due dates are day-granular in the apps, so an assignment's due date arrives as a day."},"description_excerpt":{"type":"string","description":"The start of Canvas's description, given to the AI breakdown alongside the title. The app chooses\nwhat to share; the server cuts it to the breakdown prompt's input limit."},"previously_imported":{"type":"boolean","description":"This device imported the assignment before (its own record of the client-side import that preceded\nthis endpoint). A to-do that is gone then was deleted by the student and must not come back."}},"required":["uid","title","details","due_day"]},"CanvasCourseImportDto":{"type":"object","properties":{"decision":{"enum":["auto","use_existing","create"],"type":"string"},"assignments":{"uniqueItems":true,"type":"array","items":{"$ref":"#/components/schemas/CanvasAssignmentInputDto"}},"project_id":{"type":"string","description":"Required with `use_existing`: one of the student's own active projects.","format":"uuid"},"course_id":{"type":"string","description":"Canvas's course id (from `/courses/<id>` in the event link), or whatever named the course."},"name":{"type":"string","description":"The name the course's project gets: its code (\"COMP1010\") or Canvas's category."}},"required":["decision","assignments","course_id","name"]},"CanvasImportDto":{"type":"object","properties":{"courses":{"uniqueItems":true,"type":"array","items":{"$ref":"#/components/schemas/CanvasCourseImportDto"}},"generate_subtasks":{"type":"boolean","description":"Break each newly imported assignment into subtasks with AI. Off unless the student turned it on: the\nassignment's title and the start of its description go to the AI provider."},"language":{"type":"string","description":"The language subtasks are written in (`en`, `es`, … or a name); English when absent or unknown."},"feed_host":{"type":"string","description":"The school's Canvas host, e.g. `school.instructure.com`."}},"required":["courses","generate_subtasks","feed_host"]},"CanvasCourseResultDto":{"type":"object","properties":{"course_id":{"type":"string"},"project_id":{"type":"object","nullable":true},"project_name":{"type":"object","nullable":true},"outcome":{"enum":["linked","adopted","created","skipped_deleted","failed"],"type":"string"}},"required":["course_id","outcome"]},"CanvasGeneratedSubtaskDto":{"type":"object","properties":{"name":{"type":"string"},"estimated_minutes":{"type":"object","nullable":true}},"required":["name"]},"CanvasTaskResultDto":{"type":"object","properties":{"uid":{"type":"string"},"todo_id":{"type":"string"},"outcome":{"enum":["created","updated","unchanged","skipped_deleted","skipped_course","failed"],"type":"string"},"subtasks":{"description":"The AI breakdown stored on a to-do this import created; empty otherwise.","type":"array","items":{"$ref":"#/components/schemas/CanvasGeneratedSubtaskDto"}}},"required":["uid","todo_id","outcome","subtasks"]},"CanvasImportResponseDto":{"type":"object","properties":{"courses":{"type":"array","items":{"$ref":"#/components/schemas/CanvasCourseResultDto"}},"tasks":{"type":"array","items":{"$ref":"#/components/schemas/CanvasTaskResultDto"}}},"required":["courses","tasks"]},"LateNoMoreConfigResponseDto":{"type":"object","properties":{"calendar_ids":{"nullable":true,"description":"Calendar provider ids (Calendar.calendar_id). null = every synced calendar.","type":"array","items":{"type":"string"}},"created_at":{"type":"string","nullable":true,"description":"null until the user first saves a config."},"updated_at":{"type":"string","nullable":true,"description":"null until the user first saves a config."},"enabled":{"type":"boolean"},"alert_lead_minutes":{"description":"Minutes before the meeting starts to alert, sorted descending.","type":"array","items":{"type":"number"}},"active_hours_start":{"type":"string","description":"Local \"HH:mm\" (24h)."},"active_hours_end":{"type":"string","description":"Local \"HH:mm\" (24h)."},"ignored_keywords":{"type":"array","items":{"type":"string"}},"require_meeting_url":{"type":"boolean"},"verbal_alerts_enabled":{"type":"boolean"}},"required":["calendar_ids","created_at","updated_at","enabled","alert_lead_minutes","active_hours_start","active_hours_end","ignored_keywords","require_meeting_url","verbal_alerts_enabled"]},"UpdateLateNoMoreConfigDto":{"type":"object","properties":{"calendar_ids":{"nullable":true,"description":"Calendar provider ids (Calendar.calendar_id). null = every synced calendar.","type":"array","items":{"type":"string","maxLength":1024}},"alert_lead_minutes":{"description":"Minutes before the meeting starts to alert. Stored sorted descending.","uniqueItems":true,"type":"array","items":{"type":"number","maximum":120,"minimum":0}},"ignored_keywords":{"description":"Meetings whose title contains one of these (case-insensitive) don't alert. Trimmed and de-duplicated.","type":"array","items":{"type":"string","maxLength":100,"minLength":1}},"enabled":{"type":"boolean"},"active_hours_start":{"type":"string","description":"Local \"HH:mm\" (24h). Start of the window in which a meeting's start raises alerts."},"active_hours_end":{"type":"string","description":"Local \"HH:mm\" (24h). End of the window in which a meeting's start raises alerts."},"require_meeting_url":{"type":"boolean"},"verbal_alerts_enabled":{"type":"boolean"}}},"VoiceTranscriptionResponseDto":{"type":"object","properties":{"text":{"type":"string","description":"The transcript of the uploaded recording."}},"required":["text"]},"VoiceIntentDto":{"type":"object","properties":{"transcript":{"type":"string","description":"The spoken command, as returned by `POST /voice/transcribe`.","maxLength":4000},"habits":{"description":"Habit names the model may match for `start_habit`.","type":"array","items":{"type":"string"}},"clientDatetime":{"type":"string","description":"The client's local \"now\" as `yyyy-MM-dd HH:mm:ss`, used when `timezone` is absent."},"timezone":{"type":"string","description":"IANA time zone (e.g. \"Australia/Melbourne\"); preferred over `clientDatetime`."}},"required":["transcript"]},"VoiceIntentParametersDto":{"type":"object","properties":{"task":{"type":"string"},"time":{"type":"string"},"repeat":{"type":"string"},"duration_minutes":{"type":"number"},"goal":{"type":"string"},"habit_name":{"type":"string"},"note_text":{"type":"string"}}},"VoiceIntentAdditionalActionDto":{"type":"object","properties":{"parameters":{"type":"object","additionalProperties":{"type":"string"}},"action":{"type":"string"}},"required":["action"]},"VoiceIntentResponseDto":{"type":"object","properties":{"confidence":{"enum":["high","medium","low"],"type":"string"},"clarification_needed":{"type":"string","nullable":true},"action":{"type":"string"},"parameters":{"$ref":"#/components/schemas/VoiceIntentParametersDto"},"additional_actions":{"type":"array","items":{"$ref":"#/components/schemas/VoiceIntentAdditionalActionDto"}}},"required":["confidence","clarification_needed","action","parameters"]},"VoiceSuggestTitleDto":{"type":"object","properties":{"text":{"type":"string","description":"The whole transcript of a voice note: the `text` of every `POST /voice/transcribe` chunk, joined. Send only the\ntranscript, not other text already in the note.","maxLength":100000}},"required":["text"]},"VoiceSuggestTitleResponseDto":{"type":"object","properties":{"title":{"type":"string","nullable":true,"description":"A short title in the transcript's language (at most 60 characters, no quotes, no trailing punctuation), or null\nwhen none could be suggested. Clients keep their own title when it is null."}},"required":["title"]},"VoiceActionItemsDto":{"type":"object","properties":{"current_datetime":{"type":"string","description":"Reference datetime including timezone for relative deadlines; omit when unknown.","format":"date-time","example":"2026-10-24T09:00:00+11:00"},"transcript":{"type":"string","description":"The transcript of a recorded meeting, one line per paragraph. Lines may start with a speaker label (\"Me:\",\n\"Someone else:\"). Send only the transcript, not the user's own notes.","maxLength":250000},"user_names":{"type":"array","description":"The recording user's display name and aliases (e.g. full name and first name), so the model can tell the user's own tasks from other people's","items":{"type":"string","maxLength":80},"maxItems":10,"example":["Jeremy Nagel","Jeremy"]}},"required":["transcript"]},"VoiceActionTaskDto":{"type":"object","properties":{"duration":{"type":"number","nullable":true,"description":"Estimated work duration in seconds; null when unknown"},"due_date":{"type":"string","nullable":true,"format":"date-time","description":"Deadline with timezone offset; null when absent or ambiguous"},"owner":{"type":"string","nullable":true,"maxLength":40,"description":"\"me\" for the user who recorded the meeting, else the name or speaker label of whoever took the action on; null when unclear (file it under the user's own)"},"owner_confidence":{"type":"number","nullable":true,"minimum":0,"maximum":1,"description":"How clearly the transcript shows owner, from 0 to 1; null when owner is null. \"me\" always has one"},"title":{"type":"string","description":"Plain action title, including owner and deadline words when stated."},"description":{"type":"string","description":"Brief supporting context from the transcript."}},"required":["duration","due_date","owner","owner_confidence","title","description"]},"VoiceActionItemsResponseDto":{"type":"object","properties":{"action_items":{"description":"The meeting's action items as plain text in the transcript's language, without bullets or checkboxes (at most\n20, each under 200 characters). An item another person owns starts with their name and a colon. Empty when the\nmeeting had none.","type":"array","items":{"type":"string"}},"action_tasks":{"description":"Editable task suggestions, in exactly the same order as action_items. Duration is seconds.","type":"array","items":{"$ref":"#/components/schemas/VoiceActionTaskDto"}},"summary":{"type":"string","description":"A short plain-text paragraph (two to four sentences, at most 700 characters) saying what the meeting covered and\ndecided, in the transcript's language. Empty when the transcript had too little to summarise. Added after\n`action_items`, so clients that predate it simply ignore it."}},"required":["action_items","action_tasks","summary"]},"MySchoolFeaturePolicy":{"type":"object","properties":{"is_school_managed":{"type":"boolean","description":"True when the caller is a student of at least one active school"},"locked_features":{"type":"array","items":{"type":"string","enum":["ai_features","ai_voice_transcription","health_integrations","location_routines","session_replay","third_party_integrations","shared_project_comments"]}},"updated_at":{"type":"string","nullable":true}},"required":["is_school_managed","locked_features","updated_at"]},"SchoolFeaturePolicyView":{"type":"object","properties":{"school_id":{"type":"string"},"available_features":{"type":"array","items":{"type":"string","enum":["ai_features","ai_voice_transcription","health_integrations","location_routines","session_replay","third_party_integrations","shared_project_comments"]}},"recommended_locked_features":{"type":"array","items":{"type":"string","enum":["ai_features","ai_voice_transcription","health_integrations","location_routines","session_replay","third_party_integrations","shared_project_comments"]}},"locked_features":{"type":"array","items":{"type":"string","enum":["ai_features","ai_voice_transcription","health_integrations","location_routines","session_replay","third_party_integrations","shared_project_comments"]}},"is_saved":{"type":"boolean","description":"False until a school admin first saves; nothing is locked before then"},"updated_at":{"type":"string","nullable":true},"updated_by":{"type":"string","nullable":true}},"required":["school_id","available_features","recommended_locked_features","locked_features","is_saved","updated_at","updated_by"]},"UpdateSchoolFeaturePolicyDto":{"type":"object","properties":{"locked_features":{"uniqueItems":true,"type":"array","items":{"type":"string","enum":["ai_features","ai_voice_transcription","health_integrations","location_routines","session_replay","third_party_integrations","shared_project_comments"]}}},"required":["locked_features"]},"SchoolFeaturePolicyChange":{"type":"object","properties":{"id":{"type":"string"},"actor_id":{"type":"string"},"before":{"type":"array","items":{"type":"string","enum":["ai_features","ai_voice_transcription","health_integrations","location_routines","session_replay","third_party_integrations","shared_project_comments"]}},"after":{"type":"array","items":{"type":"string","enum":["ai_features","ai_voice_transcription","health_integrations","location_routines","session_replay","third_party_integrations","shared_project_comments"]}},"created_at":{"type":"string"}},"required":["id","actor_id","before","after","created_at"]}}}}