openapi: 3.1.0
info:
  title: Kamee Partner API
  version: "1.0.0"
  description: |
    Read-only JSON feed of Kamee's published training plans.

    Access is by arrangement; contact PLACEHOLDER_CONTACT for an API key.
  contact:
    name: Kamee Partners
    email: PLACEHOLDER_CONTACT
servers:
  - url: https://kamee.fit
paths:
  /api/plans:
    get:
      summary: List published training plans
      description: |
        Returns every published, approved training plan, sorted by discipline
        ascending then title ascending. There is no pagination.
      operationId: listPlans
      security:
        - ApiKeyAuth: []
      parameters:
        - name: discipline
          in: query
          required: false
          description: Filter the catalog. Any other value returns 400.
          schema:
            $ref: "#/components/schemas/Discipline"
      responses:
        "200":
          description: The published plan catalog.
          headers:
            Cache-Control:
              schema:
                type: string
              example: public, max-age=300
            Vary:
              schema:
                type: string
              example: X-Api-Key
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlansResponse"
        "400":
          description: Invalid discipline value.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "401":
          description: Missing or wrong API key.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "500":
          description: Server error.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-Api-Key
  schemas:
    Discipline:
      type: string
      enum: [strength, running]
    Level:
      type: string
      enum: [none, beginner, intermediate, advanced]
    Error:
      type: object
      required: [error]
      properties:
        error:
          type: string
    PlansResponse:
      type: object
      required: [generatedAt, plans]
      properties:
        generatedAt:
          type: string
          format: date-time
          description: >
            Stamped when the origin built the response, not when it was
            delivered. A cached copy can be roughly 25 hours older than delivery.
        plans:
          type: array
          items:
            $ref: "#/components/schemas/Plan"
    Plan:
      type: object
      required:
        - id
        - title
        - summary
        - coverUrl
        - level
        - discipline
        - disciplineLabel
        - weeksCount
        - daysPerWeek
        - estMinutesPerSession
        - webUrl
        - appUrl
      properties:
        id:
          type: string
          format: uuid
        title:
          type: string
        summary:
          type: [string, "null"]
        coverUrl:
          type: [string, "null"]
          format: uri
        level:
          $ref: "#/components/schemas/Level"
        discipline:
          $ref: "#/components/schemas/Discipline"
        disciplineLabel:
          type: string
          description: Display name. "Workouts" for strength, "Outdoor" for running.
          enum: [Workouts, Outdoor]
        weeksCount:
          type: integer
        daysPerWeek:
          type: [integer, "null"]
        estMinutesPerSession:
          type: [integer, "null"]
        webUrl:
          type: string
          format: uri
        appUrl:
          type: string
          description: Deep link into the Kamee mobile app.
