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

# Duplicate a workout v2 plan moment

> For sequence plans, creates a new session at the end of the selected plan moment's programme week. For calendar plans, creates a new workout item immediately after every placement of the selected moment, possibly across weeks. Active exercises, set targets, setup fields, scoring settings, and superset group ids are copied; deleted exercises are not copied. An optional targetPlanId copies the day into another non-archived company template (coach/admin only); only the destination is saved. Cross-template copies append to targetWeekNumber (default 1); calendar destinations also require targetWeekday (1=Monday through 7=Sunday) and append a workout placement there. Source calendar placements are not copied across templates. The programme-calendar entitlement is enforced for both plans. This endpoint intentionally accepts an empty request body for same-plan duplication.

Requires the workout_plans:write scope. This operation maps to /app/v1/workout/plans/moments/:planId/:planMomentId/duplicate 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/plans/moments/{planId}/{planMomentId}/duplicate
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/plans/moments/{planId}/{planMomentId}/duplicate:
    post:
      tags:
        - Workout
      summary: Duplicate a workout v2 plan moment
      description: >-
        For sequence plans, creates a new session at the end of the selected
        plan moment's programme week. For calendar plans, creates a new workout
        item immediately after every placement of the selected moment, possibly
        across weeks. Active exercises, set targets, setup fields, scoring
        settings, and superset group ids are copied; deleted exercises are not
        copied. An optional targetPlanId copies the day into another
        non-archived company template (coach/admin only); only the destination
        is saved. Cross-template copies append to targetWeekNumber (default 1);
        calendar destinations also require targetWeekday (1=Monday through
        7=Sunday) and append a workout placement there. Source calendar
        placements are not copied across templates. The programme-calendar
        entitlement is enforced for both plans. This endpoint intentionally
        accepts an empty request body for same-plan duplication.


        Requires the workout_plans:write scope. This operation maps to
        /app/v1/workout/plans/moments/:planId/:planMomentId/duplicate 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: publicWorkoutpostPublicV1WorkoutPlansMomentsPlanIdPlanMomentIdDuplicate
      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`.
        - in: path
          name: planId
          required: true
          description: Workout plan id.
          schema:
            type: string
            example: 67f1234567890abcdef1234
        - in: path
          name: planMomentId
          required: true
          description: Embedded workout plan-moment id.
          schema:
            type: string
            example: 67f1234567890abcdef1234
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: >-
                #/components/schemas/PublicWorkoutSourcePOSTAppV1WorkoutPlansMomentsPlanIdPlanMomentIdDuplicateRequest
      responses:
        '201':
          description: Duplicated plan moment.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/PublicApiWriteSuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: >-
                          #/components/schemas/PublicWorkoutSourcePOSTAppV1WorkoutPlansMomentsPlanIdPlanMomentIdDuplicateResponse201
              examples:
                success:
                  summary: Successful response
                  value:
                    data:
                      planMoment:
                        _id: 67f1234567890abcdef1234
                        name:
                          - lang: en
                            value: Full Body Strength
                          - lang: nl
                            value: Full Body Kracht
                        description:
                          - lang: en
                            value: Full Body Strength
                          - lang: nl
                            value: Full Body Kracht
                        dayOrder: 1
                        order: 0
                        weekNumber: 1
                        sessionOrder: 1
                        date: '2026-04-15'
                        scoringType: forTime
                        targetValue: null
                        descriptionOnly: true
                        timeDomain:
                          windowSeconds: null
                          timeCapSeconds: 900
                          rounds: 3
                          intervalSeconds: null
                          intervalCount: null
                          workSeconds: null
                          restSeconds: null
                        scoreValidation:
                          timeCapSeconds: 900
                          maxReps: null
                          expectedIntervals: null
                        exercises:
                          - _id: 67f1234567890abcdef1234
                            exerciseId: 67f1234567890abcdef1234
                            type: reps
                            minReps: 6
                            maxReps: 8
                            notes: Pause 1 second on the chest.
                            sets: 4
                            metric: kg
                            rest: 120
                            intensity: High
                            difficulty: Intermediate
                            groupId: super-a
                            rpe: 8
                            rmPercentage: 75
                            tempo: '3010'
                            perSetTrackingEnabled: true
                            rpeEnabled: false
                            showSetRpe: true
                            setsData:
                              - setNumber: 1
                                setType: 'N'
                                metric: '12'
                                repetition: 8-12
                                weight: 60
                                rest: 90
                                rpe: 7.5
                                duration: 45
                                distance: 250
                            setupSettingsEnabled: true
                            setupFields:
                              - key: seat
                                label: Seat
                                type: text
                                unit: ''
                                options:
                                  - '1'
                                  - '2'
                                  - '3'
                                  - '4'
                                order: 1
                                required: false
                                enabled: true
                                defaultValue: 3
                            order: 0
                            isDeleted: false
                            deletedAt: null
                            createdAt: '2026-04-12T10:00:00.000Z'
                            updatedAt: '2026-04-12T10:00:00.000Z'
                        isDeleted: false
                        deletedAt: null
                        createdAt: '2026-04-12T10:00:00.000Z'
                        updatedAt: '2026-04-12T10:00:00.000Z'
                      scheduleItems:
                        - _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
                    meta:
                      requestId: 4f849d7d-f4f1-45cc-b4b7-3984a3d17f83
                      rateLimit:
                        limit: 10
                        remaining: 9
                        resetSeconds: 1
                      idempotency:
                        replayed: false
        '400':
          description: An id, destination template, week, or calendar placement is invalid.
          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: >-
            Workout V2 programme calendar is disabled for the active company
            (`WORKOUT_V2_PROGRAMME_CALENDAR_DISABLED`) or the caller lacks
            access.
          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: Workout plan or plan moment was not found.
          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':
          $ref: '#/components/schemas/ErrorResponse'
          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/plans/moments/{planId}/{planMomentId}/duplicate"
            \
              -H "Authorization: Bearer <access_token>" \
              -H "Idempotency-Key: <stable_request_key>" \
              -H "Content-Type: application/json" \
              -d '{}'
components:
  schemas:
    PublicWorkoutSourcePOSTAppV1WorkoutPlansMomentsPlanIdPlanMomentIdDuplicateRequest:
      type: object
      properties:
        targetPlanId:
          type: string
          description: >-
            Optional destination company template id. Defaults to the source
            plan.
        targetWeekNumber:
          type: integer
          minimum: 1
          default: 1
          description: >-
            Destination programme week for cross-template copies. Recurring
            plans require week 1.
        targetWeekday:
          type: integer
          enum:
            - 1
            - 2
            - 3
            - 4
            - 5
            - 6
            - 7
          description: >-
            Required for cross-template copies to a calendar: Monday=1 through
            Sunday=7. A rest day cannot contain a workout.
    PublicApiWriteSuccessResponse:
      type: object
      additionalProperties: false
      required:
        - data
        - meta
      properties:
        data:
          type: object
        meta:
          $ref: '#/components/schemas/PublicApiWriteMeta'
    PublicWorkoutSourcePOSTAppV1WorkoutPlansMomentsPlanIdPlanMomentIdDuplicateResponse201:
      type: object
      properties:
        planMoment:
          type: object
          properties:
            _id:
              type: string
              example: 67f1234567890abcdef1234
            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
              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
            dayOrder:
              type: number
              example: 1
            order:
              type: number
              example: 0
            weekNumber:
              type: integer
              minimum: 1
              example: 1
            sessionOrder:
              type: integer
              minimum: 1
              example: 1
            date:
              type: string
              example: '2026-04-15'
            scoringType:
              type: string
              enum:
                - standard
                - forTime
                - amrap
                - emom
                - tabata
                - maxLoad
              default: standard
              example: forTime
              description: >-
                Scoring mechanism. Must not be `standard` when `descriptionOnly`
                is true.
            targetValue:
              type: number
              nullable: true
              minimum: 0
              example: null
            descriptionOnly:
              type: boolean
              default: false
              example: true
              description: >-
                Marks an exercise-free scored day: the full workout lives in
                `description` (required), `exercises` must stay empty,
                `scoringType` must not be standard, and amrap/emom/tabata
                require their full `timeDomain`. Completing the day requires a
                manual `wodResult`. Enforced on every write path, including
                client day edits. Moments that merely have no exercises are NOT
                scored unless this is true.
            timeDomain:
              type: object
              nullable: true
              description: >-
                Clock prescription, same contract as a WOD `timeDomain`. Allowed
                fields depend on `scoringType`: amrap → windowSeconds
                (required); forTime → timeCapSeconds, rounds (defaults to 1);
                emom → intervalSeconds, intervalCount (both required); tabata →
                workSeconds, restSeconds, intervalCount (all required);
                standard/maxLoad → none.
              properties:
                windowSeconds:
                  type: integer
                  nullable: true
                  minimum: 1
                  example: null
                timeCapSeconds:
                  type: integer
                  nullable: true
                  minimum: 1
                  example: 900
                rounds:
                  type: integer
                  nullable: true
                  minimum: 1
                  example: 3
                intervalSeconds:
                  type: integer
                  nullable: true
                  minimum: 1
                  example: null
                intervalCount:
                  type: integer
                  nullable: true
                  minimum: 1
                  example: null
                workSeconds:
                  type: integer
                  nullable: true
                  minimum: 1
                  example: null
                restSeconds:
                  type: integer
                  nullable: true
                  minimum: 0
                  example: null
            scoreValidation:
              type: object
              nullable: true
              description: >-
                Optional result caps. timeCapSeconds and expectedIntervals are
                derived from `timeDomain` when one is set.
              properties:
                timeCapSeconds:
                  type: integer
                  nullable: true
                  minimum: 1
                  example: 900
                maxReps:
                  type: integer
                  nullable: true
                  minimum: 1
                  example: null
                expectedIntervals:
                  type: integer
                  nullable: true
                  minimum: 1
                  example: null
            exercises:
              type: array
              items:
                type: object
                properties:
                  _id:
                    type: string
                    example: 67f1234567890abcdef1234
                  exerciseId:
                    type: string
                    example: 67f1234567890abcdef1234
                  type:
                    type: string
                    enum:
                      - reps
                      - time
                      - distance
                    example: reps
                  minReps:
                    type: number
                    example: 6
                  maxReps:
                    type: number
                    example: 8
                  notes:
                    type: string
                    example: Pause 1 second on the chest.
                  sets:
                    type: number
                    example: 4
                  metric:
                    type: string
                    example: kg
                  rest:
                    type: number
                    example: 120
                  intensity:
                    type: string
                    enum:
                      - Low
                      - Medium
                      - High
                    example: High
                  difficulty:
                    type: string
                    enum:
                      - Beginner
                      - Intermediate
                      - Advanced
                    example: Intermediate
                  groupId:
                    type: string
                    example: super-a
                  rpe:
                    type: number
                    example: 8
                  rmPercentage:
                    type: number
                    example: 75
                  tempo:
                    type: string
                    example: '3010'
                  perSetTrackingEnabled:
                    type: boolean
                    example: true
                  rpeEnabled:
                    type: boolean
                    example: false
                    description: >-
                      Master RPE switch for this plan exercise. False hides
                      current targets and inputs without clearing prescriptions
                      or recorded history. Missing legacy values retain RPE when
                      an exercise target or per-set preference exists.
                      Independent from showSetRpe.
                  showSetRpe:
                    type: boolean
                    example: true
                    description: >-
                      Stored per-set RPE preference. Live input is visible only
                      when RPE is enabled; authoring retains this preference
                      while rpeEnabled is false.
                  setsData:
                    type: array
                    items:
                      type: object
                      properties:
                        setNumber:
                          type: integer
                          minimum: 1
                          example: 1
                        setType:
                          type: string
                          enum:
                            - 'N'
                            - W
                            - D
                            - F
                          example: 'N'
                          description: >-
                            Planned set type: N normal, W warm-up, D drop set, F
                            to failure.
                        metric:
                          type: string
                          example: '12'
                        repetition:
                          type: string
                          example: 8-12
                        weight:
                          type: number
                          example: 60
                        rest:
                          type: number
                          example: 90
                        rpe:
                          type:
                            - number
                            - 'null'
                          minimum: 0
                          maximum: 10
                          example: 7.5
                          description: >-
                            Optional target RPE for this set. It does not
                            inherit the exercise-level RPE value.
                        duration:
                          type: number
                          example: 45
                        distance:
                          type: number
                          example: 250
                  setupSettingsEnabled:
                    type: boolean
                    example: true
                    description: >-
                      Enables the exercise-level machine or equipment setup
                      settings block.
                  setupFields:
                    type: array
                    maxItems: 8
                    items:
                      type: object
                      required:
                        - key
                        - label
                      properties:
                        key:
                          type: string
                          example: seat
                        label:
                          type: string
                          example: Seat
                        type:
                          type: string
                          enum:
                            - text
                            - number
                            - select
                          example: text
                        unit:
                          type: string
                          example: ''
                        options:
                          type: array
                          items:
                            type: string
                          example:
                            - '1'
                            - '2'
                            - '3'
                            - '4'
                        order:
                          type: number
                          example: 1
                        required:
                          type: boolean
                          example: false
                        enabled:
                          type: boolean
                          example: true
                        defaultValue:
                          oneOf:
                            - type: string
                            - type: number
                          example: 3
                  order:
                    type: number
                    example: 0
                  isDeleted:
                    type: boolean
                    example: false
                  deletedAt:
                    type:
                      - string
                      - 'null'
                    format: date-time
                    example: null
                  createdAt:
                    type: string
                    format: date-time
                    example: '2026-04-12T10:00:00.000Z'
                  updatedAt:
                    type: string
                    format: date-time
                    example: '2026-04-12T10:00:00.000Z'
            isDeleted:
              type: boolean
              example: false
            deletedAt:
              type:
                - string
                - 'null'
              format: date-time
              example: null
            createdAt:
              type: string
              format: date-time
              example: '2026-04-12T10:00:00.000Z'
            updatedAt:
              type: string
              format: date-time
              example: '2026-04-12T10:00:00.000Z'
        scheduleItems:
          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'
    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
    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
    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.