Activities¶
client.activities: /api/v1/activities/...
Bases: Resource
Activities: the summaries, their time series, and analyses over one or many.
app_metadata
cached
property
¶
This app's metadata on activities: set(activity_id, data=...) and delete.
longitudinal
cached
property
¶
Data and analyses across many activities: data, mean_max and awd.
awd(activity_id, *, metric=None, output=None)
¶
awd(activity_id: str, *, metric: IntensityMetric | None = None, output: None = None) -> pd.DataFrame | pl.DataFrame
awd(activity_id: str, *, metric: IntensityMetric | None = None, output: Literal['pandas']) -> pd.DataFrame
awd(activity_id: str, *, metric: IntensityMetric | None = None, output: Literal['polars']) -> pl.DataFrame
awd(activity_id: str, *, metric: IntensityMetric | None = None, output: Literal['arrow']) -> pa.Table
awd(activity_id: str, *, metric: IntensityMetric | None = None, output: Literal['bytes']) -> bytes
Retrieves an activity's accumulated work duration (AWD) curve.
Endpoint: GET /api/v1/activities/{activity_id}/accumulated-work-duration
AWD is how long the activity spent at or above each intensity: the activity's samples sorted by intensity.
Parameters:
-
activity_id(str) –The activity's ID.
-
metric(IntensityMetric | None, default:None) –"power"or"speed". Defaults to power for cycling, speed otherwise. -
output(FrameOutput | None, default:None) –"pandas","polars","arrow"or"bytes". Defaults to the installed frame library, Polars if both are.
Returns:
-
DataFrame | DataFrame | Table | bytes–A frame with the metric value and
durationas columns.
Raises:
-
SweatStackNotFoundError–If the activity does not exist.
-
SweatStackAPIError–If the API request fails for any other reason.
Examples:
from sweatstack import Client
client = Client()
latest = client.activities.latest(sport="cycling")
awd = client.activities.awd(latest.id, metric="power")
backfill_status()
¶
Retrieves how far the activity backfill has reached: the first update of the stream.
Endpoint: GET /api/v1/activities/backfill-status
Returns:
-
BackfillStatus(BackfillStatus) –backfill_loaded_until, the earliest date loaded so far.
Raises:
-
ValueError–If the stream ends without an update.
-
SweatStackAPIError–If the API request fails.
Examples:
from sweatstack import Client
client = Client()
print(client.activities.backfill_status().backfill_loaded_until)
data(activity_id, *, segmentation_on=None, metrics=None, output=None)
¶
data(activity_id: str, *, segmentation_on: IntensityMetric | None = None, metrics: MetricParam | None = None, output: None = None) -> pd.DataFrame | pl.DataFrame
data(activity_id: str, *, segmentation_on: IntensityMetric | None = None, metrics: MetricParam | None = None, output: Literal['pandas']) -> pd.DataFrame
data(activity_id: str, *, segmentation_on: IntensityMetric | None = None, metrics: MetricParam | None = None, output: Literal['polars']) -> pl.DataFrame
data(activity_id: str, *, segmentation_on: IntensityMetric | None = None, metrics: MetricParam | None = None, output: Literal['arrow']) -> pa.Table
data(activity_id: str, *, segmentation_on: IntensityMetric | None = None, metrics: MetricParam | None = None, output: Literal['bytes']) -> bytes
Retrieves an activity's time series, one row per sample.
Endpoint: GET /api/v1/activities/{activity_id}/data
Parameters:
-
activity_id(str) –The activity's ID.
-
segmentation_on(IntensityMetric | None, default:None) –Downsample with AISC (Adaptive Intensity Segmentation Codec), keyed on
"power"or"speed". Omit for every sample. -
metrics(MetricParam | None, default:None) –One metric or a list. Defaults to the server's selection.
-
output(FrameOutput | None, default:None) –"pandas","polars","arrow"or"bytes"(the raw parquet response). Defaults to the installed frame library, Polars if both are.
Returns:
-
DataFrame | DataFrame | Table | bytes–A frame with a timezone-aware UTC
timestampcolumn,timestamp_local, and -
DataFrame | DataFrame | Table | bytes–one column per metric.
Raises:
-
SweatStackNotFoundError–If the activity does not exist.
-
SweatStackAPIError–If the API request fails for any other reason.
Examples:
from sweatstack import Client
client = Client()
latest = client.activities.latest()
df = client.activities.data(latest.id, metrics=["power", "heart_rate"], output="polars")
latest(*, sport=None)
¶
Retrieves the most recent activity, or None if there is none.
Endpoint: GET /api/v1/activities/latest
Parameters:
-
sport(Sport | str | None, default:None) –Only consider this sport. A parent sport (
"cycling") also matches its sub-sports.
Returns:
-
ActivityDetails | None–ActivityDetails | None: The most recent matching activity, or
Nonewhen the -
ActivityDetails | None–user has no matching activity.
Raises:
-
SweatStackAPIError–If the API request fails.
Examples:
from sweatstack import Client
client = Client()
latest = client.activities.latest(sport="cycling")
if latest is not None:
data = client.activities.data(latest.id)
list(*, start=None, end=None, sport=None, tags=None, limit=100, offset=0, output=None)
¶
list(*, start: date | None = None, end: date | None = None, sport: SportParam | None = None, tags: TagParam | None = None, limit: int = 100, offset: int = 0, output: Literal['models'] | None = None) -> builtins.list[ActivitySummary]
list(*, start: date | None = None, end: date | None = None, sport: SportParam | None = None, tags: TagParam | None = None, limit: int = 100, offset: int = 0, output: Literal['pandas']) -> pd.DataFrame
list(*, start: date | None = None, end: date | None = None, sport: SportParam | None = None, tags: TagParam | None = None, limit: int = 100, offset: int = 0, output: Literal['polars']) -> pl.DataFrame
list(*, start: date | None = None, end: date | None = None, sport: SportParam | None = None, tags: TagParam | None = None, limit: int = 100, offset: int = 0, output: Literal['arrow']) -> pa.Table
Lists activities, newest first.
Endpoint: GET /api/v1/activities/
Parameters:
-
start(date | None, default:None) –Only activities on or after this date.
-
end(date | None, default:None) –Only activities on or before this date.
-
sport(SportParam | None, default:None) –One sport or a list; an activity matches any of them. A parent sport (
"cycling") also matches its sub-sports. -
tags(TagParam | None, default:None) –One tag or a list; an activity must have all of them.
-
limit(int, default:100) –How many activities to return. The client pages through the endpoint until it has this many or there are no more.
-
offset(int, default:0) –How many of the newest matching activities to skip.
-
output(ListOutput | None, default:None) –"models"(default),"pandas","polars"or"arrow". Overrides the client-level default for this call.
Returns:
-
list[ActivitySummary] | DataFrame | DataFrame | Table–ActivitySummary objects, or a frame with one row per activity. Nested fields are
-
list[ActivitySummary] | DataFrame | DataFrame | Table–flattened to dotted columns in pandas and typed structs in Polars and Arrow.
Raises:
-
SweatStackAPIError–If the API request fails.
Examples:
from datetime import date
from sweatstack import Client
client = Client()
rides = client.activities.list(sport="cycling", start=date(2026, 1, 1), limit=20)
frame = client.activities.list(output="polars")
mean_max(activity_id, *, metric, durations=None, output=None)
¶
mean_max(activity_id: str, *, metric: IntensityMetric, durations: Sequence[int] | Literal['all'] | None = None, output: None = None) -> pd.DataFrame | pl.DataFrame
mean_max(activity_id: str, *, metric: IntensityMetric, durations: Sequence[int] | Literal['all'] | None = None, output: Literal['pandas']) -> pd.DataFrame
mean_max(activity_id: str, *, metric: IntensityMetric, durations: Sequence[int] | Literal['all'] | None = None, output: Literal['polars']) -> pl.DataFrame
mean_max(activity_id: str, *, metric: IntensityMetric, durations: Sequence[int] | Literal['all'] | None = None, output: Literal['arrow']) -> pa.Table
mean_max(activity_id: str, *, metric: IntensityMetric, durations: Sequence[int] | Literal['all'] | None = None, output: Literal['bytes']) -> bytes
Retrieves an activity's mean-max curve: the best average for each duration.
Endpoint: GET /api/v1/activities/{activity_id}/mean-max
Parameters:
-
activity_id(str) –The activity's ID.
-
metric(IntensityMetric) –"power"or"speed". -
durations(Sequence[int] | Literal['all'] | None, default:None) –In seconds.
None(default) for 19 durations from 1 s to 6 h,"all"for the full grid (1 s steps to 3 min, then 5, 10, 30 and 60 s steps), or a list. Durations the activity did not last are left out. -
output(FrameOutput | None, default:None) –"pandas","polars","arrow"or"bytes". Defaults to the installed frame library, Polars if both are.
Returns:
-
DataFrame | DataFrame | Table | bytes–A frame, one row per duration:
duration, the metric (W or m/s) andstart, -
DataFrame | DataFrame | Table | bytes–the UTC time the best effort began. The curve can rise again at longer durations
-
DataFrame | DataFrame | Table | bytes–(intermittent efforts); it is returned as it is.
Raises:
-
SweatStackNotFoundError–If the activity does not exist.
-
SweatStackAPIError–If the API request fails for any other reason.
Examples:
from sweatstack import Client
client = Client()
latest = client.activities.latest(sport="cycling")
curve = client.activities.mean_max(latest.id, metric="power", durations=[5, 60, 300, 1200])
retrieve(activity_id)
¶
Retrieves one activity with its summary and laps.
Endpoint: GET /api/v1/activities/{activity_id}
Parameters:
-
activity_id(str) –The activity's ID.
Returns:
-
ActivityDetails(ActivityDetails) –The activity.
Raises:
-
SweatStackNotFoundError–If the activity does not exist.
-
SweatStackAPIError–If the API request fails for any other reason.
Examples:
from sweatstack import Client
client = Client()
activity = client.activities.retrieve("act_123")
print(activity.sport, activity.start)
upload(files)
¶
Uploads activity files (FIT or CSV); they are processed in the background.
Endpoint: POST /api/v1/activities/upload
FIT files carry their sport. CSV files need a sport column with an Open Sport
Taxonomy code (cycling.road) and a timestamp column with offset-aware ISO 8601
datetimes (...+02:00 or ...Z); naive timestamps are rejected during processing.
Parameters:
-
files(str | Path | Sequence[str | Path]) –One path or a list of paths.
Returns:
-
list[SourceResponse]–list[SourceResponse]: One entry per file.
statusstarts as"processing"; -
list[SourceResponse]–retrieve the activities by ID once processed.
Raises:
-
FileNotFoundError–If a file does not exist.
-
SweatStackBadRequestError–If the server rejects the upload.
-
SweatStackAPIError–If the API request fails for any other reason.
Examples:
from sweatstack import Client
client = Client()
sources = client.activities.upload(["ride.fit", "run.fit"])
print([source.status for source in sources])
watch_backfill_status(*, auto_reconnect=False)
¶
Streams how far the activity backfill of a newly connected user has reached.
Endpoint: GET /api/v1/activities/backfill-status
Yields an update every few seconds. The server closes the stream after 60 seconds;
with auto_reconnect=True the generator reconnects and keeps yielding until you
stop iterating.
Parameters:
-
auto_reconnect(bool, default:False) –Reconnect after the server closes the stream or the connection drops.
Yields:
-
BackfillStatus(BackfillStatus) –backfill_loaded_until, the earliest date loaded so far.
Raises:
-
SweatStackAPIError–If the API request fails.
-
SweatStackConnectionError–If the connection fails and
auto_reconnectis off.
Examples:
from sweatstack import Client
client = Client()
for status in client.activities.watch_backfill_status():
print(status.backfill_loaded_until)
Bases: Resource
Data and analyses across many activities: /api/v1/activities/longitudinal-*.
awd(*, sport, metric, start=None, end=None, output=None)
¶
awd(*, sport: SportParam, metric: IntensityMetric, start: date | None = None, end: date | None = None, output: None = None) -> pd.DataFrame | pl.DataFrame
awd(*, sport: SportParam, metric: IntensityMetric, start: date | None = None, end: date | None = None, output: Literal['pandas']) -> pd.DataFrame
awd(*, sport: SportParam, metric: IntensityMetric, start: date | None = None, end: date | None = None, output: Literal['polars']) -> pl.DataFrame
awd(*, sport: SportParam, metric: IntensityMetric, start: date | None = None, end: date | None = None, output: Literal['arrow']) -> pa.Table
awd(*, sport: SportParam, metric: IntensityMetric, start: date | None = None, end: date | None = None, output: Literal['bytes']) -> bytes
Retrieves accumulated work duration (AWD) across a date range, at four intensities.
Endpoint: GET /api/v1/activities/longitudinal-accumulated-work-duration
Beta: the server marks this endpoint as in development.
Parameters:
-
sport(SportParam) –One sport or a list.
-
metric(IntensityMetric) –"power"or"speed". -
start(date | None, default:None) –First date of the range.
-
end(date | None, default:None) –Last date of the range. Defaults to today.
-
output(FrameOutput | None, default:None) –"pandas","polars","arrow"or"bytes". Defaults to the installed frame library, Polars if both are.
Returns:
-
DataFrame | DataFrame | Table | bytes–A frame with the AWD at the max (highest daily), hard, medium and easy levels.
Raises:
-
SweatStackAPIError–If the API request fails.
Examples:
from datetime import date
from sweatstack import Client
client = Client()
awd = client.activities.longitudinal.awd(
sport="cycling", metric="power", start=date(2026, 1, 1)
)
data(*, sport, start, end=None, metrics=None, segmentation_on=None, output=None)
¶
data(*, sport: SportParam, start: date, end: date | None = None, metrics: MetricParam | None = None, segmentation_on: IntensityMetric | None = None, output: None = None) -> pd.DataFrame | pl.DataFrame
data(*, sport: SportParam, start: date, end: date | None = None, metrics: MetricParam | None = None, segmentation_on: IntensityMetric | None = None, output: Literal['pandas']) -> pd.DataFrame
data(*, sport: SportParam, start: date, end: date | None = None, metrics: MetricParam | None = None, segmentation_on: IntensityMetric | None = None, output: Literal['polars']) -> pl.DataFrame
data(*, sport: SportParam, start: date, end: date | None = None, metrics: MetricParam | None = None, segmentation_on: IntensityMetric | None = None, output: Literal['arrow']) -> pa.Table
data(*, sport: SportParam, start: date, end: date | None = None, metrics: MetricParam | None = None, segmentation_on: IntensityMetric | None = None, output: Literal['bytes']) -> bytes
Retrieves the time series of every matching activity in a date range, concatenated.
Endpoint: GET /api/v1/activities/longitudinal-data
Responses are cached on disk when :func:sweatstack.enable_cache is on.
Parameters:
-
sport(SportParam) –One sport or a list. Required by the API.
-
start(date) –First date of the range.
-
end(date | None, default:None) –Last date of the range. Defaults to today.
-
metrics(MetricParam | None, default:None) –One metric or a list. Defaults to
duration,power,heart_rateandspeed. -
segmentation_on(IntensityMetric | None, default:None) –Downsample with AISC, keyed on
"power"or"speed". -
output(FrameOutput | None, default:None) –"pandas","polars","arrow"or"bytes". Defaults to the installed frame library, Polars if both are.
Returns:
-
DataFrame | DataFrame | Table | bytes–A frame, one row per sample, with
timestamp(UTC),timestamp_local, -
DataFrame | DataFrame | Table | bytes–activity_idandsportcolumns plus one column per metric.
Raises:
-
SweatStackAPIError–If the API request fails.
Examples:
from datetime import date
from sweatstack import Client
client = Client()
season = client.activities.longitudinal.data(
sport="cycling", start=date(2026, 1, 1), metrics=["power"], output="polars"
)
mean_max(*, sport, metric, start=None, end=None, after=None, durations=None, output=None)
¶
mean_max(*, sport: SportParam, metric: IntensityMetric, start: date | None = None, end: date | None = None, after: float | Sequence[float] | None = None, durations: Sequence[int] | Literal['all'] | None = None, output: None = None) -> pd.DataFrame | pl.DataFrame
mean_max(*, sport: SportParam, metric: IntensityMetric, start: date | None = None, end: date | None = None, after: float | Sequence[float] | None = None, durations: Sequence[int] | Literal['all'] | None = None, output: Literal['pandas']) -> pd.DataFrame
mean_max(*, sport: SportParam, metric: IntensityMetric, start: date | None = None, end: date | None = None, after: float | Sequence[float] | None = None, durations: Sequence[int] | Literal['all'] | None = None, output: Literal['polars']) -> pl.DataFrame
mean_max(*, sport: SportParam, metric: IntensityMetric, start: date | None = None, end: date | None = None, after: float | Sequence[float] | None = None, durations: Sequence[int] | Literal['all'] | None = None, output: Literal['arrow']) -> pa.Table
mean_max(*, sport: SportParam, metric: IntensityMetric, start: date | None = None, end: date | None = None, after: float | Sequence[float] | None = None, durations: Sequence[int] | Literal['all'] | None = None, output: Literal['bytes']) -> bytes
Retrieves the mean-max curve across every matching activity in a date range.
Endpoint: GET /api/v1/activities/longitudinal-mean-max
Responses are cached on disk when :func:sweatstack.enable_cache is on.
Parameters:
-
sport(SportParam) –One sport or a list.
-
metric(IntensityMetric) –"power"or"speed". -
start(date | None, default:None) –First date of the range.
-
end(date | None, default:None) –Last date of the range. Defaults to today.
-
after(float | Sequence[float] | None, default:None) –One or more fatigue states (at most 5). For each, the curve is computed over the part of every activity after that much accumulated work (kJ, for power) or distance (m, for speed; experimental), then enveloped across activities. The frame gains an
aftercolumn. The date range is capped at one year. -
durations(Sequence[int] | Literal['all'] | None, default:None) –In seconds.
None(default) for 19 durations from 1 s to 6 h,"all"for the full grid, or a list. -
output(FrameOutput | None, default:None) –"pandas","polars","arrow"or"bytes". Defaults to the installed frame library, Polars if both are.
Returns:
-
DataFrame | DataFrame | Table | bytes–A frame, one row per duration (and per
aftervalue):duration, the metric, -
DataFrame | DataFrame | Table | bytes–start(UTC), and theactivity_idandsportthat set it.
Raises:
-
SweatStackAPIError–If the API request fails.
Examples:
from datetime import date
from sweatstack import Client
client = Client()
curve = client.activities.longitudinal.mean_max(
sport="cycling", metric="power", start=date(2026, 1, 1), after=[0, 1000]
)
Bases: _RecordAppMetadata
This app's metadata on activitys. Requires an app token.
delete(activity_id)
¶
Deletes this app's metadata from an activity.
Endpoint: DELETE /api/v1/activities/{activity_id}/app-metadata
Parameters:
-
activity_id(str) –The activity's ID.
Raises:
-
SweatStackAuthError–If the client does not hold an app token (403).
-
SweatStackAPIError–If the API request fails for any other reason.
Examples:
from sweatstack import Client
client = Client(api_key="app-user-token")
client.activities.app_metadata.delete("act_123")
set(activity_id, *, data)
¶
Replaces this app's metadata on an activity.
Endpoint: PUT /api/v1/activities/{activity_id}/app-metadata
The whole dict is replaced; there is no merge. Each app sees only its own metadata,
and it appears as app_metadata on the activity when read with an app token.
Parameters:
-
activity_id(str) –The activity's ID.
-
data(dict[str, Any]) –Any JSON-serialisable dict, at most 1 KB and 32 levels deep.
Raises:
-
SweatStackAuthError–If the client does not hold an app token (403). A personal token, from
authenticate()or an API key, never qualifies. -
SweatStackBadRequestError–If
datais too large (413) or too deep (422). -
SweatStackNotFoundError–If the activity does not exist.
-
SweatStackAPIError–If the API request fails for any other reason.
Examples:
from sweatstack import Client
client = Client(api_key="app-user-token") # e.g. user.client in FastAPI
client.activities.app_metadata.set("act_123", data={"reviewed": True})