Skip to content

List the team's metric thresholds

GET
/api/thresholds/
curl --request GET \
--url http://localhost:8000/api/thresholds/ \
--header 'Authorization: Bearer <token>'

Any team member. Returns one row per metric in the requested (activity, exercise, gender) slice, each carrying either the team’s persisted override or the inherited system / MetricSpec default (with inherited=true). Used to render the threshold-configurator table.

Query params: activity (slug, optional), exercise (string, optional), gender ("" | male | female, default ""). Omitting all three returns every metric across activities.

Each row also carries norms — the Movement Norms Library reference band (ADR-0034 / #1406) for the requested slice: the exact (gender, age_band, skill_level) cohort row when all three dimensions are set and covered, else the library’s base band (scope discriminates); null when the library has no usable band for the metric. Display-only — the green-zone resolver never reads it, and a saved team row always wins (#1317).

activity
string

Activity slug filter (optional).

age_band
string

"" (default, all ages) / under_18 / 18_34 / 35_49 / 50_64 / 65_69 / 70_74 / 75_79 / 80_84 / 85_plus. Demographic slice — gender is treated as more specific than age band.

exercise
string

Exercise name filter (optional).

gender
string

"" (default) / male / female.

skill_level
string

"" (default, all levels) / beginner / intermediate / advanced. Demographic slice; the resolver ranks gender > skill_level > age_band.

Media typeapplication/json
object
items
required
Array<object>

Read shape — either a materialised team row (inherited=False, id populated) or a synthetic catalog entry sourced from MetricSpec (inherited=True, id=None). Plain Serializer rather than ModelSerializer because inherited rows have no DB backing — the container POSTs to materialise on first edit.

object
id
required
string
inherited
required
boolean
activity
required
string
exercise
required
string
nullable
metric_key
required
string
metric_label
required
string
unit
required
string
higher_is_better
required
boolean
nullable
min_good
required
number format: double
nullable
max_good
required
number format: double
nullable
is_height_scaled
required
boolean
default_min_good
required
number format: double
nullable
default_max_good
required
number format: double
nullable
norms
required
object
min
required
number format: double
nullable
max
required
number format: double
nullable
evidence_basis
required
string
source
required
string
scope
required
  • cohort - Cohort
  • base - Base
string
Allowed values: cohort base
overrides
required
Array<object>
object
kind
required
  • gender - gender
  • age_band - age_band
  • skill_level - skill_level
  • height_scaled - height_scaled
  • segment - segment
string
Allowed values: gender age_band skill_level height_scaled segment
label
required
string
detail
required
object
key
additional properties
number format: double
nullable
slice

The demographic slice an override row lives in — the FE’s jump target when the coach clicks the badge to land on that cohort. Empty strings are the “all” sentinel for each dimension.

object
gender
required
string
age_band
required
string
skill_level
required
string
observed_distribution
required
object
bins
required
Array<object>
object
bin_min
required
number
bin_max
required
number
count
required
integer
total_sessions
required
integer
axis_min
required
number
axis_max
required
number
session_window_days
required
integer
Examples
ExampleAThresholdSlice

One row per metric; inherited rows carry `inherited: true`

{
"items": [
{
"id": "7b3d9e1a-2c4f-4a6b-8d0e-1f2a3b4c5d6e",
"inherited": false,
"activity": "running",
"exercise": "Treadmill",
"metric_key": "cadence",
"unit": "spm",
"higher_is_better": false,
"min_good": 175,
"max_good": 185,
"is_height_scaled": false,
"norms": {
"min": 170,
"max": 180,
"evidence_basis": "validated",
"source": "Running cadence norms (Sport Science Insider)",
"scope": "base"
},
"overrides": [],
"observed_distribution": {
"bins": [],
"total_sessions": 0,
"axis_min": 0,
"axis_max": 1,
"session_window_days": 30
}
},
{
"id": "0a1b2c3d-4e5f-6071-8293-a4b5c6d7e8f9",
"inherited": true,
"activity": "running",
"exercise": "Treadmill",
"metric_key": "vertical_oscillation",
"unit": "cm",
"higher_is_better": false,
"min_good": 6,
"max_good": 9,
"is_height_scaled": false,
"norms": null,
"overrides": [],
"observed_distribution": {
"bins": [],
"total_sessions": 0,
"axis_min": 0,
"axis_max": 1,
"session_window_days": 30
}
}
]
}
Media typeapplication/json
object
detail
required

Human-readable message, or a stable machine code for the cases a client branches on. The standard envelope for 400 (validation — a field-keyed object may appear instead), 401 (missing / invalid credentials), 403 (authenticated but not permitted), and 404 (absent — cross-team records are collapsed to 404 so the API never leaks the existence of another team’s data).

string
Examplegenerated
{
"detail": "example"
}
Media typeapplication/json
object
detail
required

Human-readable message, or a stable machine code for the cases a client branches on. The standard envelope for 400 (validation — a field-keyed object may appear instead), 401 (missing / invalid credentials), 403 (authenticated but not permitted), and 404 (absent — cross-team records are collapsed to 404 so the API never leaks the existence of another team’s data).

string
Examples
Example403—PartnerAPIKeysCan'tManageThresholds

403 — partner API keys can't manage thresholds

{
"detail": "You do not have permission to perform this action."
}