FitExerciseDB API response fields, explained
2026-10-02 · 6 min
A FitExerciseDB exercise object has 16 fields. Five are always present (id, name, bodyPart, target and equipment) and the other eleven can be null or missing, so a client should treat them as optional. List calls wrap exercises in data and pagination; a single-exercise call adds a _links object; and the lang parameter changes the text fields but never the numbers. This page is the field-by-field reference for the ExerciseDB-style JSON that GET /v1/exercises returns.
In short
- 16 fields per exercise: id, name, bodyPart, target and equipment are required, everything else may be null.
- id is a four-digit string such as "0001". Keep it a string so the leading zeros survive.
- caloriesPerMinute and averageCaloriesPerMinute are the same stored number; averageCaloriesPerHour is that number times 60, rounded. For a real user, call the calories endpoint with a bodyweight.
- Lists return { data, pagination }. Compute the page count yourself from total and pageSize.
- Only the single-exercise response carries _links. The lang parameter translates text fields and leaves numbers and enums alone.
What fields does an exercise object contain?
Every exercise, in a list or on its own, has the same 16 fields. The five required ones describe what the movement is and which muscle it works. The rest add training and calorie detail.
| Field | Type | Present | Notes |
|---|---|---|---|
id | string | Always | Four digits such as "0001". Stable identifier. |
name | string | Always | The exercise name, in the response language. |
bodyPart | string | Always | One of 10 broad regions, capitalised, for example Waist. |
target | string | Always | One of 19 specific muscles, for example Abs. |
equipment | string | Always | One of 34 literal values, for example "Body Weight". |
category | string | Can be null | Free-form label such as strength. |
difficulty | string | Can be null | Such as beginner. |
mechanic | string | Can be null | Such as isolation. |
force | string | Can be null | Such as push. |
met | number | Can be null | Metabolic equivalent of the movement, for example 3.5. |
caloriesPerMinute | number | Can be null | Stored kcal per minute at a typical bodyweight. |
averageCaloriesPerMinute | number | Can be null | Same value as caloriesPerMinute. |
averageCaloriesPerHour | number | Can be null | caloriesPerMinute multiplied by 60 and rounded. |
secondaryMuscles | string[] | Can be null | Supporting muscles, in the response language. |
instructions | string[] | Can be null | Ordered steps, in the response language. |
language | string | Optional | Code of the language this response was rendered in. |
The exact strings for bodyPart, target and equipment come from the taxonomy endpoints, described in the API docs.
Which fields can be null, and how should a client handle that?
Only id, name, bodyPart, target and equipment are guaranteed. Model the other eleven as optional and nullable, then decide per field what an empty value means for your screen. A TypeScript type that matches the API looks like this:
type Exercise = {
id: string; // "0001", keep it a string
name: string;
bodyPart: string;
target: string;
equipment: string;
category?: string | null;
difficulty?: string | null;
mechanic?: string | null;
force?: string | null;
met?: number | null;
caloriesPerMinute?: number | null;
averageCaloriesPerMinute?: number | null;
averageCaloriesPerHour?: number | null;
secondaryMuscles?: string[] | null;
instructions?: string[] | null;
language?: "en" | "fr" | "es" | "pt" | "zh" | "ja";
};In the live dataset today, all 1,324 exercises have every one of the 16 fields filled in, but the schema allows nulls, so do not rely on that.
Two rules save most bugs. First, hide the steps section when instructions is null instead of rendering an empty list. Second, check met before you call the calories endpoint: an exercise without a MET value returns a 422 problem response, not a number.
How do the calorie fields relate to the calories endpoint?
caloriesPerMinute is a stored figure at a typical bodyweight, meant for quick display in a list. averageCaloriesPerMinute repeats it under a friendlier name, and averageCaloriesPerHour is that value times 60, rounded (4.3 kcal per minute becomes 258 per hour). None of them know who your user is.
For a personal estimate, pass the user's weight and the duration to GET /v1/exercises/{id}/calories?bodyweightKg=80&minutes=30, which multiplies the exercise's MET by bodyweight and time. The maths and the caveats are in the MET calorie guide. MET values themselves come from the Compendium of Physical Activities, so treat every result as an estimate.
What wraps a list, and what does a single exercise add?
List and search responses share one wrapper: an array in data and a pagination object with page, pageSize and total. The default page size is 50 and the maximum is 100, so the 1,324 exercises take 14 requests at the largest size. Some examples in our docs also show a totalPages field; compute it yourself so your code works either way:
{
"data": [ { "id": "0001", "name": "3/4 Sit-up", "bodyPart": "Waist", "target": "Abs", "equipment": "Body Weight" } ],
"pagination": { "page": 1, "pageSize": 50, "total": 1324 }
}const pages = Math.ceil(total / pageSize); // 1324 / 100 = 14The single-exercise call, GET /v1/exercises/{id}, returns the same 16 fields plus a _links object in the style of HAL. The calories link is templated, so a client fills in the two query parameters instead of building the URL by hand. Lists do not carry _links.
"_links": {
"self": { "href": "/v1/exercises/0001" },
"related": { "href": "/v1/exercises/0001/related" },
"calories": { "href": "/v1/exercises/0001/calories{?bodyweightKg,minutes}", "templated": true },
"marketplacePreview": { "href": "/marketplace/preview/0001.gif" }
}What does the lang parameter change?
Adding ?lang=fr (or es, pt, zh, ja) translates name, bodyPart, target, equipment, secondaryMuscles and instructions, and sets language to the code you asked for. It never touches id, the numeric fields, or the four enum-like labels category, difficulty, mechanic and force, which stay as they are. That means you can cache numbers once and only refetch text per language.
How the language is chosen, and why search terms should stay in English, is the subject of the search and languages guide. To try any of this, browse the exercise database or read the docs. The response has no image field: see how to buy and embed ExerciseDB GIFs and GIF vs video support in exercise APIs.
FAQ
- Is the exercise id a number or a string?
- A string. IDs are four digits with leading zeros, such as "0001" or "5201" (the numbers are not consecutive). Store and send them as strings, because converting to a number drops the zeros and breaks lookups.
- Are bodyPart and target lowercase?
- No. Values are capitalised, for example Waist, Abs and Body Weight. Filters compare against these exact strings, so copy them from the taxonomy endpoints rather than typing them.
- Does caloriesPerMinute depend on the user's weight?
- No. It is a stored figure for a typical bodyweight. For a number that reflects your user, call the calories endpoint with bodyweightKg and minutes.
- Why is my page count missing from the response?
- The pagination object is guaranteed to give page, pageSize and total. Compute the page count as Math.ceil(total / pageSize) instead of depending on an extra field.