An exercise library your app can actually query
The Fitness API returns an exercise database as clean JSON.
8 active endpoints, on 0 and 1 credit tiers.
- POST/fitness/v1/exercises
- POST/fitness/v1/by_bodypart
- POST/fitness/v1/by_equipment
- POST/fitness/v1/by_target
- POST/fitness/v1/exercise_detail
- POST/fitness/v1/bodypart_list
- POST/fitness/v1/equipment_list
- +1 more
What Fitness & Nutrition endpoints does ReefAPI ship?
8 live read endpoints. Read-only data API: no writes, no account actions, no dashboard access on the target site.
Fitness & Nutrition API
3 of 8 endpoints, ready to run
Exercises matching a name, each with its body part, target muscle, secondary muscles, equipment, instructions and licence.
{ "ok": true, "meta": { "api": "fitness", "endpoint": "exercises", "mode": "live", "latency_ms": 2855.8, "record_count": 10, "cache_hit": false, "completeness_pct": 85 }, "data": { "results": [ { "id": "20", "name": "Arnold Shoulder Press", "bodyPart": "shoulders", "target": "Shoulders", "equipment": "Dumbbell", "secondaryMuscles": [ "Trapezius", "Triceps" ], "instructions": [ "Very common shoulder exercise.", "As shown here: https://www.youtube.com/watch?v=vj2w851ZHRM" ], "description": "Very common shoulder exercise. As shown here: https://www.youtube.com/watch?v=vj2w851ZHRM", "difficulty": null, "category": "Shoulders", "gifUrl": null, "imageUrl": null, "license": "CC-BY-SA 3", "licenseAuthor": "trzr23", "source": "wger.de" }, { "id": "73", "name": "Bench Press", "bodyPart": "chest", "target": "Chest", "equipment": "Barbell", "secondaryMuscles": [ "Shoulders", "Triceps" ], "instructions": [ "wide grip: outer chest muscles", "narrow grip: inner chest muscles and triceps" ], "description": "Lay down on a bench, the bar should be directly above your eyes, the knees are somewhat angled and the feet are firmly on the floor. Concentrate, breath deeply and grab the bar more than shoulder wide. Bring it slowly down till it briefly touches your chest at the height of your nipples. Push the bar up. If you train with a high weight it is advisable to have a spotter that can help you up if you can't lift the weight on your own. With the width of the grip you can also control which part of the chest is trained more: wide grip: outer chest muscles narrow grip: inner chest muscles and triceps", "difficulty": null, "category": "Chest", "gifUrl": "https://wger.de/media/exercise-images/192/Bench-press-1.png", "imageUrl": "https://wger.de/media/exercise-images/192/Bench-press-1.png", "license": "CC-BY-SA 3", "licenseAuthor": "sistab2", "source": "wger.de" }, { "id": "75", "name": "Benchpress Dumbbells", "bodyPart": "chest", "target": "Chest", "equipment": "Bench", "secondaryMuscles": [ "Shoulders", "Triceps" ], "instructions": [ "Setup and Starting Position: Sit at the end of a flat bench with a dumbbell resting vertically against each thigh. Carefully lean back while driving the dumbbells toward your chest with your knees.", "The “Leg Drive” and Posture: Plant your feet firmly on the floor. Retract your shoulder blades (press them together against the bench) and maintain a slight natural lumbar curve.", "Starting Position: Push the dumbbells toward the ceiling. Your wrists should be aligned with your elbows. Rotate the dumbbells slightly inward (about 45 degrees) so that your elbows do not splay out too far to the sides, thereby protecting your shoulders." ], "description": "Setup and Starting Position: Sit at the end of a flat bench with a dumbbell resting vertically against each thigh. Carefully lean back while driving the dumbbells toward your chest with your knees. The “Leg Drive” and Posture: Plant your feet firmly on the floor. Retract your shoulder blades (press them together against the bench) and maintain a slight natural lumbar curve. Starting Position: Push the dumbbells toward the ceiling. Your wrists should be aligned with your elbows. Rotate the dumbbells slightly inward (about 45 degrees) so that your elbows do not splay out too far to the sides, thereby protecting your shoulders. Eccentric Phase (Lowering): Lower the dumbbells in a controlled manner toward the sides of your chest. Your elbows should lower at an angle of about 45–60 degrees relative to your body. Feel the stretch in the lower part of your chest. Concentric Phase (Lift): Push the weight upward in a slight arc (toward the center), without letting the dumbbells collide at the top or fully locking out your elbows to maintain muscle tension. Exhale as you lift. Translated with DeepL.com (free version)", "difficulty": null, "category": "Chest", "gifUrl": "https://wger.de/media/exercise-images/97/Dumbbell-bench-press-1.png", "imageUrl": "https://wger.de/media/exercise-images/97/Dumbbell-bench-press-1.png", "license": "CC-BY-SA 3", "licenseAuthor": "wger.de", "source": "wger.de" } ], "count": 76, "next_offset": 10 } }
How the Fitness & Nutrition API works
Fitness & Nutrition is a normal ReefAPI surface — the same four rules that hold for every other engine on the key.
No OAuth app, no request signing, no per-site account. One key covers all 184 engines.
Every route is a POST with a JSON body. Parameters are validated against the published schema before anything is charged.
Credits, not seats. Failed and blocked calls are never charged, and cache hits cost nothing.
One envelope everywhere. meta carries latency_ms, record_count and the endpoint that answered.
Building a workout screen from a body part and a piece of equipment
The two questions a training app asks are 'what can I do for chest' and 'what can I do with only dumbbells'. Both are browse axes, not searches.
{"bodypart": "chest", "limit": 20}Returns exercises with the target muscle, the secondary muscles and the equipment on each row, so the filtering you do next needs no extra calls.
{"id": "1962"}For the one the user tapped. Instructions come back as an array of steps rather than a blob of markup.
Every record carries its licence and the name of the contributor, so an app can display the attribution the licence requires instead of quietly stripping it.
curl -X POST https://api.reefapi.com/fitness/v1/exercises \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{}'{
"ok": true,
"data": { … },
"meta": {
"api": "fitness",
"endpoint": "exercises",
"mode": "live",
"latency_ms": …,
"record_count": …
},
"error": null
}The three vocabularies, and the field shapes that catch people out
This is exercise reference data, not nutrition data. Three list actions hand you the exact strings the filters accept, and one of them contains two overlapping naming systems at once. Everything below was measured on live calls: target_list, equipment_list and bodypart_list in full, exercise_detail for id 1962, and by_bodypart, by_equipment and by_target sweeps in English and German.
| Vocabulary or field | Measured values | How to use it |
|---|---|---|
| target_list | 15 muscles: Abs, Biceps, Brachialis, Calves, Chest, Glutes, Hamstrings, Lats, Obliquus externus abdominis, Quads, Serratus anterior, Shoulders, Soleus, Trapezius, Triceps | These are wger's anatomical names, so pass 'Quads' rather than 'quadriceps', and expect Latin names like Obliquus externus abdominis. Matching is by substring and case-insensitive. |
| equipment_list | 12 entries: Barbell, Bench, Cable machine, Dumbbell, Gym mat, Incline bench, Kettlebell, Pull-up bar, Resistance band, SZ-Bar, Swiss Ball, none (bodyweight exercise) | SZ-Bar is the EZ-curl bar. Bodyweight exercises carry the literal string 'none (bodyweight exercise)', and passing equipment='none' matches them. |
| bodypart_list | 16 entries that are really two overlapping sets: capitalized categories (Abs, Arms, Back, Calves, Cardio, Chest, Legs, Shoulders) and lowercase legacy labels (back, cardio, chest, lower legs, shoulders, upper arms, upper legs, waist) | Both work. 'Legs' and 'upper legs' return the same records, and 'chest' and 'Chest' returned byte-identical responses. |
| category vs bodyPart | Every record carries both: category is the capitalized wger category ('Legs', 'Cardio'), bodyPart is the lowercase legacy label ('upper legs', 'cardio') | Group on category if you want eight clean buckets. bodyPart is finer but inconsistent. |
| id | A string, even though exercise_detail's id parameter is typed as an integer: '1962', '73', '12' | Cast before you compare. Ids are stable across languages: id 12 is 'Seated Hip Adduction' in English and 'Adduktoren-Maschine' in German. |
| count | Means different things per action | On the exercises action it is 861, the size of the whole library, regardless of how many rows you asked for. On by_bodypart, by_equipment and by_target it is the number of rows actually returned. |
| gifUrl / imageUrl | Identical values, and they point at static .png files rather than animations. Both are null on many records. | The number inside the URL path is not always the exercise id: 'Bench Press' is id 73 but its image sits under /exercise-images/192/. |
| empty vs null | difficulty was null on every record we read. target and equipment come back as empty strings, and secondaryMuscles as an empty array, when wger has nothing. | Check for '' as well as null before you branch. |
| language | An integer wger language id: 2 English (the default), 1 German, 4 Russian, 5 Spanish | It changes names and instructions, not ids, so you can build a multi-language catalog keyed on the same id. |
| license / licenseAuthor | Per record: 'CC-BY-SA 4', 'CC-BY-SA 3' or 'CC0', with a contributor handle such as 'nate303303' or 'sistab2' | meta.attribution reads 'Data © wger.de — CC-BY-SA 4.0'. Records differ, so carry the per-record license through if you republish. |
An unrecognized filter value is not rejected. by_bodypart with 'zzzz' returned ok:true with results: [] and count: 0, and by_equipment and by_target behave the same way. Check count rather than trusting the 200.
What the database contains, and where it is uneven
Measured across searches, browse axes and the taxonomy lists. Two of these go against us.
Searching for press returned seventy-six matching exercises and squat returned forty-seven, with the count reflecting the matches rather than the size of the library. A term that matches nothing returns nothing — an honest empty result rather than a full page of unrelated rows.
Target muscle, secondary muscles, equipment, body part and category all travel on the list row. A workout builder can filter on them without a detail call per exercise, which is the difference between one request and twenty for a single screen.
Instructions come back as an array of discrete steps rather than an HTML blob, so they render as a list without you parsing markup. The licence and the contributing author are on the record, which is what makes the content legally usable in a product rather than merely available.
The library is community-built. Some exercises have several paragraphs of instruction and a picture; others have a single line and no media at all, and the difficulty field is frequently empty. Do not design a screen that assumes an image exists — design one that degrades to text, because for a meaningful share of the library that is what there is.
The list contains both broad names and narrower ones — legs alongside upper legs and lower legs — because the source itself carries two granularities. We do not merge them, since collapsing them would lose real distinctions, but it means a body-part picker built straight from the list will show overlapping choices unless you decide which level you want.
What people build with Fitness & Nutrition
The jobs this data is most often used for.
endpoints
credits per call
Fitness apps call by_bodypart or by_equipment to build targeted workouts.
Trainers use exercise_detail for step-by-step instructions.
Apps use the demonstration media to show correct form.
What Fitness & Nutrition data costs
The cheapest call here is 0 credits, so $15/mo (Pro) buys 10,000 of them — $1.50 per 1,000 credits. Credits roll over and never expire, and failed or blocked calls are not charged.
Full pricing →- 1,000 free credits on signup, no card
- One key, all 184 APIs, one credit pool
- Failed and blocked calls are never charged
- Credits roll over and never expire
Call it in two lines
Sign up, get 1,000 credits and one key that works on every engine. Then this is the whole protocol.
curl -X POST https://api.reefapi.com/fitness/v1/exercises \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{}'import requests
r = requests.post(
"https://api.reefapi.com/fitness/v1/exercises",
headers={"x-api-key": REEF_KEY},
json={},
)
print(r.json()["data"])Have a question? We got answers.
The questions people actually ask before wiring up Fitness & Nutrition.
Get a free key →Does this return calories, macros or any nutrition data?▾
No. It is exercise reference data only. A record holds name, bodyPart, category, target, secondaryMuscles, equipment, an instructions array, a description, an image URL and licensing. There is no kcal or kJ figure, no per-100g or per-serving nutrition block, and no food database behind it.
Why does bodypart_list contain both 'chest' and 'Chest'?▾
The list exposes two naming systems that both exist in the underlying data. The capitalized entries are wger's own categories (Abs, Arms, Back, Calves, Cardio, Chest, Legs, Shoulders) and the lowercase ones are the legacy body-part labels (back, cardio, chest, lower legs, shoulders, upper arms, upper legs, waist). Both are accepted, matching is case-insensitive, and 'Legs' and 'upper legs' resolve to the same records. Every result carries both, as category and bodyPart.
Which muscle names does by_target accept?▾
The 15 in target_list, and they use wger's anatomical vocabulary rather than gym slang: Abs, Biceps, Brachialis, Calves, Chest, Glutes, Hamstrings, Lats, Obliquus externus abdominis, Quads, Serratus anterior, Shoulders, Soleus, Trapezius, Triceps. So 'Quads' works and 'quadriceps' does not, and there is no separate entry for abductors or forearms. Matching is by substring, so 'bicep' also hits Biceps.
Is the exercise id a number or a string?▾
The response gives it as a string ('1962', '73') while exercise_detail's id parameter is typed as an integer. Both directions work, but if you are keying a cache or diffing two responses, cast one side. Ids are stable across languages, so id 12 is the same exercise whether you ask in English or German.
Why is count 861 on one action and 3 on another?▾
The exercises action reports the size of the whole library, 861 exercises, no matter how many rows it returns, and pages with next_offset. The three filter actions report the number of rows actually in that response instead. So do not use count as a page-size check on exercises, and do not read it as a library total on by_bodypart, by_equipment or by_target.
Is gifUrl actually an animation?▾
No. gifUrl and imageUrl hold the same value and it points at a static .png on wger's media host. Many exercises have neither, in which case both are null. The number inside the image path is not reliably the exercise id: 'Bench Press' has id 73 but its image lives under /exercise-images/192/, so build image URLs from the field rather than by templating the id.
What happens if I pass a body part or equipment name that does not exist?▾
You get a 200 with ok:true, results: [] and count: 0, not an error. by_bodypart with 'zzzz' behaved exactly that way. Because matching is by substring, a near-miss can also return a smaller set than you expected rather than nothing at all. Call bodypart_list, equipment_list or target_list once, cache the strings, and check count on every response.
Do I have to credit wger?▾
Yes, if you republish. The data comes from wger.de and each record carries its own license field, which was 'CC-BY-SA 4', 'CC-BY-SA 3' or 'CC0' across the records we read, plus a licenseAuthor contributor handle. The response meta also carries an attribution string. Because the license varies per record, keep license and licenseAuthor attached to anything you store.
Can I search exercises by name?▾
Not dependably right now. The exercises action takes a name parameter, but in our tests name='press', name='squat' and a deliberate nonsense string all returned the identical first page of the unfiltered library with count 861. Filter with by_bodypart, by_equipment or by_target, which we verified do narrow the result set, and match on the name field client-side if you need a keyword.
What is the Fitness & Nutrition API?▾
Fitness & Nutrition API is a ReefAPI endpoint group for exercise and nutrition data for foods and workouts. It returns live JSON through POST requests under /fitness/v1.
Is the Fitness & Nutrition API free to try?▾
Yes. ReefAPI starts with 1,000 free credits, no card required. Fitness & Nutrition calls use the same shared credit balance as every other ReefAPI engine.
Do I need a Fitness & Nutrition login or account?▾
No login to Fitness & Nutrition is needed for the API response. You call ReefAPI with your x-api-key header, and the playground can run live examples before you create a production key.
How fresh is the Fitness & Nutrition data?▾
The page example is captured from a live exercises call, and production requests fetch live data through ReefAPI rather than a static sample.
How many credits does the Fitness & Nutrition API use?▾
Fitness & Nutrition actions currently cost 1 credit per successful call. Failed or blocked calls are free, and all APIs draw from one credit pool.
19 Utilities & AI APIs on the same key
One key, one credit pool, one response envelope. If you are pulling Fitness & Nutrition, you are one call away from the rest of the category — no second contract, no second integration.
Need something this API does not do?
Name the endpoint, the field, or a source we do not carry yet. We ship new APIs every week and you would be first to get the key. Real people read every message and reply the same day.
Try it on your own data before you pay anything
The call above is the real endpoint, not a recording. A free key gives you 1,000 credits, the other 183 APIs, and the same envelope everywhere.
Endpoints, parameters and credit costs on this page are read from the live catalog and cannot drift from what the API accepts. Field notes were captured on 2026-08-30.