Choosing how athletes connect¶
An app gets athletes' data into SweatStack in one of three ways. They differ in one thing: what your app brings.
| You bring | Layer | SweatStack does | You do |
|---|---|---|---|
| Nothing | Hosted | Connects athletes' platforms (Garmin, Wahoo, Intervals.icu) with its own keys | Send athletes to /oauth/authorize |
| Your keys | Bring your own keys | Connects with your keys, runs the webhooks, backfills and workout push | Get platform keys, register them, point the platform at SweatStack's URLs |
| Your data | Bring your own data | Stores and analyses what you send | Run the platform connection yourself, upload files, post dailies |
Hosted is what every app uses today and the right default: nothing to obtain, one consent screen, and the athlete gets a SweatStack account they can use with other apps too. The other two layers exist for apps that cannot or should not go through SweatStack's keys: an app with its own Garmin agreement (Garmin requires its licensees to use their own keys), an app that already pulls data from platforms SweatStack does not integrate with, or a hardware vendor whose own device produces the files.
How to choose, in three questions:
- Do you have your own agreement with a platform, and does it require you to use your own keys? Bring your own keys for that platform.
- Do you already collect the data yourself, or from a platform SweatStack does not integrate with? Bring your own data.
- Otherwise, Hosted.
You can mix them per platform: hosted Wahoo and email sign-in, your own Garmin keys, your own data from Coros. To bring your own Garmin keys, see Bring your own keys. To bring your own data, create the athlete with the management API below, get a token for them, and relay their files and dailies.
Who owns the athlete¶
With Hosted, the athlete owns their account. It is a SweatStack account: they can sign in at sweatstack.no, connect other apps to it, and delete it. Your app receives a copy of the data they grant it, and you are an independent controller of that copy (the developer terms).
With Bring your own keys and Bring your own data, the athlete's account belongs to your app. SweatStack manages it completely on your behalf: identity, email, sign-in, recovery, data, deletion, so you never build an account system around it. Such a user:
- belongs to exactly one app and is deleted with it;
- signs in to that app only, never to sweatstack.no;
- cannot authorize another app or a team and is never shared;
- connects platforms only through your keys, never through SweatStack's;
- has the same
sub, tokens, data endpoints, webhooks, account status and Portal as a SweatStack account.
You are the controller of these accounts and SweatStack your processor, under the Data Processing Agreement. Their email, if your app gives one, is unverified until the person confirms it through the message SweatStack sends, co-branded with your app.
What is the same everywhere¶
Tokens and their sub, the data endpoints, webhooks, the account status and Portal links: your code reads a user the same way whichever layer they came through. What differs is how the user came into existence and who talks to the platform, and that is exactly the table above.
The management API (beta)¶
Beta
The management API is in beta and is subject to breaking changes. If you plan to use it in production, email [email protected] before you integrate, so we can tell you about changes in advance and help you migrate.
The management API is how your app creates, finds and deletes the users that belong to it, and how it gets a token for one without the athlete present. Your app authenticates with its client credentials, HTTP Basic with the client_id as user name and a client_secret as password, on every call; the same credentials the token endpoint takes. No user token is involved, and a Basic header never authenticates anywhere else.
Before your app can create users, you accept the developer terms and the Data Processing Agreement for it on its Consent screen tab (see Going live); until then the create call answers 403 and says where.
Create a user, with your own reference for them:
curl -u "$CLIENT_ID:$CLIENT_SECRET" \
-X POST https://app.sweatstack.no/api/v1/applications/$CLIENT_ID/users \
-H "Content-Type: application/json" \
-d '{"first_name": "Kari", "last_name": "Nordmann", "email": "[email protected]", "external_reference": "kari-42"}'
The response is the user: id (their sub from now on), the name, email, email_verified, external_reference and registered_at. A second user with the same email or reference in your app answers 409. The same email may belong to a SweatStack account at the same time; that is a different person as far as SweatStack is concerned.
Find your users (GET .../users, filtered with ?email= or ?external_reference=), read one (GET .../users/{user_id}), change a name (PATCH .../users/{user_id}; an email address is changed through support) or delete one and all their data (DELETE .../users/{user_id}, irreversible).
Get a token for one of them:
curl -u "$CLIENT_ID:$CLIENT_SECRET" \
-X POST https://app.sweatstack.no/api/v1/applications/$CLIENT_ID/users/$USER_ID/token
This is exactly what the token endpoint returns after a code exchange: an access token and a refresh token with your app's default scopes on this user. Use it on the data API as any other token, and refresh it at POST /oauth/token with your client credentials. Every token minted this way counts the user as active for billing, like any token.
Deleting your app deletes its users and all their data. The Settings tab says how many go with it and asks for the app's name before it does.
A Portal link for one of these users signs them in: it works once, for a few minutes. The profile destination opens their name and email; manage-teams is not available to them.
The endpoint reference is under App users.
Naming¶
"Bring your own keys" and "BYOK" are both fine. "Bring your own data" is always written in full, so it is not read as "bring your own device". "Keys" means the platform's credentials your app registers with SweatStack; "client credentials" means your app's own SweatStack client_id and client_secret.