SparkyFitness Exercise Stats API

The Exercise Stats API from SparkyFitness — 4 operation(s) for exercise stats.

Operations 4

GET /exercise-stats/summary Get multi-interval exercise totals, trends, and period-over-period comparison
POST /exercise-stats/query Interrogate and filter activities (e.g. query all Half Marathons by distance/pace/date)
GET /exercise-stats/prs Get personal records (PRs) matrix across distance milestones and 1RMs
GET /exercise-stats/matched-courses Get grouped matched courses and repeated loop activities

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/sparkyfitness-exercise-stats-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no email required.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

sparkyfitness-exercise-stats-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: SparkyFitness Exercise Stats API
  version: 1.0.0
  description: API documentation for the SparkyFitness application, providing a comprehensive guide to all available endpoints. Have caution using the API directly, as improper use may lead to data loss or corruption.  Also note that the API is subject to change without notice due to heavy development, so always refer to the latest documentation for up-to-date information. It might have flaw and due to vite/nginx internal proxy actual end point accessed via front end URL might be different than hitting them directly on the server.
  contact:
    name: SparkyFitness Support
servers:
- url: https://{host}/api
  description: Self-hosted SparkyFitness instance (the operator supplies the host). The upstream spec declares the relative base "/api".
  variables:
    host:
      default: sparkyfitness.example.com
      description: Hostname of your own SparkyFitness deployment. SparkyFitness is self-hosted; there is no vendor-operated API host.
security:
- apiKeyAuth: []
tags:
- name: Exercise Stats
paths:
  /exercise-stats/summary:
    get:
      summary: Get multi-interval exercise totals, trends, and period-over-period comparison
      tags:
      - Exercise Stats
      security:
      - apiKeyAuth: []
  /exercise-stats/query:
    post:
      summary: Interrogate and filter activities (e.g. query all Half Marathons by distance/pace/date)
      tags:
      - Exercise Stats
      security:
      - apiKeyAuth: []
  /exercise-stats/prs:
    get:
      summary: Get personal records (PRs) matrix across distance milestones and 1RMs
      description: 'Returns one cardio record per (sportGroup, distance standard) pair. sportGroup is the record boundary, so a hike and a walk compete for the same walk record, while sport describes the winning activity itself. Records are only comparable within a sportGroup — a 1 km walk is slower than a 1 mile run — so group by sportGroup rather than render a flat list.

        '
      tags:
      - Exercise Stats
      security:
      - apiKeyAuth: []
      parameters:
      - in: query
        name: userId
        schema:
          type: string
          format: uuid
        description: Target user; defaults to the authenticated user. Requires reports permission for anyone else.
      - in: query
        name: unitSystem
        schema:
          type: string
          enum:
          - metric
          - imperial
          default: metric
        description: Controls distance and pace formatting in the response.
      responses:
        '200':
          description: Personal records matrix.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExercisePRMatrixResponse'
        '400':
          description: Target User ID is required, or unitSystem is not metric/imperial.
        '403':
          description: Forbidden — no reports permission for the requested user.
  /exercise-stats/matched-courses:
    get:
      summary: Get grouped matched courses and repeated loop activities
      tags:
      - Exercise Stats
      security:
      - apiKeyAuth: []
      parameters:
      - in: query
        name: userId
        schema:
          type: string
          format: uuid
        description: Target user; defaults to the authenticated user. Requires reports permission for anyone else.
      - in: query
        name: unitSystem
        schema:
          type: string
          enum:
          - metric
          - imperial
          default: metric
        description: Controls distance and pace formatting in the response.
      responses:
        '200':
          description: Repeated courses with their recent activities.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MatchedCoursesResponse'
        '400':
          description: Target User ID is required, or unitSystem is not metric/imperial.
        '403':
          description: Forbidden — no reports permission for the requested user.
components:
  schemas:
    ExercisePRMatrixResponse:
      type: object
      properties:
        cardioPRs:
          type: array
          description: One entry per (sportGroup, distance standard) pair, ordered by sport group then distance.
          items:
            $ref: '#/components/schemas/ExercisePersonalRecordItem'
        strength1RMs:
          type: array
          items:
            type: object
            properties:
              exerciseName:
                type: string
              estimatedOneRMKg:
                type: number
              weightKg:
                type: number
              reps:
                type: number
              achievedAt:
                type: string
    ExercisePersonalRecordItem:
      type: object
      description: One best effort. sportGroup is the record boundary — efforts compete only within the same group, so a hike and a walk contend for the same walk record — while sport classifies the winning activity itself.
      properties:
        id:
          type: string
          description: Stable id in the form pr-<sportGroup>-<standard>.
        category:
          type: string
          description: Legacy alias of sport, retained for older clients.
        sport:
          type: string
          enum:
          - running
          - cycling
          - walking
          - hiking
          - swimming
          - rowing
          - fitness_equipment
          - strength
          - other
          description: Canonical sport of the winning activity, named after the ANT+/FIT SDK sport enum. Descriptive only — it does not define which efforts competed for this record. Absent on servers predating per-sport records.
        sportGroup:
          type: string
          enum:
          - run
          - ride
          - walk
          - swim
          - other
          description: 'The record boundary: one record is kept per (sportGroup, distanceStandard) pair, and hiking folds into walk. Group by this field to render the matrix.'
        sportConfidence:
          type: string
          enum:
          - declared
          - inferred
          description: declared when the sport came from the provider's own enum, inferred when it was derived from notes or the activity name.
        distanceStandard:
          type: string
          enum:
          - 1k
          - 1mi
          - 5k
          - 10k
          - 15k
          - half_marathon
          - marathon
          - custom
          description: Milestone distance band this record belongs to.
        label:
          type: string
          description: Display label, e.g. "Half Marathon (21.1 km)".
        bestTimeSeconds:
          type: number
        formattedTime:
          type: string
          description: e.g. "1:42:15".
        avgPaceSecondsPerKm:
          type: number
        formattedPace:
          type: string
          description: e.g. "4:50 /km" or "7:47 /mi".
        activityId:
          type: string
        activityName:
          type: string
        achievedAt:
          type: string
          description: Calendar day the record was set (YYYY-MM-DD).
    MatchedCourseGroup:
      type: object
      description: A repeated route, grouped by activity name, with its recent runs of that course.
      properties:
        courseId:
          type: string
        courseName:
          type: string
        category:
          type: string
          description: Raw entry category as stored.
        sport:
          type: string
          enum:
          - running
          - cycling
          - walking
          - hiking
          - swimming
          - rowing
          - fitness_equipment
          - strength
          - other
          description: Sport derived from the course name and category. Absent on servers predating per-sport records.
        totalDistanceMeters:
          type: number
        avgDistanceFormatted:
          type: number
        activityCount:
          type: number
        bestTimeSeconds:
          type: number
        bestPaceFormatted:
          type: string
        recentActivities:
          type: array
          items:
            type: object
            properties:
              activityId:
                type: string
              activityName:
                type: string
              entryDate:
                type: string
              durationMinutes:
                type: number
              avgPaceFormatted:
                type: string
              avgHeartRate:
                type:
                - number
                - 'null'
    MatchedCoursesResponse:
      type: object
      properties:
        courses:
          type: array
          items:
            $ref: '#/components/schemas/MatchedCourseGroup'
  securitySchemes:
    apiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: API key authentication via x-api-key header.
x-provenance:
  generated: '2026-08-27'
  method: derived
  source: https://github.com/CodeWithCJ/SparkyFitness — assembled from the project's own swagger-jsdoc configuration (SparkyFitnessServer/config/swagger.ts) and the 419 @swagger JSDoc blocks in SparkyFitnessServer/routes/**, using the same scan paths and the same cookieAuth->apiKeyAuth post-processing the server applies. This is the identical document a running instance serves at GET /api/api-docs/json (Swagger UI at /api/api-docs/swagger, ReDoc at /api/api-docs/redoc).
  note: 'Not fetched from a live host: SparkyFitness is self-hosted and the project operates no public instance, so the contract can only be read from the source that generates it. Upstream sets no operationIds; paths+methods are the stable identifiers.'
  upstream_version: server package.json 1.6.4 (release v1.6.4, 2026-08-27)