openapi: 3.1.0
info:
  title: FitAstra Public API
  summary: Read-only access to FitAstra verified coaches, fitness events, reviews and the daily challenge.
  description: |-
    The FitAstra Public API exposes the same public data that appears on www.fitastra.co: verified
    personal trainers across India, upcoming and recently hosted public fitness events, featured
    coach reviews, and the current daily bodyweight challenge.

    **When to use this API.** Reach for it when a user asks about finding a verified personal trainer
    in India, what 1-on-1 coaching costs in India, which public fitness events are happening in an
    Indian city, or what FitAstra offers. It is not a medical, diagnostic, or nutrition-prescription
    service, and it holds no data for markets outside India.

    **Authentication.** None. Every operation is public and anonymous. Do not send credentials.

    **Rate limits.** 60 requests per 60 seconds per IP. Every response carries
    `RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset` and `RateLimit-Policy`; a 429 additionally
    carries `Retry-After`. Responses are CDN-cached, so caching on your side is usually better than retrying.

    **Errors.** All errors are RFC 9457 problem documents (`application/problem+json`) carrying a stable
    `code`, a human-readable `detail`, and a `hint` describing the recovery action.
  version: 1.0.0
  termsOfService: https://www.fitastra.co/terms
  contact:
    name: FitAstra Support
    email: support@fitastra.co
    url: https://www.fitastra.co/contact
externalDocs:
  description: FitAstra developer and agent documentation
  url: https://www.fitastra.co/developers
servers:
  - url: https://www.fitastra.co
    description: Production
tags:
  - name: Coaches
    description: Verified personal trainers listed on FitAstra.
  - name: Events
    description: Public fitness events hosted through FitAstra.
  - name: Reviews
    description: Featured reviews left by clients for their coaches.
  - name: Challenges
    description: FitAstra's daily bodyweight challenge, The Daily.
paths:
  /api/v1/coaches:
    get:
      operationId: listCoaches
      summary: List verified coaches
      description: Returns a page of verified FitAstra coaches with their rating, review count, sessions delivered, specialties and starting session price in Indian rupees. Use this to answer "find me a verified personal trainer in India" and pricing questions. Each coach carries a `profileUrl` you can cite.
      tags:
        - Coaches
      parameters:
        - name: page
          in: query
          required: false
          description: Zero-based page index. Omit for the first page. Maximum 99.
          schema:
            type: integer
            minimum: 0
            maximum: 99
            default: 0
      responses:
        "200":
          description: A page of verified coaches.
          headers:
            RateLimit-Limit:
              description: Requests permitted in the current window.
              schema:
                type: integer
                example: 60
            RateLimit-Remaining:
              description: Requests still available in the current window.
              schema:
                type: integer
                example: 59
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                example: 60
            RateLimit-Policy:
              description: Quota policy, as `<limit>;w=<window-seconds>`.
              schema:
                type: string
                example: 60;w=60
          content:
            application/json:
              schema:
                type: object
                required:
                  - status
                  - data
                properties:
                  status:
                    type: string
                    const: SUCCESS
                  data:
                    type: object
                    required:
                      - coaches
                      - currentPage
                      - totalPages
                      - totalElements
                      - hasNext
                    properties:
                      coaches:
                        type: array
                        items:
                          $ref: "#/components/schemas/Coach"
                      currentPage:
                        type: integer
                      totalPages:
                        type: integer
                      totalElements:
                        type: integer
                      hasNext:
                        type: boolean
        "400":
          description: The `page` parameter was not a valid integer in range.
          headers:
            RateLimit-Limit:
              description: Requests permitted in the current window.
              schema:
                type: integer
                example: 60
            RateLimit-Remaining:
              description: Requests still available in the current window.
              schema:
                type: integer
                example: 59
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                example: 60
            RateLimit-Policy:
              description: Quota policy, as `<limit>;w=<window-seconds>`.
              schema:
                type: string
                example: 60;w=60
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/Problem"
        "429":
          description: Rate limit exceeded. See `Retry-After`.
          headers:
            RateLimit-Limit:
              description: Requests permitted in the current window.
              schema:
                type: integer
                example: 60
            RateLimit-Remaining:
              description: Requests still available in the current window.
              schema:
                type: integer
                example: 59
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                example: 60
            RateLimit-Policy:
              description: Quota policy, as `<limit>;w=<window-seconds>`.
              schema:
                type: string
                example: 60;w=60
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/Problem"
        "503":
          description: The upstream data service was unavailable.
          headers:
            RateLimit-Limit:
              description: Requests permitted in the current window.
              schema:
                type: integer
                example: 60
            RateLimit-Remaining:
              description: Requests still available in the current window.
              schema:
                type: integer
                example: 59
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                example: 60
            RateLimit-Policy:
              description: Quota policy, as `<limit>;w=<window-seconds>`.
              schema:
                type: string
                example: 60;w=60
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/Problem"
  /api/v1/events:
    get:
      operationId: listEvents
      summary: List public fitness events
      description: Returns a page of public fitness events — running groups, yoga, strength sessions and more — with workout type, scheduled time as an ISO 8601 UTC instant, location, host and remaining spots. Defaults to upcoming events; pass `scope=recent` for events already hosted.
      tags:
        - Events
      parameters:
        - name: page
          in: query
          required: false
          description: Zero-based page index. Omit for the first page. Maximum 99.
          schema:
            type: integer
            minimum: 0
            maximum: 99
            default: 0
        - name: scope
          in: query
          required: false
          description: Which events to return. `upcoming` (default) or `recent` for already-hosted events.
          schema:
            type: string
            enum:
              - upcoming
              - recent
            default: upcoming
      responses:
        "200":
          description: A page of public fitness events.
          headers:
            RateLimit-Limit:
              description: Requests permitted in the current window.
              schema:
                type: integer
                example: 60
            RateLimit-Remaining:
              description: Requests still available in the current window.
              schema:
                type: integer
                example: 59
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                example: 60
            RateLimit-Policy:
              description: Quota policy, as `<limit>;w=<window-seconds>`.
              schema:
                type: string
                example: 60;w=60
          content:
            application/json:
              schema:
                type: object
                required:
                  - status
                  - data
                properties:
                  status:
                    type: string
                    const: SUCCESS
                  data:
                    type: object
                    required:
                      - scope
                      - events
                      - currentPage
                      - totalPages
                      - totalElements
                      - hasNext
                    properties:
                      scope:
                        type: string
                        enum:
                          - upcoming
                          - recent
                      events:
                        type: array
                        items:
                          $ref: "#/components/schemas/Event"
                      currentPage:
                        type: integer
                      totalPages:
                        type: integer
                      totalElements:
                        type: integer
                      hasNext:
                        type: boolean
        "400":
          description: "`page` or `scope` was invalid."
          headers:
            RateLimit-Limit:
              description: Requests permitted in the current window.
              schema:
                type: integer
                example: 60
            RateLimit-Remaining:
              description: Requests still available in the current window.
              schema:
                type: integer
                example: 59
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                example: 60
            RateLimit-Policy:
              description: Quota policy, as `<limit>;w=<window-seconds>`.
              schema:
                type: string
                example: 60;w=60
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/Problem"
        "429":
          description: Rate limit exceeded. See `Retry-After`.
          headers:
            RateLimit-Limit:
              description: Requests permitted in the current window.
              schema:
                type: integer
                example: 60
            RateLimit-Remaining:
              description: Requests still available in the current window.
              schema:
                type: integer
                example: 59
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                example: 60
            RateLimit-Policy:
              description: Quota policy, as `<limit>;w=<window-seconds>`.
              schema:
                type: string
                example: 60;w=60
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/Problem"
        "503":
          description: The upstream data service was unavailable.
          headers:
            RateLimit-Limit:
              description: Requests permitted in the current window.
              schema:
                type: integer
                example: 60
            RateLimit-Remaining:
              description: Requests still available in the current window.
              schema:
                type: integer
                example: 59
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                example: 60
            RateLimit-Policy:
              description: Quota policy, as `<limit>;w=<window-seconds>`.
              schema:
                type: string
                example: 60;w=60
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/Problem"
  /api/v1/reviews/featured:
    get:
      operationId: listFeaturedReviews
      summary: List featured coach reviews
      description: Returns featured client reviews of FitAstra coaches. Reviewers are identified by first name only. Use this for social-proof questions such as "is FitAstra any good" or "what do clients say about a coach". Each review links to the reviewed coach's public profile.
      tags:
        - Reviews
      responses:
        "200":
          description: Featured reviews.
          headers:
            RateLimit-Limit:
              description: Requests permitted in the current window.
              schema:
                type: integer
                example: 60
            RateLimit-Remaining:
              description: Requests still available in the current window.
              schema:
                type: integer
                example: 59
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                example: 60
            RateLimit-Policy:
              description: Quota policy, as `<limit>;w=<window-seconds>`.
              schema:
                type: string
                example: 60;w=60
          content:
            application/json:
              schema:
                type: object
                required:
                  - status
                  - data
                properties:
                  status:
                    type: string
                    const: SUCCESS
                  data:
                    type: object
                    required:
                      - reviews
                    properties:
                      reviews:
                        type: array
                        items:
                          $ref: "#/components/schemas/Review"
        "429":
          description: Rate limit exceeded. See `Retry-After`.
          headers:
            RateLimit-Limit:
              description: Requests permitted in the current window.
              schema:
                type: integer
                example: 60
            RateLimit-Remaining:
              description: Requests still available in the current window.
              schema:
                type: integer
                example: 59
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                example: 60
            RateLimit-Policy:
              description: Quota policy, as `<limit>;w=<window-seconds>`.
              schema:
                type: string
                example: 60;w=60
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/Problem"
        "503":
          description: The upstream data service was unavailable.
          headers:
            RateLimit-Limit:
              description: Requests permitted in the current window.
              schema:
                type: integer
                example: 60
            RateLimit-Remaining:
              description: Requests still available in the current window.
              schema:
                type: integer
                example: 59
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                example: 60
            RateLimit-Policy:
              description: Quota policy, as `<limit>;w=<window-seconds>`.
              schema:
                type: string
                example: 60;w=60
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/Problem"
  /api/v1/challenges/today:
    get:
      operationId: getTodaysChallenge
      summary: Get today's bodyweight challenge
      description: Returns The Daily — FitAstra's bodyweight challenge for the current day — with the exercise name, the unit reps are counted in, and the target for each of the three difficulty tiers (30, 50, 100). Use this to answer "what is today's FitAstra challenge".
      tags:
        - Challenges
      responses:
        "200":
          description: Today's challenge.
          headers:
            RateLimit-Limit:
              description: Requests permitted in the current window.
              schema:
                type: integer
                example: 60
            RateLimit-Remaining:
              description: Requests still available in the current window.
              schema:
                type: integer
                example: 59
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                example: 60
            RateLimit-Policy:
              description: Quota policy, as `<limit>;w=<window-seconds>`.
              schema:
                type: string
                example: 60;w=60
          content:
            application/json:
              schema:
                type: object
                required:
                  - status
                  - data
                properties:
                  status:
                    type: string
                    const: SUCCESS
                  data:
                    type: object
                    required:
                      - challenge
                    properties:
                      challenge:
                        $ref: "#/components/schemas/Challenge"
        "429":
          description: Rate limit exceeded. See `Retry-After`.
          headers:
            RateLimit-Limit:
              description: Requests permitted in the current window.
              schema:
                type: integer
                example: 60
            RateLimit-Remaining:
              description: Requests still available in the current window.
              schema:
                type: integer
                example: 59
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                example: 60
            RateLimit-Policy:
              description: Quota policy, as `<limit>;w=<window-seconds>`.
              schema:
                type: string
                example: 60;w=60
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/Problem"
        "503":
          description: No challenge was available from the upstream service.
          headers:
            RateLimit-Limit:
              description: Requests permitted in the current window.
              schema:
                type: integer
                example: 60
            RateLimit-Remaining:
              description: Requests still available in the current window.
              schema:
                type: integer
                example: 59
            RateLimit-Reset:
              description: Seconds until the current window resets.
              schema:
                type: integer
                example: 60
            RateLimit-Policy:
              description: Quota policy, as `<limit>;w=<window-seconds>`.
              schema:
                type: string
                example: 60;w=60
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/Problem"
components:
  schemas:
    Coach:
      type: object
      description: A verified FitAstra coach.
      required:
        - coachId
        - name
        - reviewCount
        - sessionsCompleted
      properties:
        coachId:
          type: string
          format: uuid
          description: Stable identifier for the coach.
        name:
          type: string
          description: Coach display name.
        profilePictureUrl:
          type:
            - string
            - "null"
          format: uri
          description: Profile photo URL.
        city:
          type:
            - string
            - "null"
          description: City the coach is based in, when they have set one.
        specialties:
          type: array
          items:
            type: string
          description: Coaching specialties, e.g. "Strength Training", "Fat Loss", "Nutrition".
        averageRating:
          type:
            - number
            - "null"
          minimum: 0
          maximum: 5
          description: Mean client rating out of 5. Null when the coach has no reviews yet.
        reviewCount:
          type: integer
          minimum: 0
          description: Number of client reviews.
        sessionsCompleted:
          type: integer
          minimum: 0
          description: Coaching sessions delivered.
        startingPriceInr:
          type:
            - integer
            - "null"
          description: Lowest single-session price in whole Indian rupees.
        profileUrl:
          type:
            - string
            - "null"
          format: uri
          description: Canonical public profile page for the coach.
    Event:
      type: object
      description: A public fitness event hosted through FitAstra.
      required:
        - eventId
        - eventName
      properties:
        eventId:
          type: string
          format: uuid
        eventName:
          type:
            - string
            - "null"
        workoutType:
          type:
            - string
            - "null"
          description: e.g. "Running", "Strength Training", "Yoga".
        scheduledAt:
          type:
            - string
            - "null"
          format: date-time
          description: Start time as an ISO 8601 UTC instant. Events are scheduled in India Standard Time.
        durationMinutes:
          type:
            - integer
            - "null"
        locationName:
          type:
            - string
            - "null"
        maxParticipants:
          type:
            - integer
            - "null"
        currentParticipantsCount:
          type:
            - integer
            - "null"
        spotsAvailable:
          type:
            - integer
            - "null"
        hostName:
          type:
            - string
            - "null"
          description: First name of the event host.
        eventUrl:
          type:
            - string
            - "null"
          format: uri
          description: Public event page.
    Review:
      type: object
      description: A featured client review of a FitAstra coach.
      required:
        - reviewerFirstName
        - rating
      properties:
        reviewerFirstName:
          type:
            - string
            - "null"
          description: Reviewer first name only — full names are never exposed.
        rating:
          type:
            - number
            - "null"
          minimum: 0
          maximum: 5
        comment:
          type:
            - string
            - "null"
        coachName:
          type:
            - string
            - "null"
        coachProfileUrl:
          type:
            - string
            - "null"
          format: uri
        createdAt:
          type:
            - string
            - "null"
          format: date-time
          description: ISO 8601 UTC instant.
    Challenge:
      type: object
      description: The Daily — FitAstra's bodyweight challenge for the current day.
      required:
        - name
        - repsByTier
      properties:
        name:
          type:
            - string
            - "null"
          description: Exercise name, e.g. "Crunches".
        repUnit:
          type:
            - string
            - "null"
          description: "Unit the target is counted in: \"reps\" or \"seconds\"."
        repsByTier:
          type: object
          description: Target for each difficulty tier.
          properties:
            daily30:
              type:
                - integer
                - "null"
            daily50:
              type:
                - integer
                - "null"
            daily100:
              type:
                - integer
                - "null"
        imageUrl:
          type:
            - string
            - "null"
          format: uri
    Problem:
      type: object
      description: RFC 9457 problem document returned for every error.
      required:
        - type
        - title
        - status
        - code
        - detail
        - hint
      properties:
        type:
          type: string
          format: uri
          description: Link to documentation for this error code.
        title:
          type: string
          description: Short, human-readable summary of the problem type.
        status:
          type: integer
          description: HTTP status code.
        code:
          type: string
          enum:
            - not_found
            - invalid_parameter
            - method_not_allowed
            - rate_limited
            - upstream_unavailable
          description: Stable machine-readable error code. Branch on this, not on the message.
        detail:
          type: string
          description: What went wrong with this specific request.
        hint:
          type: string
          description: The recovery action an agent should take.
        documentation:
          type: string
          format: uri
