settings you store on your athlete record, which you read with GET /v1/athletes/{athlete_id}/settings (see Athletes).
State machine
Every athlete on your platform is in exactly one sharing state.GET /v1/athletes/{athlete_id} carries it as profile_sharing, and GET /v1/athletes/{athlete_id}/fueling-profile carries it as sharing.
What moves an athlete between states, and the webhook each move sends:
An athlete’s account connects to your athlete record through a Saturday checkout link they open from your platform, or through an exact email match that the athlete confirms from an email Saturday sends to their Saturday address. See Freemium Model, Automatic linking by email.
What the athlete sees
- In the Saturday app. Preferences shows a Partner Sharing card once their Saturday account is connected to at least one partner platform, with one switch per connected platform: “Share my fueling profile with {your platform}”. The line under the switch lists what you see when it is on and says their numbers on your platform stay the same either way. A switch takes effect at once, on or off.
- On Saturday’s hosted onboarding page. The finish screen asks “Let {your platform} see your fueling answers?” when the athlete’s Saturday account is connected to your platform, the athlete is 18 or older, and the account has a verified email address. Yes emails that address a one-tap confirmation, and sharing starts when the athlete taps it. No turns sharing off at once. An athlete who shares sees a Stop sharing button instead.
- Under 18. No switch in the app and no question on the hosted page. You see
off, with the same message as any athlete who has not shared, so a response never reveals an age. - No expiry. Sharing stays on until the athlete turns it off, the accounts are disconnected, or the Saturday account is deleted.
The journey, narrated
1. You create the athlete with their email. They use the Saturday app under the same address. Saturday emails that address asking them to confirm the connection to your platform. Until they confirm,profile_sharing is not_linked.
Your code: nothing. Calculations use what you store.
2. They confirm the connection.
Their Saturday app answers start filling the gaps in what you store, at calculation time. profile_sharing reads off: they have not chosen to share the answers themselves.
Your code: if you want the answers, tell the athlete they can share them with you from the Saturday app or from Saturday’s hosted onboarding page. Do not poll the route.
3. They turn sharing on.
In the app that is one switch. On the hosted page it is Yes and then the link in the email. Either way you receive athlete.profile_sharing_changed, carrying the athlete record with profile_sharing: "on".
Your code: call GET /v1/athletes/{athlete_id}/fueling-profile and store what it returns.
4. They change an answer in the app.
You receive athlete.fueling_profile_updated: the athlete record plus changed_fields, the names of the answers that changed, never their values.
Your code: read the route again for the new values.
5. They stop sharing, or disconnect.
You receive athlete.profile_sharing_changed with profile_sharing at off, or at not_linked when the connection itself went. The route returns no answers from then on.
Your code: stop treating the answers you hold as the athlete’s current Saturday answers. How long you keep what you read is your platform’s call under your privacy policy.
GET /v1/athletes/{athlete_id}/fueling-profile
Returns the athlete’s sharing state, and their Saturday app answers when it ison. Call it with your partner API key, or with an athlete-delegated OAuth token for that same athlete.
200. Switch on sharing, never on the text of message.
Sharing on
Sharing off
Not linked
Response fields
Each
profile entry is an object with value and calculations_use. The names are the calculation-side names (age and athlete_weight_kg, as a calculate request takes them), and concerns holds the eight concern flags in one object:
value is null when the athlete has not answered that question in the app, or holds an answer outside what the app writes. concerns is null when they never answered the concerns question; an object of all false means they answered “none of these”.
calculations_use
value is always the app answer. calculations_use says where the value Saturday’s calculations use for this athlete comes from, field by field:
partner with a value that differs from what you store means the athlete answered differently in the two places. Calculations use yours; the app answer is there if you want to ask the athlete which is right.
Errors
Errors use the standard envelope in Error Handling. An athlete who shares nothing is never an error: that is
200 with sharing set to off or not_linked.
profile_sharing on GET /v1/athletes/{athlete_id}
Reading one athlete returnsprofile_sharing beside subscription_status (the record below is trimmed to the fields that matter here):
sharing. The field is computed on each read of one athlete. It is in the athlete record the two sharing webhooks carry, and not on GET /v1/athletes lists or in the record that athlete.created, athlete.updated and athlete.profile_completed carry. It is absent when Saturday could not read the state on that request; call the fueling-profile route for the answer.
Webhooks
Two events cover sharing. Subscribe to them by name when you register or update a webhook; full payloads are in Webhooks.athlete.profile_sharing_changed:datais the athlete record, asGET /v1/athletes/{athlete_id}returns it, withprofile_sharingshowing the new state.athlete.fueling_profile_updated:datais the same record pluschanged_fields, the names of the shared answers that changed. Sent only while sharing stays on.
data names the athlete in id, not athlete_id.
A webhook is a cue to read the route, which is the source of truth. If one Saturday account is connected to more than one of your athlete records, each record gets an event.
MCP
Partner MCP connections get aget_fueling_profile tool taking athlete_id, which returns this route’s response. get_athlete carries profile_sharing, so an agent knows when to call it. See MCP Integration.