> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fitsociety.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Preview workbook-derived running structure and unresolved rules

> Coach-only; company-scoped, linked-client and member-scope checks apply. Requires training.programmes.view and all three company cardio gates. Preview is read-only and builds the first two/three weeks when explicit prescription inputs are complete. Initial generation fills only an empty Assigned calendar programme, never existing workouts; missing inputs or invalid volume return 422 without writing. Calendar weeks include the race week; training ends before the race date. Hard volume limits override rounded workbook requests and growing weeks stay easy. Goal update replaces only the structured race goal.

Requires the workout_client_plans:write scope. This operation maps to /app/v1/workout/cardio/clients/:clientId/running-plan/preview and retains its Workout V2 permission, feature-flag, and resource-scope checks.

The clientId path parameter is resolved inside the company bound to the Public API token when present.



## OpenAPI

````yaml /openapi/public-v1.json post /public/v1/workout/cardio/clients/{clientId}/running-plan/preview
openapi: 3.1.0
info:
  title: FITsociety Public API v1
  version: 1.0.0
  description: >-
    Developer Public API endpoints under `/public/v1`. This reference is
    filtered to OAuth/Bearer Public API resources and excludes provider callback
    receivers, storefront routes, public widgets, wishlist routes, and
    access-device validation endpoints.
  contact:
    name: FITsociety Engineering
servers:
  - url: https://api.fitsociety.io
    description: Production
security: []
tags:
  - name: Workout
    description: >-
      Workout V2 libraries, programmes, client plans, calendars, sessions,
      groups, settings and progress. AI operations are excluded.
  - name: OAuth
    description: Public API OAuth endpoints for server-to-server client credentials.
  - name: Health
    description: Public API token health checks.
  - name: Platform
    description: >-
      Inspect Public API client context, capabilities, scopes, and redacted
      audit logs.
  - name: Company Catalog
    description: Read and manage company profile metadata and locations.
  - name: Clients
    description: >-
      Create and manage clients through the Public API using Bearer access
      tokens.
  - name: Coaches
    description: Retrieve coaches for the authenticated company via integrations.
  - name: Calendar Events
    description: Read Public API calendar events.
  - name: Calendar Templates
    description: >-
      Read and manage event types and event templates used by calendar
      availability and bookings.
  - name: Calendar Extensions
    description: >-
      Read recurring bookings, booking requests, calendar tasks, and
      availability closure metadata.
  - name: Availability
    description: Read bookable availability slots and signed availability tokens.
  - name: Availability Management
    description: >-
      Manage coach and location availability templates used to derive bookable
      slots.
  - name: Bookings
    description: Read and manage Public API bookings.
  - name: Finance
    description: >-
      Read invoices, transactions, products, subscriptions, and memberships with
      guarded finance writes.
  - name: Credits
    description: >-
      Read company-wide and client-scoped credit allocations, mutations, and
      guarded credit adjustments.
  - name: Exports
    description: >-
      Create and monitor asynchronous company exports through Public API Bearer
      endpoints.
  - name: Webhooks
    description: >-
      Manage outbound webhook subscriptions and inspect delivery attempts
      through Public API Bearer endpoints.
  - name: Measurements
    description: Read and write client measurement entries.
  - name: Progress Photos
    description: Read client progress photo metadata and short-lived signed media URLs.
  - name: Forms
    description: Read, create, update, and archive company form templates.
  - name: Intakes
    description: Assign intake forms and read client intake assignments and submissions.
  - name: Check-ups
    description: >-
      Schedule and cancel client check-ups and read their status and
      submissions.
  - name: Documents
    description: >-
      Read client document and folder metadata, register external document
      links, update metadata, and archive documents from Public API listings.
      Binary upload, permanent deletion, and company-wide document management
      are not exposed.
  - name: Habits
    description: Read habits and habit entries.
  - name: Goals
    description: Read client goal summaries.
  - name: Conversations
    description: >-
      Read and manage direct and group chat conversations through the Public
      API.
  - name: Reports
    description: Read aggregate attendance, revenue, and retention summaries.
paths:
  /public/v1/workout/cardio/clients/{clientId}/running-plan/preview:
    post:
      tags:
        - Workout
      summary: Preview workbook-derived running structure and unresolved rules
      description: >-
        Coach-only; company-scoped, linked-client and member-scope checks apply.
        Requires training.programmes.view and all three company cardio gates.
        Preview is read-only and builds the first two/three weeks when explicit
        prescription inputs are complete. Initial generation fills only an empty
        Assigned calendar programme, never existing workouts; missing inputs or
        invalid volume return 422 without writing. Calendar weeks include the
        race week; training ends before the race date. Hard volume limits
        override rounded workbook requests and growing weeks stay easy. Goal
        update replaces only the structured race goal.


        Requires the workout_client_plans:write scope. This operation maps to
        /app/v1/workout/cardio/clients/:clientId/running-plan/preview and
        retains its Workout V2 permission, feature-flag, and resource-scope
        checks.


        The clientId path parameter is resolved inside the company bound to the
        Public API token when present.
      operationId: publicWorkoutpostPublicV1WorkoutCardioClientsClientIdRunningPlanPreview
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
            minLength: 1
            maxLength: 200
            example: booking-create-20260714-001
          description: >-
            Required for Public API write requests. Reusing the same key with
            the same method, path, and body replays the stored successful
            response; reusing it with a different request returns `409
            idempotency.conflict`.
        - name: clientId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: >-
                #/components/schemas/PublicWorkoutSourcePOSTAppV1WorkoutCardioClientsClientIdRunningPlanPreviewRequest
      responses:
        '200':
          description: Successful result.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/PublicApiWriteSuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: >-
                          #/components/schemas/PublicWorkoutSourcePOSTAppV1WorkoutCardioClientsClientIdRunningPlanPreviewResponse200
              examples:
                success:
                  summary: Successful response
                  value:
                    data:
                      canGenerate: true
                      policyVersion: safety-calendar-v1
                      schedule:
                        layout: calendar_week
                        mode: multi_week
                        releasePolicy: weekly_from_start
                        startDate: '2026-07-14'
                        weeks:
                          - weekNumber: 1
                            days:
                              - weekday: 1
                                isRestDay: false
                                items:
                                  - _id: 67f1234567890abcdef1234
                                    order: 1
                                    startTime: '08:30'
                                    plannedDurationMinutes: 45
                                    status: today
                                    plannedDate: '2026-09-08'
                                    scheduledDate: '2026-09-08'
                                    source: programme
                                    clientAdjustment:
                                      action: moved
                                      occurrenceDate: '2026-09-08'
                                      scheduledDate: '2026-09-08'
                                      changedAt: null
                                    canClientRestore: true
                                    type: workout
                                    planMomentId: 67f1234567890abcdef1234
                      sourceVersion: plansjablonen-v259-1
                      goal:
                        distance: 5K
                        goalTimeSec: 1
                        raceDate: '2026-07-14'
                        acceptGoalAsChallenge: true
                      startDate: '2026-07-14'
                      totalWeeks: 1
                      templateKey: 5K
                      variant: true
                      baselineKm: 1
                      peakKm: 1
                      requestedPeakKm: 1
                      phases:
                        base: 1
                        threshold: 1
                        sharpen: 1
                      taperWeeks: 1
                      concreteWeeks: 2
                      runWeekdays:
                        - 1
                      qualityWeekdays:
                        - 1
                      longRunWeekday: 1
                      paces:
                        easy: 1
                        threshold: 1
                        interval: 1
                        repetition: 1
                        racePace: 1
                      baseline:
                        source: logged_activities
                        startDate: '2026-07-14'
                        endDate: '2026-07-14'
                        timeZone: Europe/Amsterdam
                        calculatedAt: '2026-07-14T10:00:00.000Z'
                        complete: true
                        baselineWeeklyKm: 1
                        weeklyTotals:
                          - weekStart: '2026-07-14'
                            distanceKm: 1
                            runCount: 1
                            missingDistanceCount: 1
                        reasonCodes:
                          - RUNNING_BASELINE_ACTIVITY_TYPE_MISSING
                      weeks:
                        - weekNumber: 1
                          weekStart: '2026-07-14'
                          phase: 1
                          phaseName: Base building
                          theme: Base building
                          weekKind: build
                          rotationWeek: 1
                          targetVolumeKm: 1
                          concrete: true
                          requestedVolumeKm: 1
                          allocatedKm: 1
                          remainingKm: 1
                          concreteRequested: true
                          sessions:
                            - weekday: 1
                              code: drempel_c
                              sessionType: threshold_continuous
                              controlMode: hr
                              longRunTargetMinutes: 1
                              ladder:
                                step: 1
                                reps: 1
                                kmPerRep: 1
                              continuousMinutes: 1
                              recoveryRangeSec:
                                low: 1
                                high: 1
                              cardio:
                                slotKey: string
                                sessionType: easy
                                controlMode: pace
                                ladderStep: 1
                                poolLengthM: 25
                                blocks:
                                  - _id: 67f1234567890abcdef1234
                                    repeat: 1
                                    steps:
                                      - _id: 67f1234567890abcdef1234
                                        kind: warmup
                                        durationType: time
                                        durationValue: 1
                                        target:
                                          kind: paceZone
                                          zone: E
                                          basis: lthr
                                          low: 1
                                          high: 1
                                        secondaryTarget:
                                          kind: paceZone
                                          zone: E
                                          basis: lthr
                                          low: 1
                                          high: 1
                                        notes: string
                                        stroke: free
                                        equipment:
                                          - pullBuoy
                                        restMode: rest
                                        sendOffSec: 1
                                        cadence:
                                          low: 1
                                          high: 1
                                sourceTemplateId: null
                              totals:
                                durationSec: 1
                                distanceM: 1
                                plannedDurationMinutes: 1
                                targetDistanceMeters: 1
                                zoneTimeSec: {}
                      diagnostics:
                        - code: RUNNING_PLAN_INPUT_MISSING
                          severity: error
                          field: string
                          fields:
                            - string
                          value: 1
                          limit: 1
                          previousVolumeKm: 1
                          targetVolumeKm: 1
                          raceWeekStart: '2026-07-14'
                          lastWeekStart: '2026-07-14'
                    meta:
                      requestId: 4f849d7d-f4f1-45cc-b4b7-3984a3d17f83
                      rateLimit:
                        limit: 10
                        remaining: 9
                        resetSeconds: 1
                      idempotency:
                        replayed: false
        '400':
          description: Invalid client/plan identifier or missing request body.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiError'
              examples:
                invalidRequest:
                  summary: Invalid request
                  value:
                    error:
                      code: 400
                      key: request.invalid
                      message: The request is invalid.
                    meta:
                      requestId: 4f849d7d-f4f1-45cc-b4b7-3984a3d17f83
                      rateLimit:
                        limit: 10
                        remaining: 9
                        resetSeconds: 1
                idempotencyRequired:
                  summary: Missing Idempotency-Key
                  value:
                    error:
                      code: 400
                      key: idempotency.required
                      message: >-
                        Idempotency-Key header is required for Public API write
                        requests.
                    meta:
                      requestId: 4f849d7d-f4f1-45cc-b4b7-3984a3d17f83
                      rateLimit:
                        limit: 10
                        remaining: 9
                        resetSeconds: 1
                idempotencyInvalid:
                  summary: Invalid Idempotency-Key
                  value:
                    error:
                      code: 400
                      key: idempotency.invalid
                      message: Idempotency-Key header must be 200 characters or fewer.
                    meta:
                      requestId: 4f849d7d-f4f1-45cc-b4b7-3984a3d17f83
                      rateLimit:
                        limit: 10
                        remaining: 9
                        resetSeconds: 1
        '401':
          $ref: '#/components/schemas/ErrorResponse'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiError'
              examples:
                missingBearer:
                  summary: Missing Bearer token
                  value:
                    error:
                      code: 401
                      key: auth.missing_bearer
                      message: Authorization Bearer token is required.
                    meta:
                      requestId: 4f849d7d-f4f1-45cc-b4b7-3984a3d17f83
                      rateLimit:
                        limit: 10
                        remaining: 9
                        resetSeconds: 1
                invalidToken:
                  summary: Invalid or expired token
                  value:
                    error:
                      code: 401
                      key: auth.invalid_token
                      message: The access token is invalid or expired.
                    meta:
                      requestId: 4f849d7d-f4f1-45cc-b4b7-3984a3d17f83
                      rateLimit:
                        limit: 10
                        remaining: 9
                        resetSeconds: 1
                invalidClient:
                  summary: Inactive or revoked client
                  value:
                    error:
                      code: 401
                      key: auth.invalid_client
                      message: The Public API client is inactive or revoked.
                    meta:
                      requestId: 4f849d7d-f4f1-45cc-b4b7-3984a3d17f83
                      rateLimit:
                        limit: 10
                        remaining: 9
                        resetSeconds: 1
        '403':
          description: >-
            Disabled cardio gates, wrong actor, unlinked client or insufficient
            permission/member scope.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiError'
              examples:
                insufficientScopes:
                  summary: Missing required scope
                  value:
                    error:
                      code: 403
                      key: scopes.insufficient
                      message: The access token does not include the required scope.
                      details:
                        requiredScopes:
                          - required:scope
                    meta:
                      requestId: 4f849d7d-f4f1-45cc-b4b7-3984a3d17f83
                      rateLimit:
                        limit: 10
                        remaining: 9
                        resetSeconds: 1
        '404':
          $ref: '#/components/schemas/ErrorResponse'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiError'
              examples:
                notFound:
                  summary: Resource not found
                  value:
                    error:
                      code: 404
                      key: resource.not_found
                      message: The requested Public API resource was not found.
                    meta:
                      requestId: 4f849d7d-f4f1-45cc-b4b7-3984a3d17f83
                      rateLimit:
                        limit: 10
                        remaining: 9
                        resetSeconds: 1
        '409':
          $ref: '#/components/schemas/ErrorResponse'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiError'
              examples:
                idempotencyConflict:
                  summary: Idempotency-Key conflict
                  value:
                    error:
                      code: 409
                      key: idempotency.conflict
                      message: >-
                        Idempotency-Key was already used with a different
                        request.
                    meta:
                      requestId: 4f849d7d-f4f1-45cc-b4b7-3984a3d17f83
                      rateLimit:
                        limit: 10
                        remaining: 9
                        resetSeconds: 1
                idempotencyInProgress:
                  summary: Idempotency-Key in progress
                  value:
                    error:
                      code: 409
                      key: idempotency.in_progress
                      message: >-
                        Idempotency-Key is already processing for this Public
                        API client.
                    meta:
                      requestId: 4f849d7d-f4f1-45cc-b4b7-3984a3d17f83
                      rateLimit:
                        limit: 10
                        remaining: 9
                        resetSeconds: 1
        '422':
          description: >-
            RUNNING_PLAN_INVALID with invalid field path;
            RUNNING_PLAN_UNRESOLVED with generation diagnostics;
            RUNNING_PLAN_NOT_EMPTY or RUNNING_PLAN_CHANGED when initial
            generation cannot safely fill the programme;
            RUNNING_PLAN_GOAL_LOCKED when updating a generated goal without
            reviewed prescription adaptation. Preview diagnostics use a 200
            response.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiError'
              examples:
                emptyBody:
                  summary: Empty or invalid JSON object body
                  value:
                    error:
                      code: 422
                      key: EMPTY_BODY
                      message: Request body must be a non-empty JSON object.
                    meta:
                      requestId: 4f849d7d-f4f1-45cc-b4b7-3984a3d17f83
                      rateLimit:
                        limit: 10
                        remaining: 9
                        resetSeconds: 1
        '429':
          $ref: '#/components/schemas/ErrorResponse'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiError'
              examples:
                rateLimitExceeded:
                  summary: Rate limit exceeded
                  value:
                    error:
                      code: 429
                      key: rate_limit.exceeded
                      message: Too many Public API requests. Retry later.
                    meta:
                      requestId: 4f849d7d-f4f1-45cc-b4b7-3984a3d17f83
                      rateLimit:
                        limit: 10
                        remaining: 0
                        resetSeconds: 1
                        retryAfterSeconds: 1
        '500':
          description: Unexpected server error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiError'
              examples:
                serverInternalError:
                  summary: Unexpected server error
                  value:
                    error:
                      code: 500
                      key: server.internal_error
                      message: An unexpected Public API server error occurred.
                    meta:
                      requestId: 4f849d7d-f4f1-45cc-b4b7-3984a3d17f83
                      rateLimit:
                        limit: 10
                        remaining: 9
                        resetSeconds: 1
      security:
        - PublicBearerAuth: []
      x-codeSamples:
        - lang: cURL
          label: cURL
          source: >-
            curl -X POST
            "https://api.fitsociety.io/public/v1/workout/cardio/clients/{clientId}/running-plan/preview"
            \
              -H "Authorization: Bearer <access_token>" \
              -H "Idempotency-Key: <stable_request_key>" \
              -H "Content-Type: application/json" \
              -d '{}'
components:
  schemas:
    PublicWorkoutSourcePOSTAppV1WorkoutCardioClientsClientIdRunningPlanPreviewRequest:
      $ref: '#/components/schemas/PublicWorkoutSourceRunningPlanPreviewInput'
    PublicApiWriteSuccessResponse:
      type: object
      additionalProperties: false
      required:
        - data
        - meta
      properties:
        data:
          type: object
        meta:
          $ref: '#/components/schemas/PublicApiWriteMeta'
    PublicWorkoutSourcePOSTAppV1WorkoutCardioClientsClientIdRunningPlanPreviewResponse200:
      type: object
      required:
        - canGenerate
        - sourceVersion
        - weeks
        - diagnostics
      description: >-
        Read-only preview using the approved safety/calendar precedence. Builds
        concrete prescriptions only inside the requested horizon. Complete,
        valid inputs yield a candidate schedule; missing inputs and safety
        errors block generation.
      properties:
        canGenerate:
          type: boolean
        policyVersion:
          type: string
          enum:
            - safety-calendar-v1
        schedule:
          type: object
          required:
            - layout
            - mode
            - releasePolicy
            - startDate
            - weeks
          properties:
            layout:
              type: string
              enum:
                - calendar_week
            mode:
              type: string
              enum:
                - multi_week
            releasePolicy:
              type: string
              enum:
                - weekly_from_start
            startDate:
              type: string
              format: date
            weeks:
              type: array
              items:
                type: object
                required:
                  - weekNumber
                  - days
                properties:
                  weekNumber:
                    type: integer
                    minimum: 1
                    example: 1
                  days:
                    type: array
                    items:
                      type: object
                      required:
                        - weekday
                        - isRestDay
                        - items
                      properties:
                        weekday:
                          type: integer
                          minimum: 1
                          maximum: 7
                          example: 1
                          description: 'ISO weekday number: 1 is Monday and 7 is Sunday.'
                        isRestDay:
                          type: boolean
                          example: false
                        items:
                          type: array
                          items:
                            oneOf:
                              - type: object
                                additionalProperties: false
                                required:
                                  - type
                                  - order
                                  - planMomentId
                                properties:
                                  _id:
                                    type: string
                                    example: 67f1234567890abcdef1234
                                  order:
                                    type: integer
                                    minimum: 1
                                    example: 1
                                  startTime:
                                    type: string
                                    pattern: ^(?:[01]\d|2[0-3]):[0-5]\d$|^$
                                    example: '08:30'
                                  plannedDurationMinutes:
                                    type:
                                      - number
                                      - 'null'
                                    minimum: 0
                                    example: 45
                                    description: >-
                                      Planned duration in minutes; null when no
                                      target is set.
                                  status:
                                    type:
                                      - string
                                      - 'null'
                                    enum:
                                      - in_progress
                                      - completed
                                      - overdue
                                      - today
                                      - upcoming
                                      - null
                                    readOnly: true
                                    example: today
                                    description: >-
                                      Occurrence presentation status. Template
                                      items use null; cancelled occurrences fall
                                      back to overdue, today, or upcoming.
                                  plannedDate:
                                    oneOf:
                                      - type: string
                                        format: date
                                        pattern: ^\d{4}-\d{2}-\d{2}$
                                        example: '2026-09-08'
                                      - type: string
                                        enum:
                                          - ''
                                        example: ''
                                    readOnly: true
                                    description: >-
                                      Original authored occurrence date for a
                                      calendar response item.
                                  scheduledDate:
                                    oneOf:
                                      - type: string
                                        format: date
                                        pattern: ^\d{4}-\d{2}-\d{2}$
                                        example: '2026-09-08'
                                      - type: string
                                        enum:
                                          - ''
                                        example: ''
                                    readOnly: true
                                    description: >-
                                      Effective calendar date after a client
                                      move; otherwise plannedDate.
                                  source:
                                    type: string
                                    enum:
                                      - programme
                                    readOnly: true
                                  clientAdjustment:
                                    oneOf:
                                      - type: object
                                        required:
                                          - action
                                          - occurrenceDate
                                          - scheduledDate
                                          - changedAt
                                        properties:
                                          action:
                                            type: string
                                            enum:
                                              - moved
                                              - skipped
                                          occurrenceDate:
                                            type: string
                                            format: date
                                            pattern: ^\d{4}-\d{2}-\d{2}$
                                            example: '2026-09-08'
                                          scheduledDate:
                                            oneOf:
                                              - type: string
                                                format: date
                                                pattern: ^\d{4}-\d{2}-\d{2}$
                                                example: '2026-09-08'
                                              - type: string
                                                enum:
                                                  - ''
                                                example: ''
                                          changedAt:
                                            type:
                                              - string
                                              - 'null'
                                            format: date-time
                                            example: null
                                      - type: 'null'
                                    readOnly: true
                                  canClientRestore:
                                    type: boolean
                                    readOnly: true
                                  type:
                                    type: string
                                    enum:
                                      - workout
                                    example: workout
                                  planMomentId:
                                    type: string
                                    example: 67f1234567890abcdef1234
                              - type: object
                                additionalProperties: false
                                required:
                                  - type
                                  - order
                                  - activityType
                                  - name
                                properties:
                                  _id:
                                    type: string
                                    example: 67f1234567890abcdef1234
                                  order:
                                    type: integer
                                    minimum: 1
                                    example: 1
                                  startTime:
                                    type: string
                                    pattern: ^(?:[01]\d|2[0-3]):[0-5]\d$|^$
                                    example: '08:30'
                                  plannedDurationMinutes:
                                    type:
                                      - number
                                      - 'null'
                                    minimum: 0
                                    example: 45
                                    description: >-
                                      Planned duration in minutes; null when no
                                      target is set.
                                  status:
                                    type:
                                      - string
                                      - 'null'
                                    enum:
                                      - in_progress
                                      - completed
                                      - overdue
                                      - today
                                      - upcoming
                                      - null
                                    readOnly: true
                                    example: today
                                    description: >-
                                      Occurrence presentation status. Template
                                      items use null; cancelled occurrences fall
                                      back to overdue, today, or upcoming.
                                  plannedDate:
                                    oneOf:
                                      - type: string
                                        format: date
                                        pattern: ^\d{4}-\d{2}-\d{2}$
                                        example: '2026-09-08'
                                      - type: string
                                        enum:
                                          - ''
                                        example: ''
                                    readOnly: true
                                    description: >-
                                      Original authored occurrence date for a
                                      calendar response item.
                                  scheduledDate:
                                    oneOf:
                                      - type: string
                                        format: date
                                        pattern: ^\d{4}-\d{2}-\d{2}$
                                        example: '2026-09-08'
                                      - type: string
                                        enum:
                                          - ''
                                        example: ''
                                    readOnly: true
                                    description: >-
                                      Effective calendar date after a client
                                      move; otherwise plannedDate.
                                  source:
                                    type: string
                                    enum:
                                      - programme
                                    readOnly: true
                                  clientAdjustment:
                                    oneOf:
                                      - type: object
                                        required:
                                          - action
                                          - occurrenceDate
                                          - scheduledDate
                                          - changedAt
                                        properties:
                                          action:
                                            type: string
                                            enum:
                                              - moved
                                              - skipped
                                          occurrenceDate:
                                            type: string
                                            format: date
                                            pattern: ^\d{4}-\d{2}-\d{2}$
                                            example: '2026-09-08'
                                          scheduledDate:
                                            oneOf:
                                              - type: string
                                                format: date
                                                pattern: ^\d{4}-\d{2}-\d{2}$
                                                example: '2026-09-08'
                                              - type: string
                                                enum:
                                                  - ''
                                                example: ''
                                          changedAt:
                                            type:
                                              - string
                                              - 'null'
                                            format: date-time
                                            example: null
                                      - type: 'null'
                                    readOnly: true
                                  canClientRestore:
                                    type: boolean
                                    readOnly: true
                                  type:
                                    type: string
                                    enum:
                                      - activity
                                    example: activity
                                  activityType:
                                    type: string
                                    enum:
                                      - running
                                      - cycling
                                      - walking
                                      - swimming
                                      - rowing
                                      - padel
                                      - mobility
                                      - other
                                    example: running
                                  name:
                                    type: array
                                    minItems: 1
                                    items:
                                      type: object
                                      required:
                                        - lang
                                        - value
                                      properties:
                                        lang:
                                          type: string
                                          enum:
                                            - en
                                            - nl
                                            - fr
                                            - de
                                            - es
                                          example: en
                                        value:
                                          type: string
                                          example: Full Body Strength
                                    example:
                                      - lang: en
                                        value: Full Body Strength
                                      - lang: nl
                                        value: Full Body Kracht
                                  description:
                                    type: array
                                    items:
                                      type: object
                                      required:
                                        - lang
                                        - value
                                      properties:
                                        lang:
                                          type: string
                                          enum:
                                            - en
                                            - nl
                                            - fr
                                            - de
                                            - es
                                          example: en
                                        value:
                                          type: string
                                          example: Full Body Strength
                                  cardio:
                                    type: object
                                    additionalProperties: false
                                    description: >-
                                      Optional structured activity prescription.
                                      Requires workoutsectionv2 +
                                      workoutV2ProgrammeCalendar +
                                      workoutV2CardioBuilder. Omitted from
                                      disabled reads. Supported sports: running
                                      (paceZone E/T/I/R/RP, absolute pace,
                                      absolute HR, RPE), walking (pace, HR,
                                      RPE), cycling (power, HR, RPE), rowing
                                      (pace, power, HR, RPE), swimming (pace,
                                      RPE). Rejected for workout, padel,
                                      mobility and other items. Totals overwrite
                                      planned duration/distance; unknown time or
                                      distance contributes zero.
                                    properties:
                                      slotKey:
                                        type: string
                                        description: >-
                                          Generated when missing; retain across
                                          edits, copies and weeks.
                                      sessionType:
                                        type: string
                                        enum:
                                          - easy
                                          - zone2
                                          - long_run
                                          - threshold_continuous
                                          - threshold_reps
                                          - interval
                                          - race_pace
                                          - time_trial
                                          - race
                                        description: >-
                                          Running only. Template session codes:
                                          threshold_continuous = drempel_c,
                                          threshold_reps = drempel_r, interval,
                                          race_pace = doeltempo, zone2. A typed
                                          session with empty blocks is a skeleton
                                          to be filled later.
                                      controlMode:
                                        type: string
                                        enum:
                                          - pace
                                          - hr
                                        description: >-
                                          Binding signal. Defaults from
                                          sessionType: hr for easy, zone2 and
                                          long_run; pace for threshold_continuous,
                                          threshold_reps, interval and race_pace;
                                          none for time_trial and race. A
                                          contradicting value is rejected.
                                      ladderStep:
                                        type: integer
                                        minimum: 1
                                        description: >-
                                          Ladder position: interval 1–8,
                                          threshold_reps 1–7, threshold_continuous
                                          1–5 (15/18/20/22/25 min). Rejected for
                                          other session types.
                                      poolLengthM:
                                        type: number
                                        enum:
                                          - 25
                                          - 50
                                        description: Swimming only.
                                      blocks:
                                        type: array
                                        maxItems: 10
                                        items:
                                          type: object
                                          additionalProperties: false
                                          properties:
                                            _id:
                                              type: string
                                              example: 67f1234567890abcdef1234
                                            repeat:
                                              type: integer
                                              minimum: 1
                                              maximum: 50
                                              default: 1
                                            steps:
                                              type: array
                                              maxItems: 20
                                              items:
                                                type: object
                                                additionalProperties: false
                                                required:
                                                  - kind
                                                  - durationType
                                                properties:
                                                  _id:
                                                    type: string
                                                    example: 67f1234567890abcdef1234
                                                  kind:
                                                    type: string
                                                    enum:
                                                      - warmup
                                                      - work
                                                      - recovery
                                                      - rest
                                                      - cooldown
                                                  durationType:
                                                    type: string
                                                    enum:
                                                      - time
                                                      - distance
                                                      - open
                                                  durationValue:
                                                    type:
                                                      - number
                                                      - 'null'
                                                    minimum: 0
                                                    default: null
                                                    description: >-
                                                      Required seconds for time or metres for
                                                      distance; null/omitted for open.
                                                  target:
                                                    type: object
                                                    additionalProperties: false
                                                    required:
                                                      - kind
                                                    description: >-
                                                      Allowed kinds and zones depend on the
                                                      sport. Zone targets require zone; other
                                                      targets require ordered low/high bounds.
                                                      Pace is seconds/km for running/walking,
                                                      seconds/500m for rowing, seconds/100m
                                                      for swimming. Percentages are percent
                                                      values; HR is bpm, power is watts, RPE
                                                      is 1–10. Numeric strings with dot or
                                                      comma decimals are accepted.
                                                    properties:
                                                      kind:
                                                        type: string
                                                        enum:
                                                          - paceZone
                                                          - pacePct
                                                          - pace
                                                          - hrZone
                                                          - hrPct
                                                          - hr
                                                          - powerZone
                                                          - powerPct
                                                          - power
                                                          - rpe
                                                      zone:
                                                        type: string
                                                        enum:
                                                          - E
                                                          - T
                                                          - I
                                                          - R
                                                          - RP
                                                          - Z1
                                                          - Z2
                                                          - Z3
                                                          - Z4
                                                          - Z5
                                                          - Z6
                                                          - Z7
                                                          - easy
                                                          - endurance
                                                          - threshold
                                                          - speed
                                                        description: >-
                                                          Run pace: E (easy), T (threshold), I
                                                          (interval), R (repetition), RP (race
                                                          pace = goal time / goal distance, never
                                                          derived from T). Running has no HR
                                                          zones; HR bands are absolute bpm from
                                                          athlete data. Walking/rowing pace and
                                                          five-zone HR: Z1–Z5. Bike/row power:
                                                          Z1–Z7. Swimming pace: easy, endurance,
                                                          threshold, speed.
                                                      basis:
                                                        type: string
                                                        enum:
                                                          - lthr
                                                          - maxHr
                                                        description: HR zone/percentage targets only.
                                                      low:
                                                        type: number
                                                        minimum: 0
                                                      high:
                                                        type: number
                                                        minimum: 0
                                                  secondaryTarget:
                                                    type: object
                                                    additionalProperties: false
                                                    required:
                                                      - kind
                                                    description: >-
                                                      Allowed kinds and zones depend on the
                                                      sport. Zone targets require zone; other
                                                      targets require ordered low/high bounds.
                                                      Pace is seconds/km for running/walking,
                                                      seconds/500m for rowing, seconds/100m
                                                      for swimming. Percentages are percent
                                                      values; HR is bpm, power is watts, RPE
                                                      is 1–10. Numeric strings with dot or
                                                      comma decimals are accepted.
                                                    properties:
                                                      kind:
                                                        type: string
                                                        enum:
                                                          - paceZone
                                                          - pacePct
                                                          - pace
                                                          - hrZone
                                                          - hrPct
                                                          - hr
                                                          - powerZone
                                                          - powerPct
                                                          - power
                                                          - rpe
                                                      zone:
                                                        type: string
                                                        enum:
                                                          - E
                                                          - T
                                                          - I
                                                          - R
                                                          - RP
                                                          - Z1
                                                          - Z2
                                                          - Z3
                                                          - Z4
                                                          - Z5
                                                          - Z6
                                                          - Z7
                                                          - easy
                                                          - endurance
                                                          - threshold
                                                          - speed
                                                        description: >-
                                                          Run pace: E (easy), T (threshold), I
                                                          (interval), R (repetition), RP (race
                                                          pace = goal time / goal distance, never
                                                          derived from T). Running has no HR
                                                          zones; HR bands are absolute bpm from
                                                          athlete data. Walking/rowing pace and
                                                          five-zone HR: Z1–Z5. Bike/row power:
                                                          Z1–Z7. Swimming pace: easy, endurance,
                                                          threshold, speed.
                                                      basis:
                                                        type: string
                                                        enum:
                                                          - lthr
                                                          - maxHr
                                                        description: HR zone/percentage targets only.
                                                      low:
                                                        type: number
                                                        minimum: 0
                                                      high:
                                                        type: number
                                                        minimum: 0
                                                  notes:
                                                    type: string
                                                    default: ''
                                                  stroke:
                                                    type: string
                                                    enum:
                                                      - free
                                                      - back
                                                      - breast
                                                      - fly
                                                      - im
                                                      - choice
                                                      - kick
                                                      - drill
                                                    description: Swimming only.
                                                  equipment:
                                                    type: array
                                                    items:
                                                      type: string
                                                      enum:
                                                        - pullBuoy
                                                        - paddles
                                                        - fins
                                                        - kickboard
                                                        - snorkel
                                                    description: Swimming only.
                                                  restMode:
                                                    type: string
                                                    enum:
                                                      - rest
                                                      - sendOff
                                                    description: >-
                                                      Swimming only. sendOff requires
                                                      sendOffSec.
                                                  sendOffSec:
                                                    type: number
                                                    minimum: 1
                                                    description: Swimming sendOff only.
                                                  cadence:
                                                    type: object
                                                    additionalProperties: false
                                                    required:
                                                      - low
                                                      - high
                                                    properties:
                                                      low:
                                                        type: number
                                                        minimum: 0
                                                      high:
                                                        type: number
                                                        minimum: 0
                                              default: []
                                        default: []
                                      sourceTemplateId:
                                        type:
                                          - string
                                          - 'null'
                                        example: null
                                  targetDistanceMeters:
                                    type:
                                      - number
                                      - 'null'
                                    minimum: 0
                                    example: 5000
                                    description: >-
                                      Planned distance in meters; null when no
                                      target is set.
                            discriminator:
                              propertyName: type
                              mapping:
                                workout: >-
                                  #/components/schemas/WorkoutProgrammeCalendarWorkoutItem
                                activity: >-
                                  #/components/schemas/WorkoutProgrammeCalendarActivityItem
        sourceVersion:
          type: string
          enum:
            - plansjablonen-v259-1
        goal:
          type: object
          additionalProperties: false
          required:
            - distance
            - goalTimeSec
            - raceDate
          properties:
            distance:
              type: string
              enum:
                - 5K
                - 10K
                - half
                - marathon
            goalTimeSec:
              type: number
              exclusiveMinimum: 0
              description: >-
                Finish time in seconds. Localized numeric strings are accepted
                on input.
            raceDate:
              type: string
              format: date
              description: Canonical YYYY-MM-DD athlete calendar date.
            acceptGoalAsChallenge:
              type: boolean
              default: false
        startDate:
          type: string
          format: date
        totalWeeks:
          type: integer
          minimum: 1
          maximum: 104
        templateKey:
          type: string
          enum:
            - 5K
            - 10K
            - half
            - marathon
        variant:
          type: boolean
        baselineKm:
          type: number
        peakKm:
          type: number
        requestedPeakKm:
          type: number
        phases:
          type: object
          properties:
            base:
              type: integer
            threshold:
              type: integer
            sharpen:
              type: integer
        taperWeeks:
          type: integer
          enum:
            - 1
            - 2
        concreteWeeks:
          type: integer
          enum:
            - 2
            - 3
        runWeekdays:
          type: array
          uniqueItems: true
          items:
            type: integer
            minimum: 1
            maximum: 7
        qualityWeekdays:
          type: array
          uniqueItems: true
          items:
            type: integer
            minimum: 1
            maximum: 7
        longRunWeekday:
          type: integer
          minimum: 1
          maximum: 7
        paces:
          type: object
          properties:
            easy:
              type:
                - number
                - 'null'
              minimum: 0
            threshold:
              type:
                - number
                - 'null'
              minimum: 0
            interval:
              type:
                - number
                - 'null'
              minimum: 0
            repetition:
              type:
                - number
                - 'null'
              minimum: 0
            racePace:
              type:
                - number
                - 'null'
              minimum: 0
          additionalProperties: false
        baseline:
          $ref: '#/components/schemas/PublicWorkoutSourceCardioLoggedBaseline'
        weeks:
          type: array
          items:
            type: object
            properties:
              weekNumber:
                type: integer
              weekStart:
                type: string
                format: date
              phase:
                type: integer
                enum:
                  - 1
                  - 2
                  - 3
              phaseName:
                type: string
                enum:
                  - Base building
                  - Threshold development
                  - Sharpening
              theme:
                type: string
                enum:
                  - Base building
                  - Threshold development
                  - Sharpening
              weekKind:
                type: string
                enum:
                  - build
                  - race
                  - taper
                  - sharpen
                  - deload
              rotationWeek:
                type: integer
                enum:
                  - 1
                  - 2
                  - 3
              targetVolumeKm:
                type: number
              concrete:
                type: boolean
              requestedVolumeKm:
                type: number
              allocatedKm:
                type: number
              remainingKm:
                type: number
              concreteRequested:
                type: boolean
              sessions:
                type: array
                items:
                  type: object
                  properties:
                    weekday:
                      type: integer
                      minimum: 1
                      maximum: 7
                    code:
                      type: string
                      enum:
                        - drempel_c
                        - drempel_r
                        - interval
                        - doeltempo
                        - zone2
                        - long_run
                    sessionType:
                      type: string
                      enum:
                        - threshold_continuous
                        - threshold_reps
                        - interval
                        - race_pace
                        - zone2
                        - long_run
                    controlMode:
                      type: string
                      enum:
                        - hr
                        - pace
                    longRunTargetMinutes:
                      type: number
                    ladder:
                      type: object
                      required:
                        - step
                        - reps
                        - kmPerRep
                      properties:
                        step:
                          type: integer
                          minimum: 1
                          maximum: 8
                        reps:
                          type: integer
                          minimum: 1
                        kmPerRep:
                          type: number
                          exclusiveMinimum: 0
                    continuousMinutes:
                      type: number
                    recoveryRangeSec:
                      type: object
                      properties:
                        low:
                          type: number
                        high:
                          type: number
                    cardio:
                      type: object
                      additionalProperties: false
                      description: >-
                        Optional structured activity prescription. Requires
                        workoutsectionv2 + workoutV2ProgrammeCalendar +
                        workoutV2CardioBuilder. Omitted from disabled reads.
                        Supported sports: running (paceZone E/T/I/R/RP, absolute
                        pace, absolute HR, RPE), walking (pace, HR, RPE),
                        cycling (power, HR, RPE), rowing (pace, power, HR, RPE),
                        swimming (pace, RPE). Rejected for workout, padel,
                        mobility and other items. Totals overwrite planned
                        duration/distance; unknown time or distance contributes
                        zero.
                      properties:
                        slotKey:
                          type: string
                          description: >-
                            Generated when missing; retain across edits, copies
                            and weeks.
                        sessionType:
                          type: string
                          enum:
                            - easy
                            - zone2
                            - long_run
                            - threshold_continuous
                            - threshold_reps
                            - interval
                            - race_pace
                            - time_trial
                            - race
                          description: >-
                            Running only. Template session codes:
                            threshold_continuous = drempel_c, threshold_reps =
                            drempel_r, interval, race_pace = doeltempo, zone2. A
                            typed session with empty blocks is a skeleton to be
                            filled later.
                        controlMode:
                          type: string
                          enum:
                            - pace
                            - hr
                          description: >-
                            Binding signal. Defaults from sessionType: hr for
                            easy, zone2 and long_run; pace for
                            threshold_continuous, threshold_reps, interval and
                            race_pace; none for time_trial and race. A
                            contradicting value is rejected.
                        ladderStep:
                          type: integer
                          minimum: 1
                          description: >-
                            Ladder position: interval 1–8, threshold_reps 1–7,
                            threshold_continuous 1–5 (15/18/20/22/25 min).
                            Rejected for other session types.
                        poolLengthM:
                          type: number
                          enum:
                            - 25
                            - 50
                          description: Swimming only.
                        blocks:
                          type: array
                          maxItems: 10
                          items:
                            type: object
                            additionalProperties: false
                            properties:
                              _id:
                                type: string
                                example: 67f1234567890abcdef1234
                              repeat:
                                type: integer
                                minimum: 1
                                maximum: 50
                                default: 1
                              steps:
                                type: array
                                maxItems: 20
                                items:
                                  type: object
                                  additionalProperties: false
                                  required:
                                    - kind
                                    - durationType
                                  properties:
                                    _id:
                                      type: string
                                      example: 67f1234567890abcdef1234
                                    kind:
                                      type: string
                                      enum:
                                        - warmup
                                        - work
                                        - recovery
                                        - rest
                                        - cooldown
                                    durationType:
                                      type: string
                                      enum:
                                        - time
                                        - distance
                                        - open
                                    durationValue:
                                      type:
                                        - number
                                        - 'null'
                                      minimum: 0
                                      default: null
                                      description: >-
                                        Required seconds for time or metres for
                                        distance; null/omitted for open.
                                    target:
                                      type: object
                                      additionalProperties: false
                                      required:
                                        - kind
                                      description: >-
                                        Allowed kinds and zones depend on the
                                        sport. Zone targets require zone; other
                                        targets require ordered low/high bounds.
                                        Pace is seconds/km for running/walking,
                                        seconds/500m for rowing, seconds/100m
                                        for swimming. Percentages are percent
                                        values; HR is bpm, power is watts, RPE
                                        is 1–10. Numeric strings with dot or
                                        comma decimals are accepted.
                                      properties:
                                        kind:
                                          type: string
                                          enum:
                                            - paceZone
                                            - pacePct
                                            - pace
                                            - hrZone
                                            - hrPct
                                            - hr
                                            - powerZone
                                            - powerPct
                                            - power
                                            - rpe
                                        zone:
                                          type: string
                                          enum:
                                            - E
                                            - T
                                            - I
                                            - R
                                            - RP
                                            - Z1
                                            - Z2
                                            - Z3
                                            - Z4
                                            - Z5
                                            - Z6
                                            - Z7
                                            - easy
                                            - endurance
                                            - threshold
                                            - speed
                                          description: >-
                                            Run pace: E (easy), T (threshold), I
                                            (interval), R (repetition), RP (race
                                            pace = goal time / goal distance, never
                                            derived from T). Running has no HR
                                            zones; HR bands are absolute bpm from
                                            athlete data. Walking/rowing pace and
                                            five-zone HR: Z1–Z5. Bike/row power:
                                            Z1–Z7. Swimming pace: easy, endurance,
                                            threshold, speed.
                                        basis:
                                          type: string
                                          enum:
                                            - lthr
                                            - maxHr
                                          description: HR zone/percentage targets only.
                                        low:
                                          type: number
                                          minimum: 0
                                        high:
                                          type: number
                                          minimum: 0
                                    secondaryTarget:
                                      type: object
                                      additionalProperties: false
                                      required:
                                        - kind
                                      description: >-
                                        Allowed kinds and zones depend on the
                                        sport. Zone targets require zone; other
                                        targets require ordered low/high bounds.
                                        Pace is seconds/km for running/walking,
                                        seconds/500m for rowing, seconds/100m
                                        for swimming. Percentages are percent
                                        values; HR is bpm, power is watts, RPE
                                        is 1–10. Numeric strings with dot or
                                        comma decimals are accepted.
                                      properties:
                                        kind:
                                          type: string
                                          enum:
                                            - paceZone
                                            - pacePct
                                            - pace
                                            - hrZone
                                            - hrPct
                                            - hr
                                            - powerZone
                                            - powerPct
                                            - power
                                            - rpe
                                        zone:
                                          type: string
                                          enum:
                                            - E
                                            - T
                                            - I
                                            - R
                                            - RP
                                            - Z1
                                            - Z2
                                            - Z3
                                            - Z4
                                            - Z5
                                            - Z6
                                            - Z7
                                            - easy
                                            - endurance
                                            - threshold
                                            - speed
                                          description: >-
                                            Run pace: E (easy), T (threshold), I
                                            (interval), R (repetition), RP (race
                                            pace = goal time / goal distance, never
                                            derived from T). Running has no HR
                                            zones; HR bands are absolute bpm from
                                            athlete data. Walking/rowing pace and
                                            five-zone HR: Z1–Z5. Bike/row power:
                                            Z1–Z7. Swimming pace: easy, endurance,
                                            threshold, speed.
                                        basis:
                                          type: string
                                          enum:
                                            - lthr
                                            - maxHr
                                          description: HR zone/percentage targets only.
                                        low:
                                          type: number
                                          minimum: 0
                                        high:
                                          type: number
                                          minimum: 0
                                    notes:
                                      type: string
                                      default: ''
                                    stroke:
                                      type: string
                                      enum:
                                        - free
                                        - back
                                        - breast
                                        - fly
                                        - im
                                        - choice
                                        - kick
                                        - drill
                                      description: Swimming only.
                                    equipment:
                                      type: array
                                      items:
                                        type: string
                                        enum:
                                          - pullBuoy
                                          - paddles
                                          - fins
                                          - kickboard
                                          - snorkel
                                      description: Swimming only.
                                    restMode:
                                      type: string
                                      enum:
                                        - rest
                                        - sendOff
                                      description: >-
                                        Swimming only. sendOff requires
                                        sendOffSec.
                                    sendOffSec:
                                      type: number
                                      minimum: 1
                                      description: Swimming sendOff only.
                                    cadence:
                                      type: object
                                      additionalProperties: false
                                      required:
                                        - low
                                        - high
                                      properties:
                                        low:
                                          type: number
                                          minimum: 0
                                        high:
                                          type: number
                                          minimum: 0
                                default: []
                          default: []
                        sourceTemplateId:
                          type:
                            - string
                            - 'null'
                          example: null
                    totals:
                      type: object
                      properties:
                        durationSec:
                          type: number
                          minimum: 0
                        distanceM:
                          type: number
                          minimum: 0
                        plannedDurationMinutes:
                          type: number
                          minimum: 0
                        targetDistanceMeters:
                          type: number
                          minimum: 0
                        zoneTimeSec:
                          type: object
                          additionalProperties:
                            type: number
                            minimum: 0
                      additionalProperties: false
        diagnostics:
          type: array
          items:
            type: object
            required:
              - code
              - severity
            properties:
              code:
                type: string
                enum:
                  - RUNNING_PLAN_INPUT_MISSING
                  - REFER_TO_PROFESSIONAL
                  - RUNNING_BASELINE_ZERO
                  - THRESHOLD_MEASUREMENT_REQUIRED
                  - THRESHOLD_OFFSET_UNRESOLVED
                  - GOAL_NOT_FEASIBLE
                  - NO_REAL_PERIODISATION
                  - SHORT_PLAN_STRUCTURE_CONFLICT
                  - WEEK_ONE_VOLUME_CONFLICT
                  - PEAK_ROUNDING_CONFLICT
                  - WEEKLY_VOLUME_LIMIT_CONFLICT
                  - PEAK_VOLUME_LIMIT_CONFLICT
                  - VOLUME_INTENSITY_CONFLICT
                  - SESSION_VOLUME_REQUIRED
                  - WARMUP_COOLDOWN_REQUIRED
                  - THRESHOLD_RECOVERY_REQUIRED
                  - RACE_PACE_VOLUME_REQUIRED
                  - LONG_RUN_PROGRESSION_REQUIRED
                  - RACE_WEEK_ALIGNMENT_CONFLICT
                  - NIGGLE_INTENSITY_SUPPRESSED
                  - VOLUME_SAFETY_ADJUSTED
                  - QUALITY_SUPPRESSED_FOR_VOLUME_INCREASE
                  - NO_RUNNING_DAYS_IN_WEEK
                  - PRESCRIPTION_INPUT_MISSING
                  - LONG_RUN_PHASE_LIMIT_EXCEEDED
                  - EASY_ALLOCATION_EXHAUSTED
                  - WEEK_VOLUME_MISMATCH
                  - PRESCRIPTION_TOTALS_INVALID
                  - RACE_WEEK_NO_TRAINING_WINDOW
              severity:
                type: string
                enum:
                  - error
                  - warning
              field:
                type: string
              fields:
                type: array
                items:
                  type: string
              value:
                type: number
              limit:
                type: number
              previousVolumeKm:
                type: number
              targetVolumeKm:
                type: number
              raceWeekStart:
                type: string
                format: date
              lastWeekStart:
                type: string
                format: date
    PublicApiError:
      type: object
      additionalProperties: false
      required:
        - error
        - meta
      properties:
        error:
          type: object
          additionalProperties: false
          required:
            - code
            - key
            - message
          properties:
            code:
              type: integer
              example: 401
            key:
              type: string
              example: auth.invalid_token
            message:
              type: string
              example: The access token is invalid.
            details:
              type: object
              additionalProperties: true
        meta:
          $ref: '#/components/schemas/PublicApiMeta'
    ErrorResponse:
      allOf:
        - $ref: '#/components/schemas/StandardResponse'
        - example:
            status: 401
            error: true
            message: MISSING_AUTH
    PublicWorkoutSourceRunningPlanPreviewInput:
      type: object
      additionalProperties: false
      required:
        - goal
        - startDate
        - runWeekdays
        - qualityWeekdays
        - longRunWeekday
        - concreteWeeks
        - intake
      properties:
        goal:
          $ref: '#/components/schemas/PublicWorkoutSourceRunningPlanGoal'
        startDate:
          type: string
          format: date
        runWeekdays:
          type: array
          uniqueItems: true
          items:
            type: integer
            minimum: 1
            maximum: 7
          minItems: 3
          description: >-
            Monday=1, Sunday=7. Must respect stored availability, fixed days and
            run-day count.
        qualityWeekdays:
          type: array
          uniqueItems: true
          items:
            type: integer
            minimum: 1
            maximum: 7
          minItems: 2
          maxItems: 2
          description: >-
            Two selected running days, ordered by weekday; distinct from the
            long run.
        longRunWeekday:
          type: integer
          minimum: 1
          maximum: 7
        concreteWeeks:
          type: integer
          enum:
            - 2
            - 3
        prescriptions:
          type: array
          maxItems: 3
          items:
            $ref: '#/components/schemas/PublicWorkoutSourceRunningPlanWeekInput'
          description: >-
            Explicit coach inputs for the concrete horizon. Missing values are
            preview diagnostics and block saving. Later weeks stay skeletons.
        intake:
          type: object
          additionalProperties: false
          required:
            - persistentRunningPain
            - bonePointTenderness
            - nightPain
            - worseningDespiteRest
          properties:
            persistentRunningPain:
              type: boolean
            bonePointTenderness:
              type: boolean
            nightPain:
              type: boolean
            worseningDespiteRest:
              type: boolean
    PublicApiWriteMeta:
      type: object
      additionalProperties: false
      required:
        - requestId
      properties:
        requestId:
          type: string
          description: Stable request correlation id. Mirrors `X-Request-Id` when supplied.
          example: 4f849d7d-f4f1-45cc-b4b7-3984a3d17f83
        rateLimit:
          $ref: '#/components/schemas/PublicApiRateLimitMeta'
        idempotency:
          type: object
          additionalProperties: false
          properties:
            replayed:
              type: boolean
              description: >-
                True when the response was replayed from a previous request with
                the same `Idempotency-Key`.
              example: true
    PublicWorkoutSourceCardioLoggedBaseline:
      type: object
      readOnly: true
      description: >-
        Last four completed Monday–Sunday calendar weeks in the athlete timezone
        (company timezone fallback). endDate is exclusive. Completed,
        non-deleted programme runs and personal-calendar runs contribute actual
        measured distance. Programme completedAt determines the local date, with
        plannedDate fallback; personal-calendar logs use scheduledDate because
        no completion timestamp is stored. Separate records are separate logs. A
        week without a run log is unknown, not an inferred zero. GET is
        read-only; successful PUT selecting logged_activities persists this
        window and an audit record. All API timestamps are UTC.
      properties:
        source:
          type: string
          enum:
            - logged_activities
        startDate:
          type: string
          format: date
        endDate:
          type: string
          format: date
        timeZone:
          type: string
        calculatedAt:
          type: string
          format: date-time
        complete:
          type: boolean
        baselineWeeklyKm:
          type:
            - number
            - 'null'
        weeklyTotals:
          type: array
          minItems: 4
          maxItems: 4
          items:
            type: object
            properties:
              weekStart:
                type: string
                format: date
              distanceKm:
                type: number
              runCount:
                type: integer
              missingDistanceCount:
                type: integer
        reasonCodes:
          type: array
          items:
            type: string
            enum:
              - RUNNING_BASELINE_ACTIVITY_TYPE_MISSING
              - RUNNING_BASELINE_LOG_LIMIT_EXCEEDED
              - RUNNING_BASELINE_WEEKS_MISSING
              - RUNNING_BASELINE_DISTANCE_MISSING
    PublicApiMeta:
      type: object
      additionalProperties: false
      required:
        - requestId
      properties:
        requestId:
          type: string
          description: Stable request correlation id. Mirrors `X-Request-Id` when supplied.
          example: 4f849d7d-f4f1-45cc-b4b7-3984a3d17f83
        rateLimit:
          $ref: '#/components/schemas/PublicApiRateLimitMeta'
    StandardResponse:
      type: object
      properties:
        status:
          type: integer
          example: 200
        error:
          type: boolean
          example: false
        message:
          type: string
          example: SUCCESS
      required:
        - status
        - error
        - message
    PublicWorkoutSourceRunningPlanGoal:
      type: object
      additionalProperties: false
      required:
        - distance
        - goalTimeSec
        - raceDate
      properties:
        distance:
          type: string
          enum:
            - 5K
            - 10K
            - half
            - marathon
        goalTimeSec:
          type: number
          exclusiveMinimum: 0
          description: >-
            Finish time in seconds. Localized numeric strings are accepted on
            input.
        raceDate:
          type: string
          format: date
          description: Canonical YYYY-MM-DD athlete calendar date.
        acceptGoalAsChallenge:
          type: boolean
          default: false
    PublicWorkoutSourceRunningPlanWeekInput:
      type: object
      additionalProperties: false
      required:
        - weekNumber
        - sessions
      properties:
        weekNumber:
          type: integer
          minimum: 1
          maximum: 3
        sessions:
          type: array
          maxItems: 7
          items:
            $ref: '#/components/schemas/PublicWorkoutSourceRunningPlanSessionInput'
    PublicApiRateLimitMeta:
      type: object
      additionalProperties: false
      properties:
        limit:
          type: integer
          example: 10
        remaining:
          type: integer
          example: 9
        resetSeconds:
          type: integer
          description: Seconds until the current rate limit window resets.
          example: 1
        retryAfterSeconds:
          type: integer
          description: Present when the request was rate limited.
          example: 1
    PublicWorkoutSourceRunningPlanSessionInput:
      type: object
      additionalProperties: false
      required:
        - weekday
      properties:
        weekday:
          type: integer
          minimum: 1
          maximum: 7
        easyKm:
          type: number
          exclusiveMinimum: 0
          description: Explicit easy-run distance. Mutually exclusive with easyWeight.
        easyWeight:
          type: number
          exclusiveMinimum: 0
          description: >-
            Coach-selected relative share of the remaining week budget after
            other prescribed sessions. All weights are normalized; no
            distribution default is invented.
        warmupMinutes:
          type: number
          exclusiveMinimum: 0
        cooldownMinutes:
          type: number
          exclusiveMinimum: 0
        thresholdRecoverySec:
          type: number
          minimum: 60
          maximum: 120
        racePaceKm:
          type: number
          exclusiveMinimum: 0
        longRunMinutes:
          type: number
          exclusiveMinimum: 0
          description: >-
            Required coach-selected progression for half/marathon, bounded by
            the phase target. 5K/10K use the source phase duration.
  securitySchemes:
    PublicBearerAuth:
      type: http
      scheme: bearer
      bearerFormat: Opaque
      description: >-
        Public API access token issued by `/public/v1/oauth/token`. Example:
        `Authorization: Bearer fspt_...`. Each resource request rechecks the
        token company's current provider access. Disabling access blocks
        existing tokens with `403 auth.provider_unavailable`.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.