Using the routine API
The routine data model is split across a handful of related objects and
has a few non-obvious moving parts (iterations, day sequencing,
progression rules). This page explains how everything fits together. It
is not a field reference: for the full request/response schemas of
every endpoint, use /api/v2/schema/redoc/.
A routine has a maximum duration of 120 days.
Object hierarchy
The routine itself is just a shell. The actual training data is split across several linked objects, each with its own endpoint:
Routine /api/v2/routine/
└── Day /api/v2/day/
└── Slot /api/v2/slot/
└── SlotEntry /api/v2/slot-entry/
├── WeightConfig /api/v2/weight-config/ (+ max-)
├── RepetitionsConfig /api/v2/repetitions-config/ (+ max-)
├── SetsConfig /api/v2/sets-config/ (+ max-)
├── RirConfig /api/v2/rir-config/ (+ max-)
└── RestConfig /api/v2/rest-config/ (+ max-)
The actual training history lives in two more objects, both linked back to the routine:
WorkoutSession /api/v2/workoutsession/
└── WorkoutLog /api/v2/workoutlog/
Templates are exposed read-only through /api/v2/templates/ (your
own) and /api/v2/public-templates/ (those shared by others).
Iterations
An “iteration” is one complete cycle through all the days of a routine. Once the last day has been done, the next occurrence of the first day starts a new iteration. In practice this will most often be a week, but the system doesn’t require that.
The iteration number is the key that ties progression rules to specific
points in the routine: a WeightConfig with iteration=3 and
value=60 applies starting on the third pass through the days.
Days and day sequencing
A routine is built from an ordered list of days (controlled by each
day’s order field). From this list, plus the routine’s start and
end date, wger computes a concrete date-by-date sequence.
For a routine that starts on the 1.1 with three days, the basic sequence is:
1.1 |
1.2 |
1.3 |
1.4 |
1.5 |
1.6 |
1.7 |
1.8 |
1.9 |
1.10 |
|
|---|---|---|---|---|---|---|---|---|---|---|
Day |
Day 1 |
Day 2 |
Day 3 |
Day 1 |
Day 2 |
Day 3 |
Day 1 |
Day 2 |
Day 3 |
Day 1 |
Iteration |
1 |
1 |
1 |
2 |
2 |
2 |
3 |
3 |
3 |
4 |
Two flags change this default behaviour:
need_logs_to_advance (on the day) stalls the sequence on a day until the user logs a session for it. Below, Day 3 has the flag set, the user finally logged a session on 1.8, and the sequence resumes on 1.9:
1.1 |
1.2 |
1.3 |
1.4 |
1.5 |
1.6 |
1.7 |
1.8 |
1.9 |
1.10 |
|
|---|---|---|---|---|---|---|---|---|---|---|
Day |
Day 1 |
Day 2 |
Day 3 |
Day 1 |
Day 2 |
Day 3 |
Day 3 |
Day 3 |
Day 1 |
Day 2 |
Iteration |
1 |
1 |
1 |
2 |
2 |
2 |
2 |
2 |
3 |
3 |
fit_in_week (on the routine) pads each iteration with empty placeholder days (no day, no exercises) so the routine always restarts on a fixed weekday:
1.1 (Mon) |
1.2 |
1.3 |
1.4 |
1.5 |
1.6 |
1.7 |
1.8 (Mon) |
1.9 |
1.10 |
|
|---|---|---|---|---|---|---|---|---|---|---|
Day |
Day 1 |
Day 2 |
Day 3 |
– |
– |
– |
– |
Day 1 |
Day 2 |
Day 3 |
Iteration |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
2 |
2 |
2 |
Rest days are regular days with is_rest=true and no slots attached.
They occupy a position in the sequence but produce no exercises.
Slots and slot entries
Inside a day, exercises aren’t attached directly. They go through a two-level structure:
a slot is one “position” in the day: roughly one exercise (or one superset)
a slot entry attaches a specific exercise to that slot
If a slot has more than one entry, it automatically becomes a superset.
The /date-sequence-gym view interleaves the sets across the
entries; they don’t need to have the same number of sets. With
Exercise 1, 4 sets
Exercise 2, 2 sets
Exercise 3, 3 sets
the gym-mode output is:
Exercise 1
Exercise 2
Exercise 3
Exercise 1
Exercise 2
Exercise 3
Exercise 1
Exercise 3
Exercise 1
The repetition_rounding and weight_rounding fields on a slot
entry control how the computed values are rounded for display. If left
empty when creating the entry, the defaults from the user profile are
copied in.
Progression rules
The actual values for weight, repetitions, sets, RiR and rest aren’t
stored on the slot entry. They live in separate config objects (one
endpoint per field), each with a max- variant for ranges like
“8 to 10 reps”.
Each config record applies starting at a given iteration. The value
at iteration n is the stacked result of all preceding records: each
record either replaces the value outright (operation=r) or adds /
subtracts a value (+ / -), either as an absolute number
(step=abs) or a percentage (step=percent). The repeat flag
keeps a rule active for every following iteration until another rule
takes over, so “+1 kg every week” is a single record.
A weight config example:
Iteration |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
Config |
50kg |
– |
– |
+10% |
– |
+2kg |
+1kg |
45kg |
Result |
50kg |
50kg |
50kg |
55kg |
55kg |
57kg |
58kg |
45kg |
All configs are optional. If none is set for a field, that field will
be null in the computed output, except for sets, which defaults to
1.
Requirements
A progression rule can be made conditional on the user actually hitting
the prescribed values in the previous iteration. Set the
requirements field to a JSON object of the form:
{
"rules": [
"weight",
"repetitions",
"rir",
"rest"
]
}
If the rules list is non-empty, the rule only applies when all
listed fields were met in at least one log of the previous iteration.
For example: if the target is to move from 8x60 kg to 8x65 kg, with
rules containing weight and repetitions, the increase only
happens once the user has actually logged 8 reps at 60 kg. Until then
the field stays at the previous value.
Custom calculation logic
If the rule-based system is not flexible enough, a slot entry’s
class_name field can point to a Python class under
wger.manager.config_calculations that takes over all calculations
for that entry. This is an escape hatch and not currently used; please
get in touch if you have a use case for it.
Sessions and logs
The training history is stored in two objects. A WorkoutSession represents one workout (one date, optional notes and impression). A WorkoutLog is one performed set, attached to a session and optionally back-linked to a routine, day, slot entry and iteration.
Each log carries both what was actually performed (weight,
repetitions, rir, rest) and the originally prescribed
values (weight_target, repetitions_target, rir_target,
rest_target), so a log preserves both sides even when the routine
later changes.
Computed endpoints
Once a routine is set up, these read-only sub-resources return calculated views of it:
/api/v2/routine/{id}/structure/The full nested structure (routine → days → slots → slot entries), suitable for an editor.
/api/v2/routine/{id}/date-sequence-display/One entry per date, with the matching day and slots already resolved. Slots that contain repeated sets of the same exercise are folded together for display.
/api/v2/routine/{id}/date-sequence-gym/Same data, but the slots are split into individual sets and supersets are interleaved as described above. Use this for the gym-mode view.
/api/v2/routine/{id}/logs/The workout sessions and logs for this routine, grouped by session.
/api/v2/routine/{id}/stats/Aggregated statistics from the logs: volume, set count and average intensity (estimated 1RM via the Brzycki formula), each broken down by day, ISO week, iteration and the whole routine, and further split into total, upper/lower body, per muscle and per exercise.
All five endpoints are cached server-side and invalidated when the underlying routine changes.