openapi: 3.2.0 info: title: SparkyFitness Wellness & Metrics API version: 1.0.0 description: API documentation for the SparkyFitness application, providing a comprehensive guide to all available endpoints. Have caution using the API directly, as improper use may lead to data loss or corruption. Also note that the API is subject to change without notice due to heavy development, so always refer to the latest documentation for up-to-date information. It might have flaw and due to vite/nginx internal proxy actual end point accessed via front end URL might be different than hitting them directly on the server. contact: name: SparkyFitness Support servers: - url: https://{host}/api description: Self-hosted SparkyFitness instance (the operator supplies the host). The upstream spec declares the relative base "/api". variables: host: default: sparkyfitness.example.com description: Hostname of your own SparkyFitness deployment. SparkyFitness is self-hosted; there is no vendor-operated API host. security: - apiKeyAuth: [] tags: - name: Wellness & Metrics description: Health metrics tracking (weight, measurements, sleep, mood) and fasting. paths: /measurements/check-in-photos/dates: get: summary: List the dates on which the user has progress photos description: 'Returns the distinct calendar days (YYYY-MM-DD, newest first) that have at least one progress photo. Used to mark those days on the check-in calendar. Registered before /:date so it is not shadowed by it. ' tags: - Wellness & Metrics security: - apiKeyAuth: [] responses: '200': description: Array of YYYY-MM-DD date strings. content: application/json: schema: type: array items: type: string format: date /measurements/check-in-photos/{date}: get: summary: Get progress photos for a check-in date tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: date required: true schema: type: string format: date responses: '200': description: Array of photo records for the given date. '400': description: Invalid date format. /measurements/check-in-photos/file/{id}: get: summary: Serve a progress photo image (authenticated, owner/family only) tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: id required: true schema: type: string format: uuid responses: '200': description: The image file. content: image/*: schema: type: string format: binary '404': description: Photo not found or not accessible. /measurements/check-in-photos/{date}/{type}: post: summary: Upload a progress photo (front, back, or side) tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: date required: true schema: type: string format: date - in: path name: type required: true schema: type: string enum: - front - back - side requestBody: required: true content: multipart/form-data: schema: type: object properties: photo: type: string format: binary responses: '200': description: Photo uploaded successfully. '400': description: Invalid parameters or file type. /measurements/check-in-photos/photo/{id}: delete: summary: Delete a progress photo by ID tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: id required: true schema: type: string format: uuid responses: '204': description: Photo deleted. '400': description: Invalid ID. /fasting/current: get: summary: Get current active fast tags: - Wellness & Metrics description: Retrieves the currently active fast for the authenticated user. security: - apiKeyAuth: [] responses: '200': description: The active fast or null if none. content: application/json: schema: $ref: '#/components/schemas/FastingLog' '401': description: Unauthorized. '500': description: Internal server error. /fasting/start: post: summary: Start a new fast tags: - Wellness & Metrics description: Starts a new fasting period for the authenticated user. security: - apiKeyAuth: [] requestBody: required: true content: application/json: schema: type: object required: - start_time - fasting_type properties: start_time: type: string format: date-time description: The start time of the fast. target_end_time: type: string format: date-time description: The target end time of the fast. fasting_type: type: string description: The type of fast (e.g., "Intermittent Fasting"). responses: '201': description: Success starting fast. content: application/json: schema: $ref: '#/components/schemas/FastingLog' '400': description: Validation error or active fast already exists. '401': description: Unauthorized. '500': description: Internal server error. /fasting/end: post: summary: End an active fast tags: - Wellness & Metrics description: Ends an active fasting period, calculates duration, and optionally logs mood. security: - apiKeyAuth: [] requestBody: required: true content: application/json: schema: type: object required: - id - end_time properties: id: type: string format: uuid description: The ID of the fast to end. start_time: type: string format: date-time description: Optional start time to override. end_time: type: string format: date-time description: The end time of the fast. mood: type: object properties: value: type: integer notes: type: string responses: '200': description: Success ending fast. content: application/json: schema: $ref: '#/components/schemas/FastingLog' '400': description: Validation error. '401': description: Unauthorized. '404': description: Fast not found. '500': description: Internal server error. /fasting/{id}: put: summary: Update an existing fast tags: - Wellness & Metrics description: Updates the details of an existing fasting log. security: - apiKeyAuth: [] parameters: - in: path name: id required: true schema: type: string format: uuid description: The ID of the fast to update. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/FastingLog' responses: '200': description: Success updating fast. content: application/json: schema: $ref: '#/components/schemas/FastingLog' '401': description: Unauthorized. '404': description: Fast not found. '500': description: Internal server error. delete: summary: Delete a fasting log tags: - Wellness & Metrics description: Deletes an existing fasting log. security: - apiKeyAuth: [] parameters: - in: path name: id required: true schema: type: string format: uuid description: The ID of the fast to delete. responses: '200': description: Success deleting fast. '401': description: Unauthorized. '404': description: Fast not found. '500': description: Internal server error. /fasting/history: get: summary: Get fasting history tags: - Wellness & Metrics description: Retrieves a paginated history of fasting logs for the authenticated user. security: - apiKeyAuth: [] parameters: - in: query name: limit schema: type: integer default: 50 description: Maximum number of records to return. - in: query name: offset schema: type: integer default: 0 description: Number of records to skip. responses: '200': description: A list of fasting logs. content: application/json: schema: type: array items: $ref: '#/components/schemas/FastingLog' '401': description: Unauthorized. '500': description: Internal server error. /fasting/stats: get: summary: Get fasting statistics tags: - Wellness & Metrics description: Retrieves summary statistics for the user's fasting history. security: - apiKeyAuth: [] responses: '200': description: Fasting statistics. content: application/json: schema: type: object properties: total_completed_fasts: type: integer total_minutes_fasted: type: integer average_duration_minutes: type: number '401': description: Unauthorized. '500': description: Internal server error. /fasting/history/range/{startDate}/{endDate}: get: summary: Get fasting logs by date range tags: - Wellness & Metrics description: Retrieves completed fasting logs within a specified date range. security: - apiKeyAuth: [] parameters: - in: path name: startDate required: true schema: type: string format: date description: Start date (YYYY-MM-DD). - in: path name: endDate required: true schema: type: string format: date description: End date (YYYY-MM-DD). responses: '200': description: A list of fasting logs within the range. content: application/json: schema: type: array items: $ref: '#/components/schemas/FastingLog' '401': description: Unauthorized. '500': description: Internal server error. /measurements/health-data: post: summary: Submit health data via API Key tags: - Wellness & Metrics description: Receives health data (e.g., from a mobile app) via an authorized API key. security: - apiKeyAuth: [] requestBody: required: true content: application/json: schema: type: array items: type: object description: Flexible health data object. responses: '200': description: 'Request processed. Per-record outcomes are reported in the body: `processed` lists successful records, `errors` lists rejected records with their reasons, and `skipped` lists records that were intentionally not written (e.g. Nutrition records without a source_id). `errors` and `skipped` are always present, possibly empty. A 200 response with a non-empty `errors` array means the remaining records were still saved. ' content: application/json: schema: type: object properties: message: type: string processed: type: array items: type: object properties: type: type: string status: type: string enum: - success data: type: object errors: type: array items: type: object properties: error: type: string entry: type: object skipped: type: array items: type: object properties: reason: type: string entry: type: object '400': description: Malformed request body (invalid JSON, or entries that are not non-null objects). '401': description: Unauthorized (missing or invalid API key). '403': description: Forbidden (API key lacks write permission). /measurements/import-health-data: post: summary: Import health data from a CSV (session authenticated) tags: - Wellness & Metrics description: 'Bulk-imports client-parsed health data rows (body measurements, sleep, vitals, daily activity totals, hydration) through the same processHealthData pipeline used by mobile sync. Rows without a `source` default to `CSV_Import` so re-imports dedup on the same natural keys. ' security: - apiKeyAuth: [] requestBody: required: true content: application/json: schema: type: object required: - items properties: items: type: array items: type: object description: Flat health data object (type + value/date + optional unit/source). responses: '200': description: 'Request processed. Per-record outcomes are reported in the body: `processed`, `errors`, and `skipped`. A 200 with a non-empty `errors` array means the remaining rows were still saved. ' '400': description: Malformed request body (fails schema validation). '401': description: Unauthorized. '403': description: Forbidden (lacks checkin permission). /measurements/water-intake/{date}: get: summary: Get water intake for a date tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: date required: true schema: type: string format: date description: Date in YYYY-MM-DD format. - in: query name: userId schema: type: string format: uuid description: Optional user ID to fetch water intake for (requires diary permission). responses: '200': description: Aggregated water intake for the date. content: application/json: schema: type: object properties: water_ml: type: number description: Total water consumed in milliliters. '400': description: Invalid date format. '403': description: Forbidden. /measurements/water-intake: post: summary: Upsert water intake tags: - Wellness & Metrics security: - apiKeyAuth: [] requestBody: required: true content: application/json: schema: type: object properties: entry_date: type: string format: date description: Date in YYYY-MM-DD format. change_drinks: type: number description: Number of drinks to add (positive) or remove (negative). container_id: type: - number - 'null' description: The water container ID used for volume calculation. user_id: type: string format: uuid description: Optional target user ID (requires checkin permission). required: - entry_date - change_drinks - container_id responses: '200': description: Water intake upserted successfully. '400': description: Validation error. '403': description: Forbidden. /measurements/water-intake/entry/{id}: get: summary: Get a specific water intake entry by ID tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: id required: true schema: type: string format: uuid responses: '200': description: The water intake entry. /measurements/water-intake/{id}: put: summary: Update a water intake entry tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: id required: true schema: type: string format: uuid requestBody: content: application/json: schema: type: object properties: water_ml: type: number description: Water amount in milliliters. entry_date: type: string format: date description: Date in YYYY-MM-DD format. source: type: string description: Source of the water intake entry (e.g. manual, healthkit). responses: '200': description: Water intake entry updated successfully. '400': description: Validation error. '403': description: Forbidden. '404': description: Water intake entry not found. delete: summary: Delete a water intake entry tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: id required: true schema: type: string format: uuid responses: '200': description: Water intake entry deleted successfully. /measurements/check-in: post: summary: Upsert check-in measurements tags: - Wellness & Metrics security: - apiKeyAuth: [] requestBody: required: true content: application/json: schema: type: object properties: entry_date: type: string format: date description: Date in YYYY-MM-DD format. weight: type: - number - 'null' neck: type: - number - 'null' waist: type: - number - 'null' hips: type: - number - 'null' steps: type: - number - 'null' height: type: - number - 'null' body_fat_percentage: type: - number - 'null' required: - entry_date responses: '200': description: Check-in measurements upserted successfully. '400': description: Validation error. /measurements/check-in/latest-on-or-before-date: get: summary: Get latest check-in measurements on or before a date tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: query name: date required: true schema: type: string format: date responses: '200': description: The latest check-in measurements. /measurements/check-in/{date}: get: summary: Get check-in measurements for a specific date tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: date required: true schema: type: string format: date description: Date in YYYY-MM-DD format. - in: query name: userId schema: type: string format: uuid description: Optional user ID to fetch measurements for (requires checkin permission). responses: '200': description: Check-in measurements for the date. '400': description: Invalid date format. '403': description: Forbidden. /measurements/check-in/{id}: put: summary: Update a check-in measurement entry tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: id required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: type: object properties: entry_date: type: string format: date description: Date in YYYY-MM-DD format. weight: type: number neck: type: number waist: type: number hips: type: number steps: type: number height: type: number body_fat_percentage: type: number required: - entry_date responses: '200': description: Measurement updated successfully. '400': description: Validation error or missing entry_date. '404': description: Check-in measurement not found. delete: summary: Delete a check-in measurement entry tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: id required: true schema: type: string format: uuid responses: '200': description: Measurement deleted successfully. /measurements/custom-categories: get: summary: Get all custom measurement categories tags: - Wellness & Metrics security: - apiKeyAuth: [] responses: '200': description: A list of custom measurement categories. content: application/json: schema: type: array items: $ref: '#/components/schemas/CustomMeasurementCategory' post: summary: Create a new custom measurement category tags: - Wellness & Metrics security: - apiKeyAuth: [] requestBody: required: true content: application/json: schema: type: object properties: name: type: string display_name: type: - string - 'null' frequency: type: string description: Tracking frequency (e.g. daily, hourly). measurement_type: type: string data_type: type: - string - 'null' description: Data type (e.g. numeric, boolean, text). required: - name - frequency - measurement_type responses: '201': description: Custom category created successfully. '400': description: Validation error. /measurements/custom-entries: post: summary: Upsert a custom measurement entry tags: - Wellness & Metrics security: - apiKeyAuth: [] requestBody: required: true content: application/json: schema: type: object properties: category_id: type: string format: uuid value: oneOf: - type: number - type: string description: Measurement value (type depends on category data_type). entry_date: type: string format: date description: Date in YYYY-MM-DD format. entry_hour: type: - integer - 'null' description: Hour of day (0-23) for hourly measurements. entry_timestamp: type: string format: date-time description: Full timestamp for the entry. notes: type: string source: type: string description: Source of the entry (e.g. manual, healthkit). required: - category_id - value - entry_date responses: '201': description: Custom entry upserted successfully. '400': description: Validation error. get: summary: Get custom measurement entries with filtering tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: query name: limit schema: type: integer - in: query name: orderBy schema: type: string - in: query name: category_id schema: type: string format: uuid responses: '200': description: List of custom measurement entries. /measurements/custom-entries/{id}: delete: summary: Delete a custom measurement entry tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: id required: true schema: type: string format: uuid responses: '200': description: Entry deleted successfully. /measurements/custom-categories/{id}: put: summary: Update a custom measurement category tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: id required: true schema: type: string format: uuid requestBody: content: application/json: schema: type: object properties: name: type: string display_name: type: - string - 'null' frequency: type: string measurement_type: type: string data_type: type: - string - 'null' responses: '200': description: Category updated successfully. '400': description: Validation error. '404': description: Custom category not found. delete: summary: Delete a custom measurement category tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: id required: true schema: type: string format: uuid responses: '200': description: Category deleted successfully. /measurements/custom-entries/{date}: get: summary: Get custom measurement entries for a specific date tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: date required: true schema: type: string format: date description: Date in YYYY-MM-DD format. responses: '200': description: List of custom measurement entries for the date. '400': description: Invalid date format. /measurements/check-in-measurements-range/{startDate}/{endDate}: get: summary: Get check-in measurements within a date range tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: startDate required: true schema: type: string format: date - in: path name: endDate required: true schema: type: string format: date responses: '200': description: List of check-in measurements. /measurements/custom-measurements-range/{categoryId}/{startDate}/{endDate}: get: summary: Get custom measurements within a date range tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: categoryId required: true schema: type: string format: uuid - in: path name: startDate required: true schema: type: string format: date - in: path name: endDate required: true schema: type: string format: date responses: '200': description: List of custom measurements. /measurements/most-recent/{measurementType}: get: summary: Get most recent measurement of a specific type tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: measurementType required: true schema: type: string description: weight, steps, body_fat_percentage, etc. responses: '200': description: The most recent measurement. /mood: post: summary: Create or update a mood entry tags: - Wellness & Metrics description: Creates a new mood entry or updates an existing one for the authenticated user and specified date. security: - apiKeyAuth: [] requestBody: required: true content: application/json: schema: type: object properties: mood_value: type: integer description: The mood value (e.g., 1-5). notes: type: string description: Optional notes about the mood. entry_date: type: string format: date description: The date of the entry (YYYY-MM-DD). required: - mood_value - entry_date responses: '201': description: Mood entry created or updated successfully. content: application/json: schema: $ref: '#/components/schemas/MoodEntry' '400': description: Mood value is required. '401': description: Unauthorized. '500': description: Internal server error. get: summary: Get mood entries within a date range tags: - Wellness & Metrics description: Retrieves mood entries for a specific user and date range. security: - apiKeyAuth: [] parameters: - in: query name: userId required: true schema: type: string format: uuid description: The ID of the user to fetch entries for. - in: query name: startDate required: true schema: type: string format: date description: Start date (YYYY-MM-DD). - in: query name: endDate required: true schema: type: string format: date description: End date (YYYY-MM-DD). responses: '200': description: A list of mood entries. content: application/json: schema: type: array items: $ref: '#/components/schemas/MoodEntry' '400': description: Missing required query parameters. '401': description: Unauthorized. '500': description: Internal server error. /mood/{id}: get: summary: Get a mood entry by ID tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: id required: true schema: type: string format: uuid responses: '200': description: The mood entry. content: application/json: schema: $ref: '#/components/schemas/MoodEntry' '404': description: Mood entry not found. put: summary: Update a mood entry tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: id required: true schema: type: string format: uuid requestBody: content: application/json: schema: type: object properties: mood_value: type: integer notes: type: string responses: '200': description: Updated mood entry. delete: summary: Delete a mood entry tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: id required: true schema: type: string format: uuid responses: '204': description: Deleted successfully. '404': description: Not found. /mood/date/{entryDate}: get: summary: Get a mood entry by date tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: entryDate required: true schema: type: string format: date responses: '200': description: The mood entry for the date (or empty object if not found). /sleep/analytics: get: summary: Get sleep analytics tags: - Wellness & Metrics description: Retrieves aggregated sleep analytics for a specific date range. security: - apiKeyAuth: [] parameters: - in: query name: startDate required: true schema: type: string format: date description: Start date (YYYY-MM-DD). - in: query name: endDate required: true schema: type: string format: date description: End date (YYYY-MM-DD). responses: '200': description: Sleep analytics data. content: application/json: schema: type: array items: $ref: '#/components/schemas/SleepAnalytics' '400': description: Missing required query parameters. '401': description: Unauthorized. '500': description: Internal server error. /sleep/manual_entry: post: summary: Create a manual sleep entry tags: - Wellness & Metrics description: Allows the user to manually enter sleep data. security: - apiKeyAuth: [] requestBody: required: true content: application/json: schema: type: object properties: entry_date: type: string format: date bedtime: type: string format: date-time wake_time: type: string format: date-time duration_in_seconds: type: integer stage_events: type: array items: type: object record_timezone: type: - string - 'null' description: IANA timezone the entry was recorded in. record_utc_offset_minutes: type: - integer - 'null' description: UTC offset in minutes at recording time. required: - entry_date - bedtime - wake_time - duration_in_seconds responses: '200': description: Sleep entry processed successfully. content: application/json: schema: $ref: '#/components/schemas/SleepEntry' /sleep: get: summary: Get sleep entries within a date range tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: query name: startDate required: true schema: type: string format: date - in: query name: endDate required: true schema: type: string format: date responses: '200': description: A list of sleep entries. content: application/json: schema: type: array items: $ref: '#/components/schemas/SleepEntry' /sleep/details: get: summary: Get sleep entries details within a date range tags: - Wellness & Metrics description: This endpoint currently returns the same as the main GET /sleep endpoint. security: - apiKeyAuth: [] parameters: - in: query name: startDate required: true schema: type: string format: date - in: query name: endDate required: true schema: type: string format: date responses: '200': description: Sleep entries details. /sleep/{id}: put: summary: Update an existing sleep entry tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: id required: true schema: type: string format: uuid requestBody: content: application/json: schema: type: object properties: bedtime: type: string format: date-time wake_time: type: string format: date-time duration_in_seconds: type: integer stage_events: type: array items: type: object record_timezone: type: - string - 'null' description: IANA timezone the entry was recorded in. Omit to preserve the stored value. record_utc_offset_minutes: type: - integer - 'null' description: UTC offset in minutes at recording time. Omit to preserve the stored value. responses: '200': description: Sleep entry updated successfully. delete: summary: Delete a sleep entry tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: id required: true schema: type: string format: uuid responses: '200': description: Sleep entry deleted successfully. /v2/measurements/water-intake/entry/{id}: get: summary: Get a water intake entry by ID tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: id required: true schema: type: string format: uuid description: The unique identifier of the water intake entry. - in: header name: x-on-behalf-of-user-id schema: type: string description: Target user ID for family access. responses: '200': description: Water intake entry retrieved successfully. content: application/json: schema: type: object properties: id: type: string format: uuid water_ml: type: number entry_date: type: string format: date created_at: type: string format: date-time '400': description: Validation error - invalid UUID format. content: application/json: schema: type: object properties: error: type: string example: Validation error details: type: object '403': description: Forbidden - user doesn't have permission. content: application/json: schema: type: object properties: error: type: string example: 'Forbidden: access denied.' '404': description: Water intake entry not found. content: application/json: schema: type: object properties: error: type: string example: Water intake entry not found. /v2/measurements/water-intake/{date}: get: summary: Get water intake for a date tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: date required: true schema: type: string format: date description: Date in YYYY-MM-DD format. - in: header name: x-on-behalf-of-user-id schema: type: string description: Target user ID for family access. responses: '200': description: Water intake data retrieved successfully. content: application/json: schema: type: array items: type: object properties: id: type: string format: uuid water_ml: type: number entry_date: type: string format: date created_at: type: string format: date-time '400': description: Validation error - invalid date format. content: application/json: schema: type: object properties: error: type: string example: Validation error details: type: object '403': description: Forbidden - user doesn't have permission. content: application/json: schema: type: object properties: error: type: string example: 'Forbidden: access denied.' /v2/measurements/water-intake: post: summary: Upsert a water intake entry tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: header name: x-on-behalf-of-user-id schema: type: string description: Target user ID for family access. requestBody: required: true content: application/json: schema: type: object required: - entry_date - change_drinks properties: entry_date: type: string format: date description: Date of water intake in YYYY-MM-DD format. example: '2023-01-01' change_drinks: type: number description: Number of drinks to add (positive) or remove (negative). example: 1 container_id: type: - number - 'null' description: Optional container ID for tracking. example: 1 responses: '200': description: Water intake entry upserted successfully. content: application/json: schema: type: object properties: id: type: string format: uuid water_ml: type: number entry_date: type: string format: date created_at: type: string format: date-time '400': description: Validation error - missing required fields or invalid data. content: application/json: schema: type: object properties: error: type: string example: Invalid request body details: type: object '403': description: Forbidden - user doesn't have permission. content: application/json: schema: type: object properties: error: type: string example: 'Forbidden: access denied.' /v2/measurements/water-intake/{id}: put: summary: Update a water intake entry tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: id required: true schema: type: string format: uuid description: The unique identifier of the water intake entry. - in: header name: x-on-behalf-of-user-id schema: type: string description: Target user ID for family access. requestBody: content: application/json: schema: type: object properties: water_ml: type: number description: Updated water amount in milliliters. example: 250 entry_date: type: string format: date description: Updated date in YYYY-MM-DD format. example: '2023-01-01' source: type: string description: Source of the update (e.g., 'manual', 'garmin'). example: manual responses: '200': description: Water intake entry updated successfully. content: application/json: schema: type: object properties: id: type: string format: uuid water_ml: type: number entry_date: type: string format: date updated_at: type: string format: date-time '400': description: Validation error - invalid UUID or request body. content: application/json: schema: type: object properties: error: type: string example: Validation error details: type: object '403': description: Forbidden - user doesn't have permission. content: application/json: schema: type: object properties: error: type: string example: 'Forbidden: access denied.' '404': description: Water intake entry not found. content: application/json: schema: type: object properties: error: type: string example: Water intake entry not found. delete: summary: Delete a water intake entry tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: id required: true schema: type: string format: uuid - in: header name: x-on-behalf-of-user-id schema: type: string description: Target user ID for family access. responses: '200': description: Water intake entry deleted successfully. '403': description: Forbidden. '404': description: Water intake entry not found. /v2/measurements/water-intake/{date}/log: get: summary: Get water intake log entries for a date tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: date required: true schema: type: string format: date description: Date in YYYY-MM-DD format. - in: header name: x-on-behalf-of-user-id schema: type: string description: Target user ID for family access. responses: '200': description: Water intake log entries retrieved successfully. content: application/json: schema: type: array items: type: object properties: id: type: string format: uuid water_ml: type: number container_name: type: - string - 'null' container_id: type: - integer - 'null' created_at: type: string format: date-time '400': description: Validation error. '403': description: Forbidden. /v2/measurements/water-intake/log/{id}: delete: summary: Delete a water intake log entry tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: id required: true schema: type: string format: uuid - in: header name: x-on-behalf-of-user-id schema: type: string description: Target user ID for family access. responses: '200': description: Water intake log entry deleted and daily total updated. '403': description: Forbidden. '404': description: Log entry not found. /water-containers: post: summary: Create a new water container tags: - Wellness & Metrics security: - apiKeyAuth: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/WaterContainer' responses: '201': description: Water container created successfully. get: summary: Get all water containers for the user tags: - Wellness & Metrics security: - apiKeyAuth: [] responses: '200': description: A list of water containers. content: application/json: schema: type: array items: $ref: '#/components/schemas/WaterContainer' /water-containers/{id}: put: summary: Update a water container tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: id required: true schema: type: integer requestBody: content: application/json: schema: $ref: '#/components/schemas/WaterContainer' responses: '200': description: Water container updated successfully. delete: summary: Delete a water container tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: id required: true schema: type: integer responses: '200': description: Deleted successfully. /water-containers/{id}/set-primary: put: summary: Set a water container as primary tags: - Wellness & Metrics security: - apiKeyAuth: [] parameters: - in: path name: id required: true schema: type: integer responses: '200': description: Primary container set successfully. /water-containers/primary: get: summary: Get the primary water container for the user tags: - Wellness & Metrics security: - apiKeyAuth: [] responses: '200': description: The primary water container. components: schemas: SleepEntry: type: object properties: id: type: string format: uuid user_id: type: string format: uuid entry_date: type: string format: date bedtime: type: string format: date-time wake_time: type: string format: date-time duration_in_seconds: type: integer source: type: string sleep_score: type: - integer - 'null' record_timezone: type: - string - 'null' description: IANA timezone the entry was recorded in. NULL falls back to record_utc_offset_minutes, then the profile timezone. record_utc_offset_minutes: type: - integer - 'null' description: UTC offset in minutes at recording time; used when record_timezone is absent. created_at: type: string format: date-time updated_at: type: string format: date-time required: - entry_date - bedtime - wake_time - duration_in_seconds SleepAnalytics: type: object properties: date: type: string format: date totalSleepDuration: type: integer timeAsleep: type: integer sleepScore: type: number earliestBedtime: type: - string - 'null' format: date-time latestWakeTime: type: - string - 'null' format: date-time sleepEfficiency: type: number sleepDebt: type: number stagePercentages: type: object additionalProperties: type: number awakePeriods: type: integer totalAwakeDuration: type: integer WaterContainer: type: object properties: id: type: integer user_id: type: string format: uuid name: type: string volume: type: number description: Volume in specified unit unit: type: string description: ml, oz, etc. is_primary: type: boolean servings_per_container: type: number created_at: type: string format: date-time updated_at: type: string format: date-time required: - name - volume - unit MoodEntry: type: object properties: id: type: string format: uuid user_id: type: string format: uuid mood_value: type: integer description: Mood value (e.g., 1-5 or 0-10) notes: type: - string - 'null' entry_date: type: string format: date created_at: type: string format: date-time updated_at: type: string format: date-time required: - mood_value - entry_date CustomMeasurementCategory: type: object properties: id: type: string format: uuid user_id: type: - string - 'null' format: uuid name: type: string display_name: type: - string - 'null' frequency: type: string measurement_type: type: - string - 'null' data_type: type: - string - 'null' enum: - numeric - boolean - text created_at: type: string format: date-time updated_at: type: string format: date-time required: - name - frequency FastingLog: type: object properties: id: type: string format: uuid description: The unique identifier for the fasting log. user_id: type: string format: uuid description: The ID of the user who owns the fasting log. start_time: type: string format: date-time description: The date and time when the fast started. target_end_time: type: string format: date-time description: The scheduled or target end time for the fast. end_time: type: string format: date-time description: The date and time when the fast ended (null for active fasts). duration_minutes: type: integer description: The total duration of the fast in minutes. fasting_type: type: string description: The type of fast (e.g., "16:8", "20:4", "OMAD"). status: type: string enum: - ACTIVE - COMPLETED description: The status of the fasting log. created_at: type: string format: date-time description: The date and time when the log was created. updated_at: type: string format: date-time description: The date and time when the log was last updated. required: - id - user_id - start_time - fasting_type - status securitySchemes: apiKeyAuth: type: apiKey in: header name: x-api-key description: API key authentication via x-api-key header. x-provenance: generated: '2026-08-27' method: derived source: https://github.com/CodeWithCJ/SparkyFitness — assembled from the project's own swagger-jsdoc configuration (SparkyFitnessServer/config/swagger.ts) and the 419 @swagger JSDoc blocks in SparkyFitnessServer/routes/**, using the same scan paths and the same cookieAuth->apiKeyAuth post-processing the server applies. This is the identical document a running instance serves at GET /api/api-docs/json (Swagger UI at /api/api-docs/swagger, ReDoc at /api/api-docs/redoc). note: 'Not fetched from a live host: SparkyFitness is self-hosted and the project operates no public instance, so the contract can only be read from the source that generates it. Upstream sets no operationIds; paths+methods are the stable identifiers.' upstream_version: server package.json 1.6.4 (release v1.6.4, 2026-08-27)