API reference
Everything is a GET over JSON — keyless to try, CORS-enabled, CDN-cached. Prefer machine contracts? Use /openapi.json (rendered at /docs/api) or /llms.txt for agents.
Endpoints
| Endpoint | Purpose |
|---|---|
| GET /v1/exercises | List & filter the catalog. All filters below; sort + pagination. |
| GET /v1/exercises/{id} | One exercise by stable slug. |
| GET /v1/meta | Vocabularies with counts, dataset_version, license + attribution. |
| GET /health | Liveness + dataset size. |
| GET /openapi.json | OpenAPI 3.1 spec — the canonical machine contract. |
| GET /llms.txt | Concise API map for doc-reading agents (llms-full.txt = everything). |
| POST /v1/suggestions | Suggest a missing exercise / correction — filed to the public issue tracker for review. 5/day per IP. |
First request — your first 100 calls each day are free, no key needed:
curl "https://exercise-api.com/v1/exercises?muscle=chest&sfr_class=high"Parameters — GET /v1/exercises
Distinct filters AND together; comma-separated values within one filter OR together. Invalid values return a 400 that lists the valid ones.
| Param | Values | Meaning |
|---|---|---|
| muscle | enum (16 muscles) | Primary muscle. Comma-separated = any-of. |
| secondary_muscle | same vocabulary | Meaningful secondary involvement. |
| pattern | enum (20 patterns) | Movement pattern. |
| sfr_class | high · moderate · low | Stimulus-to-fatigue class. |
| tier | core · extended | Catalog tier. |
| modality | hypertrophy · conditioning · calisthenics · mobility | Training purpose. |
| substitution_group | see /v1/meta | e1RM substitution group. |
| progression_group | see /v1/meta | Calisthenics progression chain. |
| equipment | equipment tokens | Exercises that require this token. |
| available_equipment | equipment tokens | Subset match: only exercises whose entire equipment list is covered by your tokens. none_bodyweight (your body) is always implied. |
| gold_standard · loadable · unilateral · home_hotel_friendly | true · false | Boolean filters. |
| q | free text | Case-insensitive substring search over name and id. |
| sort | name · -name · preferred_rank · -preferred_rank · id · -id | Stable sort with id tiebreak — pagination-safe. |
| limit | 1–200 (default 20) | Page size. limit=200 fits the whole catalog in one page. |
| offset | ≥ 0 | Zero-based offset into the filtered set. |
Field dictionary
20 fields, all always present — nullable fields use null, never omission. This table is generated from the same schema module the API runs on.
| Field | Type | Meaning |
|---|---|---|
| id | string | Stable, URL-safe snake_case slug, unique across the catalog (e.g. `barbell_bench_press`). Never reused or renamed — safe to store as a foreign reference. |
| name | string | Human-readable display name. |
| primary_muscle | enum | The muscle the exercise primarily targets. |
| secondary_muscles | enum[] | Muscles meaningfully worked besides the primary. Same vocabulary as `primary_muscle`. May be empty. |
| pattern | enum | Movement pattern classification. |
| equipment | enum[] | Every equipment token required to perform the exercise. `none_bodyweight` means no equipment is needed. |
| sfr_class | enum | null | Stimulus-to-fatigue ratio class: how much hypertrophy stimulus the exercise delivers per unit of fatigue. `high` is best. Null for non-hypertrophy modalities. |
| is_gold_standard | boolean | True when the exercise is a research/EMG-backed top pick for its primary muscle (see data/SOURCE.md for citations). |
| preferred_rank | integer | null | 1-based preference order among exercises sharing a primary muscle — lower is more preferred by the curators. Null for non-hypertrophy modalities. |
| e1rm_substitution_group | string | null | Named group of interchangeable exercises for estimated-1RM tracking: swapping within a group preserves comparable strength-progression data. Null when e1RM tracking doesn't apply. |
| default_rep_low | integer | null | Lower bound of the curated default hypertrophy rep range. Null for time- or hold-based work. |
| default_rep_high | integer | null | Upper bound of the curated default hypertrophy rep range. Null for time- or hold-based work. |
| loadable | boolean | True when the exercise can be progressively loaded with external weight. |
| unilateral | boolean | True when the exercise trains one side at a time. |
| home_hotel_friendly | boolean | True when the exercise is practical with minimal/portable equipment (hotel room, home setup). |
| tier | enum | `core` = the curated default library; `extended` = additive variations and calisthenics progression rungs. |
| modality | enum | Primary training purpose. Current catalog: `hypertrophy` and `calisthenics` (skill-progression work); `conditioning` and `mobility` are reserved for upcoming dataset releases. Overlaps (e.g. weighted dips) are classified by primary purpose — use pattern/equipment/progression fields for finer slicing. |
| progression_group | string | null | Named calisthenics progression chain this exercise belongs to (e.g. `planche_push_line`), or null for non-progression exercises. |
| progression_level | integer | null | 1-based difficulty rung within `progression_group` (higher = harder), or null. |
| cues | string | Short coaching cues for correct execution. |
Vocabularies
Live from the dataset (counts = records using each value). Also served as JSON at /v1/meta. New values may be added within /v1; values are never removed or renamed.
Conventions
Lists use a Stripe-style envelope; errors carry a stable machine-readable code: invalid_parameter (400), not_found (404), rate_limited (429), internal_error (500).
{
"object": "list",
"data": [
"…exercise records…"
],
"count": 20,
"total": 47,
"limit": 20,
"offset": 0
}{
"error": {
"code": "not_found",
"message": "No exercise with id …"
}
}Rate limits
Anonymous use is free: 100 requests per day per IP, plus a per-minute burst limit. /v1 responses carry RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset; exceeding a limit returns 429 with the error envelope and Retry-After. Since catalog responses are CDN-cached, cache hits are cheap — but still budget your calls: fetch limit=200 once and work locally, or pin a snapshot release for bulk use. A free API key tier with higher limits is planned.
Versioning
Two independent axes. API contract: versioned in the path (/v1), additive-only — fields and enum values are added, never removed, renamed, or retyped; breaking changes would ship as /v2 with a 12-month /v1 sunset window. Dataset content: semver (currently v1.1.0), exposed in /v1/meta and the X-Dataset-Version header on every response. MINOR = exercises/fields added, PATCH = corrections. Immutable snapshots of each dataset release are published on GitHub for consumers who need reproducible builds.
License & attribution
The data is CC BY 4.0 — free to use, including commercially, but products using it must credit ExerciseAPI. A ready-to-use credit line is served in /v1/meta (license.attribution):
Exercise data by ExerciseAPI (https://exercise-api.com), licensed under CC BY 4.0.