openapi: 3.1.0
info:
  contact:
    email: api@tesseta.com
    name: Tesseta API Support
  description: "Read-only third-party access to a user's Tesseta data (workouts, nutrition,\
    \ medications & adherence, labs & metrics). User-delegated via OAuth 2.0 Authorization\
    \ Code + PKCE. List endpoints are keyset-paginated (`{data, nextCursor, hasMore}`)\
    \ and support incremental pull via `updatedSince`. Errors are RFC 7807 `application/problem+json`.\
    \ Scopes: profile:read, workouts:read, nutrition:read, medications:read, labs:read,\
    \ offline_access."
  license:
    name: Tesseta Platform API Terms
    url: https://tesseta.com/terms
  termsOfService: https://tesseta.com/terms
  title: Tesseta Platform API
  version: v1
externalDocs:
  description: Integration guide & rendered reference
  url: https://tesseta.com/api.html
servers:
- description: Production
  url: https://api.tesseta.com
- description: Same-origin (relative)
  url: /
security:
- tesseta-oauth: []
tags:
- description: "Blood readings, DEXA scans, body composition, and daily health metrics\
    \ — the most sensitive slice. Requires the `labs:read` scope."
  name: Labs & metrics
- description: Logged food entries and daily macro totals vs targets. Requires the
    `nutrition:read` scope.
  name: Nutrition
- description: "Medications, schedules, today's doses, and adherence — the highest-value\
    \ monitoring signal. Requires the `medications:read` scope."
  name: Medications
- description: Training programs and completed workout sessions with logged sets.
    Requires the `workouts:read` scope.
  name: Workouts
- description: The granted user's profile. Requires the `profile:read` scope.
  name: User
paths:
  /v1/adherence:
    get:
      description: "Per-day taken/skipped adherence across all medications, newest\
        \ first. Window defaults to the last 30 days (max 366)."
      operationId: adherence
      parameters:
      - description: Inclusive lower bound date (YYYY-MM-DD).
        in: query
        name: from
        required: false
        schema:
          type: string
      - description: Inclusive upper bound date (YYYY-MM-DD).
        in: query
        name: to
        required: false
        schema:
          type: string
      - description: Opaque pagination cursor from a prior page's `nextCursor`.
        in: query
        name: cursor
        required: false
        schema:
          type: string
      - description: "Max items per page (default 50, max 200)."
        in: query
        name: limit
        required: false
        schema:
          type: integer
          format: int32
      responses:
        "200":
          content:
            '*/*':
              schema:
                $ref: "#/components/schemas/V1PageAdherenceDto"
          description: OK
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
        "400":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "The request has an invalid parameter (bad cursor, date, limit,\
            \ or filter value)."
        "401":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "Missing, expired, or invalid access token."
        "403":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: The access token is valid but lacks the scope this resource
            requires.
        "429":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: Per-client/per-user rate limit exceeded; see Retry-After.
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
            Retry-After:
              description: Seconds until the rate-limit window resets.
              schema:
                type: integer
                format: int32
      summary: List adherence logs
      tags:
      - Medications
  /v1/doses:
    get:
      description: Scheduled doses for the given day (default today) with taken status.
      operationId: doses
      parameters:
      - description: The day to fetch (YYYY-MM-DD). Defaults to today.
        in: query
        name: date
        required: false
        schema:
          type: string
      responses:
        "200":
          content:
            '*/*':
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/DoseDto"
          description: OK
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
        "400":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "The request has an invalid parameter (bad cursor, date, limit,\
            \ or filter value)."
        "401":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "Missing, expired, or invalid access token."
        "403":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: The access token is valid but lacks the scope this resource
            requires.
        "429":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: Per-client/per-user rate limit exceeded; see Retry-After.
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
            Retry-After:
              description: Seconds until the rate-limit window resets.
              schema:
                type: integer
                format: int32
      summary: List a day's doses
      tags:
      - Medications
  /v1/labs/blood:
    get:
      description: "Blood marker readings, newest first, optionally filtered by marker/date."
      operationId: bloodReadings
      parameters:
      - description: "Filter to a single blood marker (enum name, e.g. TESTOSTERONE)."
        in: query
        name: marker
        required: false
        schema:
          type: string
      - description: Inclusive lower bound on sample date (YYYY-MM-DD).
        in: query
        name: from
        required: false
        schema:
          type: string
      - description: Inclusive upper bound on sample date (YYYY-MM-DD).
        in: query
        name: to
        required: false
        schema:
          type: string
      - description: Opaque pagination cursor from a prior page's `nextCursor`.
        in: query
        name: cursor
        required: false
        schema:
          type: string
      - description: "Max items per page (default 50, max 200)."
        in: query
        name: limit
        required: false
        schema:
          type: integer
          format: int32
      - description: ISO-8601 instant; return only readings updated at or after it.
        in: query
        name: updatedSince
        required: false
        schema:
          type: string
      responses:
        "200":
          content:
            '*/*':
              schema:
                $ref: "#/components/schemas/V1PageBloodDto"
          description: OK
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
        "400":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "The request has an invalid parameter (bad cursor, date, limit,\
            \ or filter value)."
        "401":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "Missing, expired, or invalid access token."
        "403":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: The access token is valid but lacks the scope this resource
            requires.
        "429":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: Per-client/per-user rate limit exceeded; see Retry-After.
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
            Retry-After:
              description: Seconds until the rate-limit window resets.
              schema:
                type: integer
                format: int32
      summary: List blood readings
      tags:
      - Labs & metrics
  /v1/labs/dexa:
    get:
      description: "DEXA scan summaries, newest first."
      operationId: dexaScans
      parameters:
      - description: Opaque pagination cursor from a prior page's `nextCursor`.
        in: query
        name: cursor
        required: false
        schema:
          type: string
      - description: "Max items per page (default 50, max 200)."
        in: query
        name: limit
        required: false
        schema:
          type: integer
          format: int32
      - description: ISO-8601 instant; return only scans updated at or after it.
        in: query
        name: updatedSince
        required: false
        schema:
          type: string
      responses:
        "200":
          content:
            '*/*':
              schema:
                $ref: "#/components/schemas/V1PageDexaSummary"
          description: OK
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
        "400":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "The request has an invalid parameter (bad cursor, date, limit,\
            \ or filter value)."
        "401":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "Missing, expired, or invalid access token."
        "403":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: The access token is valid but lacks the scope this resource
            requires.
        "429":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: Per-client/per-user rate limit exceeded; see Retry-After.
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
            Retry-After:
              description: Seconds until the rate-limit window resets.
              schema:
                type: integer
                format: int32
      summary: List DEXA scans
      tags:
      - Labs & metrics
  /v1/labs/dexa/{scanId}:
    get:
      description: A single DEXA scan with full per-region body-composition detail.
      operationId: dexaScan
      parameters:
      - description: DEXA scan id.
        in: path
        name: scanId
        required: true
        schema:
          type: string
      responses:
        "200":
          content:
            '*/*':
              schema:
                $ref: "#/components/schemas/DexaDetail"
          description: OK
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
        "400":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "The request has an invalid parameter (bad cursor, date, limit,\
            \ or filter value)."
        "401":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "Missing, expired, or invalid access token."
        "403":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: The access token is valid but lacks the scope this resource
            requires.
        "404":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: No such resource for this user.
        "429":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: Per-client/per-user rate limit exceeded; see Retry-After.
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
            Retry-After:
              description: Seconds until the rate-limit window resets.
              schema:
                type: integer
                format: int32
      summary: Get one DEXA scan
      tags:
      - Labs & metrics
  /v1/medications:
    get:
      description: "The user's medications, newest first. Optionally filter by status."
      operationId: listMedications
      parameters:
      - description: "Filter by status: ACTIVE or DISCONTINUED. Omit for all."
        in: query
        name: status
        required: false
        schema:
          type: string
      - description: Opaque pagination cursor from a prior page's `nextCursor`.
        in: query
        name: cursor
        required: false
        schema:
          type: string
      - description: "Max items per page (default 50, max 200)."
        in: query
        name: limit
        required: false
        schema:
          type: integer
          format: int32
      - description: ISO-8601 instant; return only medications updated at or after
          it.
        in: query
        name: updatedSince
        required: false
        schema:
          type: string
      responses:
        "200":
          content:
            '*/*':
              schema:
                $ref: "#/components/schemas/V1PageMedicationDto"
          description: OK
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
        "400":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "The request has an invalid parameter (bad cursor, date, limit,\
            \ or filter value)."
        "401":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "Missing, expired, or invalid access token."
        "403":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: The access token is valid but lacks the scope this resource
            requires.
        "429":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: Per-client/per-user rate limit exceeded; see Retry-After.
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
            Retry-After:
              description: Seconds until the rate-limit window resets.
              schema:
                type: integer
                format: int32
      summary: List medications
      tags:
      - Medications
  /v1/medications/{medicationId}:
    get:
      description: A single medication with its schedule and dosing.
      operationId: getMedication
      parameters:
      - description: Medication id.
        in: path
        name: medicationId
        required: true
        schema:
          type: string
      responses:
        "200":
          content:
            '*/*':
              schema:
                $ref: "#/components/schemas/MedicationDto"
          description: OK
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
        "400":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "The request has an invalid parameter (bad cursor, date, limit,\
            \ or filter value)."
        "401":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "Missing, expired, or invalid access token."
        "403":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: The access token is valid but lacks the scope this resource
            requires.
        "404":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: No such resource for this user.
        "429":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: Per-client/per-user rate limit exceeded; see Retry-After.
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
            Retry-After:
              description: Seconds until the rate-limit window resets.
              schema:
                type: integer
                format: int32
      summary: Get one medication
      tags:
      - Medications
  /v1/metrics/body-composition:
    get:
      description: "Weight / body-fat / lean-mass measurements, newest first, optionally\
        \ filtered by metric and a `from`/`to` instant window."
      operationId: bodyComposition
      parameters:
      - description: "Filter to a single metric (enum name, e.g. WEIGHT, BODY_FAT)."
        in: query
        name: metric
        required: false
        schema:
          type: string
      - description: Inclusive lower bound sample time (ISO-8601 instant).
        in: query
        name: from
        required: false
        schema:
          type: string
      - description: Inclusive upper bound sample time (ISO-8601 instant).
        in: query
        name: to
        required: false
        schema:
          type: string
      - description: Opaque pagination cursor from a prior page's `nextCursor`.
        in: query
        name: cursor
        required: false
        schema:
          type: string
      - description: "Max items per page (default 50, max 200)."
        in: query
        name: limit
        required: false
        schema:
          type: integer
          format: int32
      responses:
        "200":
          content:
            '*/*':
              schema:
                $ref: "#/components/schemas/V1PageBodyCompositionDto"
          description: OK
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
        "400":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "The request has an invalid parameter (bad cursor, date, limit,\
            \ or filter value)."
        "401":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "Missing, expired, or invalid access token."
        "403":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: The access token is valid but lacks the scope this resource
            requires.
        "429":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: Per-client/per-user rate limit exceeded; see Retry-After.
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
            Retry-After:
              description: Seconds until the rate-limit window resets.
              schema:
                type: integer
                format: int32
      summary: List body-composition measurements
      tags:
      - Labs & metrics
  /v1/metrics/daily:
    get:
      description: "Daily steps / resting HR / sleep / HRV, newest first. Window defaults\
        \ to the last 90 days (max ~10 years)."
      operationId: dailyMetrics
      parameters:
      - description: Inclusive lower bound date (YYYY-MM-DD).
        in: query
        name: from
        required: false
        schema:
          type: string
      - description: Inclusive upper bound date (YYYY-MM-DD).
        in: query
        name: to
        required: false
        schema:
          type: string
      - description: Opaque pagination cursor from a prior page's `nextCursor`.
        in: query
        name: cursor
        required: false
        schema:
          type: string
      - description: "Max items per page (default 50, max 200)."
        in: query
        name: limit
        required: false
        schema:
          type: integer
          format: int32
      responses:
        "200":
          content:
            '*/*':
              schema:
                $ref: "#/components/schemas/V1PageDailyMetricDto"
          description: OK
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
        "400":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "The request has an invalid parameter (bad cursor, date, limit,\
            \ or filter value)."
        "401":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "Missing, expired, or invalid access token."
        "403":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: The access token is valid but lacks the scope this resource
            requires.
        "429":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: Per-client/per-user rate limit exceeded; see Retry-After.
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
            Retry-After:
              description: Seconds until the rate-limit window resets.
              schema:
                type: integer
                format: int32
      summary: List daily metrics
      tags:
      - Labs & metrics
  /v1/nutrition/days/{date}:
    get:
      description: Daily macro totals for the given date alongside the active macro
        target.
      operationId: day
      parameters:
      - description: The day to fetch (YYYY-MM-DD).
        in: path
        name: date
        required: true
        schema:
          type: string
      responses:
        "200":
          content:
            '*/*':
              schema:
                $ref: "#/components/schemas/DayResponse"
          description: OK
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
        "400":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "The request has an invalid parameter (bad cursor, date, limit,\
            \ or filter value)."
        "401":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "Missing, expired, or invalid access token."
        "403":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: The access token is valid but lacks the scope this resource
            requires.
        "404":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: No such resource for this user.
        "429":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: Per-client/per-user rate limit exceeded; see Retry-After.
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
            Retry-After:
              description: Seconds until the rate-limit window resets.
              schema:
                type: integer
                format: int32
      summary: Get a day's nutrition totals
      tags:
      - Nutrition
  /v1/nutrition/entries:
    get:
      description: "Logged food entries, newest first. Pass `date` for a single day,\
        \ or a `from`/`to` window (default last 7 days, max 92)."
      operationId: entries
      parameters:
      - description: Single day to fetch (YYYY-MM-DD). Overrides from/to.
        in: query
        name: date
        required: false
        schema:
          type: string
      - description: Inclusive lower bound date (YYYY-MM-DD) when `date` is omitted.
        in: query
        name: from
        required: false
        schema:
          type: string
      - description: Inclusive upper bound date (YYYY-MM-DD) when `date` is omitted.
        in: query
        name: to
        required: false
        schema:
          type: string
      - description: Opaque pagination cursor from a prior page's `nextCursor`.
        in: query
        name: cursor
        required: false
        schema:
          type: string
      - description: "Max items per page (default 50, max 200)."
        in: query
        name: limit
        required: false
        schema:
          type: integer
          format: int32
      - description: ISO-8601 instant; return only entries updated at or after it.
        in: query
        name: updatedSince
        required: false
        schema:
          type: string
      responses:
        "200":
          content:
            '*/*':
              schema:
                $ref: "#/components/schemas/V1PageEntryDto"
          description: OK
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
        "400":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "The request has an invalid parameter (bad cursor, date, limit,\
            \ or filter value)."
        "401":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "Missing, expired, or invalid access token."
        "403":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: The access token is valid but lacks the scope this resource
            requires.
        "429":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: Per-client/per-user rate limit exceeded; see Retry-After.
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
            Retry-After:
              description: Seconds until the rate-limit window resets.
              schema:
                type: integer
                format: int32
      summary: List food entries
      tags:
      - Nutrition
  /v1/programs:
    get:
      description: "Programs (the training schedule), newest first, keyset-paginated."
      operationId: listPrograms
      parameters:
      - description: Opaque pagination cursor from a prior page's `nextCursor`.
        in: query
        name: cursor
        required: false
        schema:
          type: string
      - description: "Max items per page (default 50, max 200)."
        in: query
        name: limit
        required: false
        schema:
          type: integer
          format: int32
      - description: ISO-8601 instant; return only programs updated at or after this
          time (e.g. 2026-07-01T00:00:00Z). Use for incremental pulls.
        in: query
        name: updatedSince
        required: false
        schema:
          type: string
      responses:
        "200":
          content:
            '*/*':
              schema:
                $ref: "#/components/schemas/V1PageProgramSummary"
          description: OK
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
        "400":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "The request has an invalid parameter (bad cursor, date, limit,\
            \ or filter value)."
        "401":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "Missing, expired, or invalid access token."
        "403":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: The access token is valid but lacks the scope this resource
            requires.
        "429":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: Per-client/per-user rate limit exceeded; see Retry-After.
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
            Retry-After:
              description: Seconds until the rate-limit window resets.
              schema:
                type: integer
                format: int32
      summary: List training programs
      tags:
      - Workouts
  /v1/programs/{programId}:
    get:
      description: A single program with its full phase / day / block / prescription
        tree.
      operationId: getProgram
      parameters:
      - description: Program id.
        in: path
        name: programId
        required: true
        schema:
          type: string
      responses:
        "200":
          content:
            '*/*':
              schema:
                $ref: "#/components/schemas/ProgramDetail"
          description: OK
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
        "400":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "The request has an invalid parameter (bad cursor, date, limit,\
            \ or filter value)."
        "401":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "Missing, expired, or invalid access token."
        "403":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: The access token is valid but lacks the scope this resource
            requires.
        "404":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: No such resource for this user.
        "429":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: Per-client/per-user rate limit exceeded; see Retry-After.
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
            Retry-After:
              description: Seconds until the rate-limit window resets.
              schema:
                type: integer
                format: int32
      summary: Get one program
      tags:
      - Workouts
  /v1/user:
    get:
      description: Returns the profile of the user who authorized this app.
      operationId: get
      responses:
        "200":
          content:
            '*/*':
              schema:
                $ref: "#/components/schemas/UserResponse"
          description: OK
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
        "400":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "The request has an invalid parameter (bad cursor, date, limit,\
            \ or filter value)."
        "401":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "Missing, expired, or invalid access token."
        "403":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: The access token is valid but lacks the scope this resource
            requires.
        "429":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: Per-client/per-user rate limit exceeded; see Retry-After.
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
            Retry-After:
              description: Seconds until the rate-limit window resets.
              schema:
                type: integer
                format: int32
      summary: Get the granted user's profile
      tags:
      - User
  /v1/workouts:
    get:
      description: "Completed sessions (training history) across all programs, newest\
        \ first."
      operationId: listWorkouts
      parameters:
      - description: Opaque pagination cursor from a prior page's `nextCursor`.
        in: query
        name: cursor
        required: false
        schema:
          type: string
      - description: "Max items per page (default 50, max 200)."
        in: query
        name: limit
        required: false
        schema:
          type: integer
          format: int32
      - description: Inclusive lower bound on session date (YYYY-MM-DD).
        in: query
        name: from
        required: false
        schema:
          type: string
      - description: Inclusive upper bound on session date (YYYY-MM-DD).
        in: query
        name: to
        required: false
        schema:
          type: string
      responses:
        "200":
          content:
            '*/*':
              schema:
                $ref: "#/components/schemas/V1PageWorkoutSummary"
          description: OK
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
        "400":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "The request has an invalid parameter (bad cursor, date, limit,\
            \ or filter value)."
        "401":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "Missing, expired, or invalid access token."
        "403":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: The access token is valid but lacks the scope this resource
            requires.
        "429":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: Per-client/per-user rate limit exceeded; see Retry-After.
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
            Retry-After:
              description: Seconds until the rate-limit window resets.
              schema:
                type: integer
                format: int32
      summary: List completed workouts
      tags:
      - Workouts
  /v1/workouts/{programId}/{scheduledId}:
    get:
      description: A single completed session with its logged exercises and sets.
      operationId: getWorkout
      parameters:
      - description: Program id.
        in: path
        name: programId
        required: true
        schema:
          type: string
      - description: Scheduled-session id within the program.
        in: path
        name: scheduledId
        required: true
        schema:
          type: string
      responses:
        "200":
          content:
            '*/*':
              schema:
                $ref: "#/components/schemas/WorkoutDetail"
          description: OK
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
        "400":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "The request has an invalid parameter (bad cursor, date, limit,\
            \ or filter value)."
        "401":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: "Missing, expired, or invalid access token."
        "403":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: The access token is valid but lacks the scope this resource
            requires.
        "404":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: No such resource for this user.
        "429":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetail"
          description: Per-client/per-user rate limit exceeded; see Retry-After.
          headers:
            RateLimit-Limit:
              description: Request budget for the current fixed window.
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests remaining in the current window.
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                format: int32
            Retry-After:
              description: Seconds until the rate-limit window resets.
              schema:
                type: integer
                format: int32
      summary: Get one completed workout
      tags:
      - Workouts
components:
  schemas:
    AdherenceDto:
      type: object
      properties:
        date:
          type: string
          format: date
        doses:
          type: array
          items:
            $ref: "#/components/schemas/DoseLogDto"
        medicationId:
          type: string
        notes:
          type: string
    BlockDto:
      type: object
      properties:
        id:
          type: string
        orderIndex:
          type: integer
          format: int32
        prescriptions:
          type: array
          items:
            $ref: "#/components/schemas/PrescriptionDto"
        title:
          type: string
        type:
          type: string
    BloodDto:
      type: object
      properties:
        createdAt:
          type: string
          format: date-time
        id:
          type: string
        labSource:
          type: string
        marker:
          type: string
        notes:
          type: string
        sampleDate:
          type: string
          format: date
        unit:
          type: string
        updatedAt:
          type: string
          format: date-time
        value:
          type: number
          format: double
    BodyCompositionDto:
      type: object
      properties:
        id:
          type: string
        metric:
          type: string
        recordingMethod:
          type: string
        sampleTime:
          type: string
          format: date-time
        sourcePlatform:
          type: string
        value:
          type: number
          format: double
    CycleDto:
      type: object
      properties:
        offWeeks:
          type: integer
          format: int32
        onWeeks:
          type: integer
          format: int32
        startDate:
          type: string
          format: date
    DailyMetricDto:
      type: object
      properties:
        date:
          type: string
          format: date
        hrvMs:
          type: integer
          format: int32
        restingHeartRate:
          type: integer
          format: int32
        sleepMinutes:
          type: integer
          format: int32
        sleepScore:
          type: integer
          format: int32
        steps:
          type: integer
          format: int32
    DayDto:
      type: object
      properties:
        blocks:
          type: array
          items:
            $ref: "#/components/schemas/BlockDto"
        dayOfWeek:
          type: string
        id:
          type: string
        label:
          type: string
        locationId:
          type: string
        orderIndex:
          type: integer
          format: int32
    DayResponse:
      type: object
      properties:
        date:
          type: string
          format: date
        target:
          $ref: "#/components/schemas/MacroDto"
        totals:
          $ref: "#/components/schemas/MacroDto"
        updatedAt:
          type: string
          format: date-time
    DexaDetail:
      type: object
      properties:
        android:
          $ref: "#/components/schemas/RegionDto"
        androidGynoidRatio:
          type: number
          format: double
        armsLeft:
          $ref: "#/components/schemas/RegionDto"
        armsRight:
          $ref: "#/components/schemas/RegionDto"
        armsTotal:
          $ref: "#/components/schemas/RegionDto"
        bmdTScore:
          type: number
          format: double
        bmdZScore:
          type: number
          format: double
        fatTissueLb:
          type: number
          format: double
        gynoid:
          $ref: "#/components/schemas/RegionDto"
        id:
          type: string
        leanTissueLb:
          type: number
          format: double
        legsLeft:
          $ref: "#/components/schemas/RegionDto"
        legsRight:
          $ref: "#/components/schemas/RegionDto"
        legsTotal:
          $ref: "#/components/schemas/RegionDto"
        measuredOn:
          type: string
          format: date
        restingMetabolicRateKcal:
          type: integer
          format: int32
        sourceFacility:
          type: string
        totalBodyFatPercent:
          type: number
          format: double
        totalMassLb:
          type: number
          format: double
        trunk:
          $ref: "#/components/schemas/RegionDto"
        updatedAt:
          type: string
          format: date-time
        visceralFatLb:
          type: number
          format: double
    DexaSummary:
      type: object
      properties:
        fatTissueLb:
          type: number
          format: double
        id:
          type: string
        leanTissueLb:
          type: number
          format: double
        measuredOn:
          type: string
          format: date
        sourceFacility:
          type: string
        totalBodyFatPercent:
          type: number
          format: double
        totalMassLb:
          type: number
          format: double
        updatedAt:
          type: string
          format: date-time
    DoseDto:
      type: object
      properties:
        dose:
          type: number
          format: double
        drugName:
          type: string
        imageUrl:
          type: string
        medicationId:
          type: string
        taken:
          type: boolean
        takenAt:
          type: string
          format: date-time
        unit:
          type: string
        window:
          type: string
    DoseLogDto:
      type: object
      properties:
        dose:
          type: number
          format: double
        takenAt:
          type: string
          format: date-time
        window:
          type: string
    EntryDto:
      type: object
      properties:
        createdAt:
          type: string
          format: date-time
        date:
          type: string
          format: date
        foodId:
          type: string
        foodName:
          type: string
        id:
          type: string
        macros:
          $ref: "#/components/schemas/MacroDto"
        meal:
          type: string
        quantity:
          type: number
          format: double
        servingGrams:
          type: number
          format: double
        servingLabel:
          type: string
        source:
          type: string
        updatedAt:
          type: string
          format: date-time
    FrequencyDto:
      type: object
      properties:
        cycle:
          $ref: "#/components/schemas/CycleDto"
        specificDays:
          type: array
          items:
            type: string
        timesPerPeriod:
          type: integer
          format: int32
        type:
          type: string
    LoggedExercise:
      type: object
      properties:
        blockType:
          type: string
        exerciseId:
          type: string
        loggedSets:
          type: array
          items:
            $ref: "#/components/schemas/LoggedSetDto"
        notes:
          type: string
    LoggedSetDto:
      type: object
      properties:
        completedAt:
          type: string
          format: date-time
        durationSeconds:
          type: integer
          format: int32
        reps:
          type: integer
          format: int32
        restSeconds:
          type: integer
          format: int32
        rpe:
          type: number
          format: double
        weightLbs:
          type: number
          format: double
    MacroDto:
      type: object
      properties:
        caloriesKcal:
          type: number
          format: double
        carbsGrams:
          type: number
          format: double
        fatGrams:
          type: number
          format: double
        fiberGrams:
          type: number
          format: double
        proteinGrams:
          type: number
          format: double
        sugarGrams:
          type: number
          format: double
    MedicationDto:
      type: object
      properties:
        createdAt:
          type: string
          format: date-time
        dose:
          type: number
          format: double
        drugId:
          type: string
        endDate:
          type: string
          format: date
        frequency:
          $ref: "#/components/schemas/FrequencyDto"
        id:
          type: string
        name:
          type: string
        startDate:
          type: string
          format: date
        status:
          type: string
        timeSlots:
          type: array
          items:
            $ref: "#/components/schemas/TimeSlotDto"
        unit:
          type: string
        updatedAt:
          type: string
          format: date-time
    PhaseDto:
      type: object
      properties:
        completedAt:
          type: string
          format: date-time
        days:
          type: array
          items:
            $ref: "#/components/schemas/DayDto"
        deloadWeekIndex:
          type: integer
          format: int32
        focus:
          type: string
        id:
          type: string
        orderIndex:
          type: integer
          format: int32
        status:
          type: string
        targetEndDate:
          type: string
          format: date
        targetStartDate:
          type: string
          format: date
        title:
          type: string
        weeks:
          type: integer
          format: int32
    PrescriptionDto:
      type: object
      properties:
        durationSeconds:
          type: integer
          format: int32
        exerciseId:
          type: string
        loadBasis:
          type: string
        notes:
          type: string
        orderIndex:
          type: integer
          format: int32
        repsMax:
          type: integer
          format: int32
        repsMin:
          type: integer
          format: int32
        restSeconds:
          type: integer
          format: int32
        sets:
          type: integer
          format: int32
        targetWeightLbs:
          type: number
          format: double
        tempo:
          type: string
    ProblemDetail:
      type: object
      description: RFC 7807 problem detail (application/problem+json).
      properties:
        detail:
          type: string
          description: Human-readable explanation specific to this occurrence.
        instance:
          type: string
          description: A URI reference identifying the specific occurrence.
        status:
          type: integer
          format: int32
          description: The HTTP status code.
        title:
          type: string
          description: "Short, human-readable summary of the problem type."
        type:
          type: string
          description: A URI reference identifying the problem type.
          example: about:blank
    ProgramDetail:
      type: object
      properties:
        completedAt:
          type: string
          format: date-time
        createdAt:
          type: string
          format: date-time
        description:
          type: string
        goalId:
          type: string
        id:
          type: string
        phaseOrder:
          type: array
          items:
            type: string
        phases:
          type: array
          items:
            $ref: "#/components/schemas/PhaseDto"
        source:
          type: string
        startDate:
          type: string
          format: date
        status:
          type: string
        title:
          type: string
        updatedAt:
          type: string
          format: date-time
    ProgramSummary:
      type: object
      properties:
        completedAt:
          type: string
          format: date-time
        createdAt:
          type: string
          format: date-time
        description:
          type: string
        goalId:
          type: string
        id:
          type: string
        phaseCount:
          type: integer
          format: int32
        source:
          type: string
        startDate:
          type: string
          format: date
        status:
          type: string
        title:
          type: string
        updatedAt:
          type: string
          format: date-time
    RegionDto:
      type: object
      properties:
        fatTissueLb:
          type: number
          format: double
        leanTissueLb:
          type: number
          format: double
        regionFatPercent:
          type: number
          format: double
        totalMassLb:
          type: number
          format: double
    TimeSlotDto:
      type: object
      properties:
        dose:
          type: number
          format: double
        window:
          type: string
    UserResponse:
      type: object
      description: A Tesseta user's profile.
      properties:
        displayName:
          type: string
          description: Display name.
        email:
          type: string
          description: Account email.
        heightCm:
          type: integer
          format: int32
          description: "Height in centimetres, if known."
        id:
          type: string
          description: Stable Tesseta user id.
    V1PageAdherenceDto:
      type: object
      description: "Keyset-paginated list envelope, newest first. To page, pass `nextCursor`\
        \ back as the `cursor` query parameter until `hasMore` is false."
      properties:
        data:
          type: array
          description: "The results for this page, newest first."
          items:
            $ref: "#/components/schemas/AdherenceDto"
        hasMore:
          type: boolean
          description: True when more results exist beyond this page.
        nextCursor:
          type: string
          description: Opaque cursor for the next page; pass as `cursor`. Null on
            the last page.
    V1PageBloodDto:
      type: object
      description: "Keyset-paginated list envelope, newest first. To page, pass `nextCursor`\
        \ back as the `cursor` query parameter until `hasMore` is false."
      properties:
        data:
          type: array
          description: "The results for this page, newest first."
          items:
            $ref: "#/components/schemas/BloodDto"
        hasMore:
          type: boolean
          description: True when more results exist beyond this page.
        nextCursor:
          type: string
          description: Opaque cursor for the next page; pass as `cursor`. Null on
            the last page.
    V1PageBodyCompositionDto:
      type: object
      description: "Keyset-paginated list envelope, newest first. To page, pass `nextCursor`\
        \ back as the `cursor` query parameter until `hasMore` is false."
      properties:
        data:
          type: array
          description: "The results for this page, newest first."
          items:
            $ref: "#/components/schemas/BodyCompositionDto"
        hasMore:
          type: boolean
          description: True when more results exist beyond this page.
        nextCursor:
          type: string
          description: Opaque cursor for the next page; pass as `cursor`. Null on
            the last page.
    V1PageDailyMetricDto:
      type: object
      description: "Keyset-paginated list envelope, newest first. To page, pass `nextCursor`\
        \ back as the `cursor` query parameter until `hasMore` is false."
      properties:
        data:
          type: array
          description: "The results for this page, newest first."
          items:
            $ref: "#/components/schemas/DailyMetricDto"
        hasMore:
          type: boolean
          description: True when more results exist beyond this page.
        nextCursor:
          type: string
          description: Opaque cursor for the next page; pass as `cursor`. Null on
            the last page.
    V1PageDexaSummary:
      type: object
      description: "Keyset-paginated list envelope, newest first. To page, pass `nextCursor`\
        \ back as the `cursor` query parameter until `hasMore` is false."
      properties:
        data:
          type: array
          description: "The results for this page, newest first."
          items:
            $ref: "#/components/schemas/DexaSummary"
        hasMore:
          type: boolean
          description: True when more results exist beyond this page.
        nextCursor:
          type: string
          description: Opaque cursor for the next page; pass as `cursor`. Null on
            the last page.
    V1PageEntryDto:
      type: object
      description: "Keyset-paginated list envelope, newest first. To page, pass `nextCursor`\
        \ back as the `cursor` query parameter until `hasMore` is false."
      properties:
        data:
          type: array
          description: "The results for this page, newest first."
          items:
            $ref: "#/components/schemas/EntryDto"
        hasMore:
          type: boolean
          description: True when more results exist beyond this page.
        nextCursor:
          type: string
          description: Opaque cursor for the next page; pass as `cursor`. Null on
            the last page.
    V1PageMedicationDto:
      type: object
      description: "Keyset-paginated list envelope, newest first. To page, pass `nextCursor`\
        \ back as the `cursor` query parameter until `hasMore` is false."
      properties:
        data:
          type: array
          description: "The results for this page, newest first."
          items:
            $ref: "#/components/schemas/MedicationDto"
        hasMore:
          type: boolean
          description: True when more results exist beyond this page.
        nextCursor:
          type: string
          description: Opaque cursor for the next page; pass as `cursor`. Null on
            the last page.
    V1PageProgramSummary:
      type: object
      description: "Keyset-paginated list envelope, newest first. To page, pass `nextCursor`\
        \ back as the `cursor` query parameter until `hasMore` is false."
      properties:
        data:
          type: array
          description: "The results for this page, newest first."
          items:
            $ref: "#/components/schemas/ProgramSummary"
        hasMore:
          type: boolean
          description: True when more results exist beyond this page.
        nextCursor:
          type: string
          description: Opaque cursor for the next page; pass as `cursor`. Null on
            the last page.
    V1PageWorkoutSummary:
      type: object
      description: "Keyset-paginated list envelope, newest first. To page, pass `nextCursor`\
        \ back as the `cursor` query parameter until `hasMore` is false."
      properties:
        data:
          type: array
          description: "The results for this page, newest first."
          items:
            $ref: "#/components/schemas/WorkoutSummary"
        hasMore:
          type: boolean
          description: True when more results exist beyond this page.
        nextCursor:
          type: string
          description: Opaque cursor for the next page; pass as `cursor`. Null on
            the last page.
    WorkoutDetail:
      type: object
      properties:
        completedAt:
          type: string
          format: date-time
        date:
          type: string
          format: date
        dayId:
          type: string
        dayLabel:
          type: string
        durationSeconds:
          type: integer
          format: int32
        exercises:
          type: array
          items:
            $ref: "#/components/schemas/LoggedExercise"
        isDeload:
          type: boolean
        phaseId:
          type: string
        programId:
          type: string
        scheduledId:
          type: string
        status:
          type: string
        weekIndexInPhase:
          type: integer
          format: int32
    WorkoutSummary:
      type: object
      properties:
        completedAt:
          type: string
          format: date-time
        date:
          type: string
          format: date
        dayId:
          type: string
        dayLabel:
          type: string
        durationSeconds:
          type: integer
          format: int32
        isDeload:
          type: boolean
        phaseId:
          type: string
        programId:
          type: string
        scheduledId:
          type: string
        status:
          type: string
        weekIndexInPhase:
          type: integer
          format: int32
  securitySchemes:
    tesseta-oauth:
      description: Authorization Code + PKCE. Access tokens are RS256 JWTs; validate
        against /oauth/jwks.json. Discover endpoints at /.well-known/oauth-authorization-server.
      flows:
        authorizationCode:
          authorizationUrl: /oauth/authorize
          refreshUrl: /oauth/token
          scopes:
            labs:read: "Your blood readings, DEXA scans, body composition, and daily\
              \ health metrics"
            medications:read: "Your medications, schedules, doses, and adherence"
            nutrition:read: "Your food log, macros, and daily nutrition totals"
            offline_access: Keep monitoring your data in the background when you're
              not using the app
            profile:read: Your name and height
            workouts:read: "Your training programs, scheduled and completed workouts,\
              \ and logged sets"
          tokenUrl: /oauth/token
      type: oauth2
