Skip to content

Scopes

A scope is a category of information and a verb. Your app requests the categories it uses; the user sees one line per category on the consent screen, with your reason one tap away, and your token reaches the endpoints of those categories and nothing else. Request less, and the screen is shorter.

The scopes

Scope What it reaches What the user reads
activities:read Activities, sources and uploads, tests, traces, markers, max efforts, the metabolic map, training zones, the intensity-duration model, the template week, sports and tags: everything under /activities/, /tests/, /traces/ and the derived endpoints under /profile/. View your activities and training history. Includes tests, traces, thresholds and training analyses. Training analysis may use your wellness data.
activities:write Uploads, app metadata, tests, traces, markers and max efforts: creating, changing and deleting them. Upload activities and record tests.
wellness:read Every daily measure except the menstrual cycle day: GET /api/v1/dailies/{measure}. View your sleep, HRV and other daily wellness. Includes body composition. Does not include menstrual cycle data.
wellness:write Recording and deleting those measures. Record your daily wellness.
reproductive_health:read GET /api/v1/dailies/menstrual_cycle_day. Standalone: it neither needs nor implies wellness. View your menstrual cycle.
reproductive_health:write Recording and deleting the cycle day. Record your menstrual cycle.
workouts:read The user's scheduled workouts. See your planned workouts.
workouts:write Scheduling, changing and deleting workouts, which sends them to the user's connected devices. Plan workouts and send them to your devices.
sharing:read Who shares data with the user and whom the user shares with: the users and teams listings, team rosters, and POST /api/v1/oauth/delegated-token. Act for the people who share their data with you. Includes seeing whom you share your own data with.
sharing:write Creating, updating and deleting managed accounts, and authorizing or revoking a team. Change who you share with, and manage or delete accounts you created.
openid sub on userinfo and the ID token. Sign you in with your SweatStack account.
profile The name claims: name, given_name, family_name. See your name.
email email on userinfo. See your email address.
offline_access A refresh token for PKCE clients. Clients with a client secret always get one. Stay connected until you disconnect.

The text in italics is behind the line, one tap away. Both verbs of one category read as one line ("View and upload your activities and training history"), and profile with email as "See your name and email address".

Every endpoint's scope is in the API reference, and a 403 names the scope the token lacks.

A few endpoints need a valid token and no scope: GET /api/v1/profile/status, POST /api/v1/portal/sessions and GET /api/v1/oauth/principal-token.

What the training analysis reveals

A model may use any value the user stored. What your app can see is what the consent line names. The metabolic map and the zones use the user's body mass and resting heart rate, and they do not echo them: there is no inputs field. Two values are nevertheless derivable from activities:read alone, because the sport's own units need them; the consent line says that training analysis uses wellness data, and this is the exact list:

  • Body mass, from the VO2max the map publishes both absolute (mL/min) and relative to body mass (mL/kg/min).
  • Resting heart rate, from heart-rate zones, which are cut on heart-rate reserve.

Nothing else about the user's wellness is derivable through an activities endpoint, on any date. Body composition, sleep, heart-rate variability and stress may steer a model and never come back out. The menstrual cycle day and the email address are never exposed through any other scope, in any form. If you find a wellness value reachable through an activities endpoint that is not one of the two above, tell us: we treat it as a vulnerability.

Purposes

For every category your app requests, except the identity scopes openid and profile and offline_access, you write one sentence under Data your app uses on your app's Consent screen tab: why your app needs it. The user reads it on the consent screen behind the category's line, as "Purpose given by your app", in quotes. One purpose per category, 20 to 160 characters, plain text, no links.

Purposes are optional while only you connect to your app. Once anyone else can (your app is public), a request for a category without a purpose shows the user an "isn't released yet" page instead of the consent screen, which sends them back to your redirect URI with error=access_denied. You never meet that page: your own consent screen names the categories that would send everyone else there. The preview beside the form shows your purposes as the user will read them. What makes a good purpose.

When your app asks for a scope the user has not granted yet, the consent screen shows only the new lines, with what they already allowed listed below. On consent, the grant becomes the union of old and new. A later request for fewer scopes never removes any: two flows of one app cannot cancel each other's grant, and a refresh token minted by either keeps its scopes. The user revokes your app as a whole, under Privacy.

Acting for someone else

A delegated token (a coach for an athlete, a manager for a managed account) never carries more than the token it was minted from, and never email, sharing or offline_access. For a consented grant it carries the grant intersected with your token; for a managed account it carries your token minus those three. openid and profile ride with every grant, so userinfo works on a delegated token and returns the athlete's id and name, never their email. The endpoints are in the quick reference.

Before October 2026: data:read and data:write

Until plan 077 shipped, every app requested one of two bundles. They are retired. An app registered before the release may keep sending them until the end of the window named in the changelog; a request that carries one is read as the categories the bundle reached:

You send SweatStack reads
data:read activities:read wellness:read reproductive_health:read workouts:read sharing:read
data:write activities:write wellness:write reproductive_health:write workouts:write sharing:write
profile together with a bundle openid profile email sharing:read sharing:write

A request without a bundle is taken as it is, so profile on its own means the name only, as OpenID says; add email for the address. Your app announces its move by dropping the bundle. An app registered after the release gets invalid_scope for a bundle. Tokens and refresh tokens issued before the release keep working: grants were translated in place, so no user re-consents.

To move off a bundle without turning anyone away, follow the box on your app's Overview tab, in this order:

  1. On the Consent screen tab, tick only the data your app uses, and write a purpose for each category.
  2. Change the scope your code sends to the scope string the box shows. Its Copy button works only once every category has a purpose: a request for a category without one turns away everyone but you.