> ## 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.

# Get one programme activity occurrence

> The Activity Details screen for one occurrence of a programme activity on an assigned calendar-week plan. Returns planned values and the logged result, or null before logging. Locked future weeks remain readable with isAvailable:false. With the composite cardio flag enabled, running results include work-block actuals, immutable execution targets and server evaluation. Optional compareToPerformanceId compares one earlier log in this same company/client/plan; missing or different work structure, conditions or duration returns NOT_COMPARABLE without progress claims.

Requires the workout_sessions:read scope. This operation maps to /app/v1/workout/performance/activities/:planId/:scheduleItemId/:plannedDate 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 get /public/v1/workout/performance/activities/{planId}/{scheduleItemId}/{plannedDate}
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/performance/activities/{planId}/{scheduleItemId}/{plannedDate}:
    get:
      tags:
        - Workout
      summary: Get one programme activity occurrence
      description: >-
        The Activity Details screen for one occurrence of a programme activity
        on an assigned calendar-week plan. Returns planned values and the logged
        result, or null before logging. Locked future weeks remain readable with
        isAvailable:false. With the composite cardio flag enabled, running
        results include work-block actuals, immutable execution targets and
        server evaluation. Optional compareToPerformanceId compares one earlier
        log in this same company/client/plan; missing or different work
        structure, conditions or duration returns NOT_COMPARABLE without
        progress claims.


        Requires the workout_sessions:read scope. This operation maps to
        /app/v1/workout/performance/activities/:planId/:scheduleItemId/:plannedDate
        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: >-
        publicWorkoutgetPublicV1WorkoutPerformanceActivitiesPlanIdScheduleItemIdPlannedDate
      parameters:
        - in: query
          name: compareToPerformanceId
          required: false
          schema:
            type: string
            example: 67f1234567890abcdef1234
          description: >-
            One earlier performance id in the same company, client and assigned
            plan. Requires the cardio flag. Whole-activity means never supply
            work evidence.
        - in: path
          name: planId
          required: true
          description: Assigned workout plan id.
          schema:
            type: string
            example: 67f1234567890abcdef1234
        - in: path
          name: scheduleItemId
          required: true
          description: Activity schedule item id.
          schema:
            type: string
            example: 67f1234567890abcdef1234
        - in: path
          name: plannedDate
          required: true
          description: Canonical planned occurrence date.
          schema:
            type: string
            format: date
            pattern: ^\d{4}-\d{2}-\d{2}$
            example: '2026-09-08'
      responses:
        '200':
          description: Activity occurrence detail.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/PublicApiSuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: >-
                          #/components/schemas/PublicWorkoutSourceGETAppV1WorkoutPerformanceActivitiesPlanIdScheduleItemIdPlannedDateResponse200
              examples:
                success:
                  summary: Successful response
                  value:
                    data:
                      comparison:
                        status: COMPARABLE
                        reasonCodes:
                          - TWO_COMPLETED_SESSIONS_REQUIRED
                        blocks:
                          - blockId: 66f7b8b1e13c8d25f4d3d90a
                            stepId: 66f7b8b1e13c8d25f4d3d90a
                            repIndex: 1
                            metric: avgHrBpm
                            previous: 1
                            current: 1
                            delta: 1
                      resolvedTargetsSnapshot:
                        source: execution_snapshot
                        paceUnit: s/km
                        sessionType: easy
                        controlMode: pace
                        blocks:
                          - _id: 66f7b8b1e13c8d25f4d3d90a
                            repeat: 1
                            steps:
                              - _id: 66f7b8b1e13c8d25f4d3d90a
                                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
                                targetReasonCode: string
                                secondaryTargetReasonCode: string
                      planId: 66f7b8b1e13c8d25f4d3d90a
                      scheduleItemId: 66f7b8b1e13c8d25f4d3d90a
                      plannedDate: '2026-09-08'
                      weekNumber: 1
                      weekday: 5
                      isAvailable: true
                      activityType: walking
                      name: 30 Minutes Walk
                      description: Example description
                      planned:
                        date: '2026-09-08'
                        startTime: '10:45'
                        endTime: '11:45'
                        durationMinutes: 60
                        distanceMeters: 50
                      result:
                        workBlocks:
                          - blockId: 66f7b8b1e13c8d25f4d3d90a
                            stepId: 66f7b8b1e13c8d25f4d3d90a
                            repIndex: 1
                            durationSec: 1
                            distanceM: 1
                            avgPaceSecPerKm: 1
                            avgHrBpm: 1
                        avgHrBpm: 1
                        missedReason: sick
                        conditions:
                          temperatureC: 1
                          windNote: string
                          elevationGainM: 1
                          preFatigueNote: string
                        niggle:
                          note: string
                        source: manual
                        completedOnTarget: true
                        workBlockEvaluation:
                          reasonCodes:
                            - SESSION_NOT_COMPLETED
                          blocks:
                            - blockId: 66f7b8b1e13c8d25f4d3d90a
                              stepId: 66f7b8b1e13c8d25f4d3d90a
                              repIndex: 1
                              onTarget: true
                              reasonCode: string
                        resolvedTargetsSnapshot:
                          source: execution_snapshot
                          paceUnit: s/km
                          sessionType: easy
                          controlMode: pace
                          blocks:
                            - _id: 66f7b8b1e13c8d25f4d3d90a
                              repeat: 1
                              steps:
                                - _id: 66f7b8b1e13c8d25f4d3d90a
                                  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
                                  targetReasonCode: string
                                  secondaryTargetReasonCode: string
                        externalWorkoutRef: string
                        performanceId: 66f7b8b1e13c8d25f4d3d90a
                        status: in_progress
                        startedAt: '2026-07-14T10:00:00.000Z'
                        completedAt: '2026-07-14T10:00:00.000Z'
                        startTime: '10:45'
                        endTime: '11:45'
                        durationMinutes: 150
                        distanceMeters: 1200
                        rpe: 6
                        notes: string
                      timeZone: Europe/Amsterdam
                    meta:
                      requestId: 4f849d7d-f4f1-45cc-b4b7-3984a3d17f83
                      rateLimit:
                        limit: 10
                        remaining: 9
                        resetSeconds: 1
        '400':
          description: >-
            Invalid ids, or the planned date is not a real occurrence of this
            activity item.
          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
        '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: The caller cannot access the client assigned to this plan.
          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':
          description: >-
            Assigned calendar-week plan not found, or the schedule item is not
            an activity.
          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'
        '422':
          $ref: '#/components/schemas/ErrorResponse'
        '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 GET
            "https://api.fitsociety.io/public/v1/workout/performance/activities/{planId}/{scheduleItemId}/{plannedDate}"
            \
              -H "Authorization: Bearer <access_token>"
components:
  schemas:
    PublicApiSuccessResponse:
      type: object
      additionalProperties: false
      required:
        - data
        - meta
      properties:
        data:
          type: object
        meta:
          $ref: '#/components/schemas/PublicApiMeta'
    PublicWorkoutSourceGETAppV1WorkoutPerformanceActivitiesPlanIdScheduleItemIdPlannedDateResponse200:
      type: object
      properties:
        comparison:
          type: object
          properties:
            status:
              type: string
              enum:
                - COMPARABLE
                - NOT_COMPARABLE
            reasonCodes:
              type: array
              items:
                type: string
                enum:
                  - TWO_COMPLETED_SESSIONS_REQUIRED
                  - WORK_STRUCTURE_DIFFERS
                  - CONDITIONS_MISSING
                  - CONDITIONS_DIFFER
                  - WORK_ACTUALS_INCOMPLETE
                  - WORK_DURATION_DIFFERS
            blocks:
              type: array
              items:
                type: object
                properties:
                  blockId:
                    type: string
                  stepId:
                    type: string
                  repIndex:
                    type: integer
                  metric:
                    type: string
                    enum:
                      - avgHrBpm
                      - avgPaceSecPerKm
                  previous:
                    type: number
                  current:
                    type: number
                  delta:
                    type: number
          description: >-
            Two distinct completed sessions in the same assigned plan. Requires
            matching work structure, primary control mode, recorded conditions
            and actual work durations. Missing or different evidence returns
            NOT_COMPARABLE with no deltas. Comparable output reports observed
            metric differences, not a fitness claim.
        resolvedTargetsSnapshot:
          type: object
          readOnly: true
          properties:
            source:
              type: string
              enum:
                - execution_snapshot
            paceUnit:
              type: string
              enum:
                - s/km
            sessionType:
              type: string
              enum:
                - easy
                - zone2
                - long_run
                - threshold_continuous
                - threshold_reps
                - interval
                - race_pace
                - time_trial
                - race
            controlMode:
              type: string
              enum:
                - pace
                - hr
            blocks:
              type: array
              items:
                type: object
                properties:
                  _id:
                    type: string
                  repeat:
                    type: integer
                    minimum: 1
                    maximum: 50
                  steps:
                    type: array
                    items:
                      type: object
                      properties:
                        _id:
                          type: string
                        kind:
                          type: string
                          enum:
                            - warmup
                            - work
                            - recovery
                            - rest
                            - cooldown
                        durationType:
                          type: string
                          enum:
                            - time
                            - distance
                            - open
                        durationValue:
                          type:
                            - number
                            - 'null'
                          minimum: 0
                        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
                        targetReasonCode:
                          type: string
                        secondaryTargetReasonCode:
                          type: string
          description: >-
            First logging captures the prescribed structure and resolved
            targets. Later profile or schedule edits never replace this
            snapshot. Client writes are rejected.
        planId:
          type: string
        scheduleItemId:
          type: string
        plannedDate:
          type: string
          format: date
          pattern: ^\d{4}-\d{2}-\d{2}$
          example: '2026-09-08'
        weekNumber:
          type: integer
          nullable: true
          example: 1
        weekday:
          type: integer
          nullable: true
          example: 5
        isAvailable:
          type: boolean
          example: true
        activityType:
          type: string
          nullable: true
          example: walking
        name:
          type: string
          example: 30 Minutes Walk
        description:
          type: string
        planned:
          type: object
          properties:
            date:
              type: string
              format: date
              pattern: ^\d{4}-\d{2}-\d{2}$
              example: '2026-09-08'
            startTime:
              type: string
              example: '10:45'
            endTime:
              type: string
              example: '11:45'
            durationMinutes:
              type: number
              nullable: true
              example: 60
            distanceMeters:
              type: number
              nullable: true
              example: 50
        result:
          type: object
          nullable: true
          properties:
            workBlocks:
              type: array
              maxItems: 1000
              items:
                type: object
                additionalProperties: false
                required:
                  - blockId
                  - stepId
                  - repIndex
                properties:
                  blockId:
                    type: string
                    pattern: ^[a-fA-F0-9]{24}$
                  stepId:
                    type: string
                    pattern: ^[a-fA-F0-9]{24}$
                  repIndex:
                    type: integer
                    minimum: 1
                    maximum: 50
                  durationSec:
                    type: number
                    exclusiveMinimum: 0
                    description: Measured work-step seconds.
                  distanceM:
                    type: number
                    exclusiveMinimum: 0
                    description: Measured work-step metres.
                  avgPaceSecPerKm:
                    type: number
                    exclusiveMinimum: 0
                    description: Measured work-step mean pace in seconds/km.
                  avgHrBpm:
                    type: number
                    exclusiveMinimum: 0
                    description: Measured work-step mean HR in bpm.
                description: >-
                  At least one measured metric is required. Positive finite
                  numbers and localized decimal strings are accepted.
              description: >-
                Work steps only, identified by persisted block/step ids and a
                one-based repetition index. Recovery and whole-activity averages
                cannot supply work evidence. Omission preserves existing
                entries; an explicit array replaces them.
            avgHrBpm:
              type: number
              exclusiveMinimum: 0
              description: >-
                Whole-activity mean HR, informational only; never compared with
                a work-step band.
            missedReason:
              type: string
              enum:
                - sick
                - away
                - injured
                - interrupted
                - too_hard
                - other
            conditions:
              type: object
              additionalProperties: false
              properties:
                temperatureC:
                  type: number
                  description: >-
                    Measured temperature in degrees Celsius; no automatic heat
                    correction is inferred.
                windNote:
                  type: string
                  maxLength: 2000
                  description: >-
                    Recorded wind conditions; an explicit empty string means no
                    wind effect reported.
                elevationGainM:
                  type: number
                  minimum: 0
                  description: Recorded elevation gain in metres.
                preFatigueNote:
                  type: string
                  maxLength: 2000
                  description: >-
                    Recorded pre-fatigue; an explicit empty string means none
                    reported.
            niggle:
              type: object
              additionalProperties: false
              required:
                - note
              properties:
                note:
                  type: string
                  maxLength: 2000
              description: >-
                Authenticated athlete only. Sets the profile niggle active
                before saving the log. Clearing requires the dedicated athlete
                endpoint; coaches cannot clear it.
            source:
              type: string
              enum:
                - manual
              description: >-
                Public writes are manual. Consented wearable import is a later
                phase.
            completedOnTarget:
              type:
                - boolean
                - 'null'
              readOnly: true
              description: >-
                Server computed from every prescribed work repetition and its
                primary signal and duration. Missing evidence or a single-value
                pace target with unspecified tolerance returns null. Secondary
                guidance and activity averages are never binding.
            workBlockEvaluation:
              type: object
              readOnly: true
              properties:
                reasonCodes:
                  type: array
                  items:
                    type: string
                    enum:
                      - SESSION_NOT_COMPLETED
                      - WORK_PRESCRIPTION_MISSING
                      - WORK_BLOCK_MISSING
                      - WORK_TARGET_UNRESOLVED
                      - CONTROL_MODE_MISMATCH
                      - PACE_TOLERANCE_UNSPECIFIED
                      - WORK_METRIC_MISSING
                      - WORK_DURATION_MISSING
                blocks:
                  type: array
                  items:
                    type: object
                    properties:
                      blockId:
                        type: string
                      stepId:
                        type: string
                      repIndex:
                        type: integer
                        minimum: 1
                      onTarget:
                        type:
                          - boolean
                          - 'null'
                      reasonCode:
                        type: string
            resolvedTargetsSnapshot:
              type: object
              readOnly: true
              properties:
                source:
                  type: string
                  enum:
                    - execution_snapshot
                paceUnit:
                  type: string
                  enum:
                    - s/km
                sessionType:
                  type: string
                  enum:
                    - easy
                    - zone2
                    - long_run
                    - threshold_continuous
                    - threshold_reps
                    - interval
                    - race_pace
                    - time_trial
                    - race
                controlMode:
                  type: string
                  enum:
                    - pace
                    - hr
                blocks:
                  type: array
                  items:
                    type: object
                    properties:
                      _id:
                        type: string
                      repeat:
                        type: integer
                        minimum: 1
                        maximum: 50
                      steps:
                        type: array
                        items:
                          type: object
                          properties:
                            _id:
                              type: string
                            kind:
                              type: string
                              enum:
                                - warmup
                                - work
                                - recovery
                                - rest
                                - cooldown
                            durationType:
                              type: string
                              enum:
                                - time
                                - distance
                                - open
                            durationValue:
                              type:
                                - number
                                - 'null'
                              minimum: 0
                            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
                            targetReasonCode:
                              type: string
                            secondaryTargetReasonCode:
                              type: string
              description: >-
                First logging captures the prescribed structure and resolved
                targets. Later profile or schedule edits never replace this
                snapshot. Client writes are rejected.
            externalWorkoutRef:
              type: string
              readOnly: true
              description: >-
                Reserved for a future consented server import; rejected in
                public writes.
            performanceId:
              type: string
            status:
              type: string
              enum:
                - in_progress
                - completed
                - cancelled
            startedAt:
              type: string
              format: date-time
              nullable: true
            completedAt:
              type: string
              format: date-time
              nullable: true
            startTime:
              type: string
              example: '10:45'
            endTime:
              type: string
              example: '11:45'
            durationMinutes:
              type: number
              nullable: true
              example: 150
            distanceMeters:
              type: number
              nullable: true
              example: 1200
            rpe:
              type: number
              nullable: true
              example: 6
            notes:
              type: string
        timeZone:
          type: string
          example: Europe/Amsterdam
    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
    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
    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
  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.