Tests¶
A Test is a structured performance evaluation: a lactate test, a VO2max test, an FTP test, or any similar protocol that produces a defined set of physiological markers. Tests live alongside activities and traces, and can be referenced from either.
Where a trace is a single point measurement and an activity is a continuous recording, a test is the structured output of a deliberate evaluation protocol. The shape is rich enough to capture both interoperable, consumer-facing thresholds (first/second threshold, FatMax) and methodology-specific outputs (LT1/LT2, VT1/VT2, MLSS).
Test results¶
The results field on a Test is a structured JSON object. Every field is optional. Tests can carry any combination.
Thresholds (consumer-facing)
These are interoperable across testing methodologies. Most apps building on top of SweatStack should read from these.
| Field | Type | Description |
|---|---|---|
first_threshold |
Marker | The aerobic threshold (LT1, VT1, depending on protocol). |
second_threshold |
Marker | The anaerobic threshold (LT2, VT2, MLSS, depending on protocol). |
fatmax |
Marker | The point of maximal fat oxidation. |
Thresholds (methodology-specific)
For testing protocols where the underlying methodology matters.
| Field | Type | Description |
|---|---|---|
lt1 |
Marker | First lactate threshold. |
lt2 |
Marker | Second lactate threshold. |
vt1 |
Marker | First ventilatory threshold. |
vt2 |
Marker | Second ventilatory threshold. |
mlss |
Marker | Maximal lactate steady state. |
Capacity and ceiling metrics
| Field | Type | Unit | Description |
|---|---|---|---|
vo2max |
float | mL/min | Confirmed VO2 plateau. |
vo2peak |
float | mL/min | Highest observed VO2. |
vlamax |
float | mmol/L/s | Maximal lactate accumulation rate. |
heart_rate_max |
int | bpm | Observed maximal heart rate. |
critical_power |
int | watts | Critical power (cycling). |
critical_speed |
float | m/s | Critical speed (running). |
w_prime |
float | kJ | W′ (anaerobic work capacity). |
d_prime |
float | meters | D′ (anaerobic distance capacity). |
Economy and efficiency
| Field | Type | Unit | Description |
|---|---|---|---|
economy |
float | mL O₂/kg/km | Running or cycling economy. |
efficiency |
float | % | Gross mechanical efficiency. |
Marker shape¶
A Marker is a point on the intensity-duration curve, expressed in any of the metrics SweatStack supports.
{
"power": 285,
"heart_rate": 168,
"speed": 4.2,
"lactate": 4.0,
"vo2": 3200
}
All fields are optional. Populate the ones that the testing protocol actually measured.
Create a test¶
POST /api/v1/tests/ creates a test.
curl -X POST "https://app.sweatstack.no/api/v1/tests/" \
-H "Authorization: Bearer {your_access_token}" \
-H "Content-Type: application/json" \
-d '{
"title": "Lactate step test",
"sport": "cycling.road",
"start": "2026-05-06T10:00:00+02:00",
"end": "2026-05-06T11:30:00+02:00",
"results": {
"first_threshold": {"power": 220, "heart_rate": 150, "lactate": 2.0},
"second_threshold": {"power": 285, "heart_rate": 168, "lactate": 4.0},
"vo2max": 4100
},
"tags": ["lab", "step-test"]
}'
Required fields: sport, start. Everything else is optional. Returns the created test.
Required scope
Creating tests requires data:write.
List tests¶
GET /api/v1/tests/ returns tests filtered by date range, sport, tags, and creator.
curl -X GET "https://app.sweatstack.no/api/v1/tests/?start=2026-01-01&sport=cycling.road" \
-H "Authorization: Bearer {your_access_token}"
Available query parameters:
start: start date (YYYY-MM-DD).end: end date (YYYY-MM-DD).sport: sport identifier, repeatable for multiple values (e.g.?sport=cycling.road&sport=running.road).tags: filter by tag(s).created_by: filter by the user or app that created the test.limit: number of results (default 50).offset: pagination offset.
Get a single test¶
GET /api/v1/tests/{test_id} returns the test plus any traces and activities linked by timestamp.
curl -X GET "https://app.sweatstack.no/api/v1/tests/{test_id}" \
-H "Authorization: Bearer {your_access_token}"
Update a test¶
PUT /api/v1/tests/{test_id} replaces the test (full replace, not patch). Omitted optional fields are set to null.
curl -X PUT "https://app.sweatstack.no/api/v1/tests/{test_id}" \
-H "Authorization: Bearer {your_access_token}" \
-H "Content-Type: application/json" \
-d '{
"title": "Lactate step test (revised)",
"sport": "cycling.road",
"start": "2026-05-06T10:00:00+02:00",
"results": {
"second_threshold": {"power": 290, "heart_rate": 170, "lactate": 4.0}
}
}'
Returns 403 if the test was created by a different app and your token doesn't have access. Returns 404 if the test doesn't exist.
Delete a test¶
DELETE /api/v1/tests/{test_id} removes the test.
curl -X DELETE "https://app.sweatstack.no/api/v1/tests/{test_id}" \
-H "Authorization: Bearer {your_access_token}"
Same 403 / 404 semantics as update.
App metadata¶
Apps can attach per-app JSON metadata to tests via PUT /api/v1/tests/{test_id}/app-metadata and DELETE /api/v1/tests/{test_id}/app-metadata. See Application metadata for the full pattern (it's the same shape across activities, traces, and tests).
Python client¶
Tests aren't yet exposed in the Python client. Use the API directly via Client.session or any HTTP library until the methods land.