Activities
An activity is one training ride, run, swim, or race. Each activity belongs to an athlete and can carry a nutrition prescription and post-activity feedback. Whatever your platform calls these (workouts, sessions, events), the Saturday object is an activity, and every field and route below uses that word.Activity lifecycle
- Create the activity with type and duration, plus intensity and thermal stress if you have them.
- Calculate a nutrition prescription for it.
- Submit feedback afterward, if you collect it.
Creating an activity
Activity fields
Create accepts these fields and no others. There is no field for a display name or a scheduled start time; keep those on your side and join on
external_id.
external_id is worth sending. Saturday’s hosted onboarding finish screen uses it to deep-link the athlete back into the matching activity in your app.
Multi-sport activities
Each activity carries onetype, and Saturday prescribes for that type: an athlete fuels differently on the bike than on the run. For a triathlon or a brick, create one activity per leg.
To work out which legs a multi-sport title implies, use POST /v1/infer/brick-types.
Calculating a prescription
/v1/nutrition/calculate:
- Full tier (subscribed, covered, or in-trial athletes):
tier: "full"with theprescriptionobject (carb, sodium, and fluid totals and per-hour rates), stored on the activity. Trial responses also carrytier_source: "trial",trial_ends_at, andtrial_calls_remaining_today. Each calculation debits the trial’s daily call allowance, exactly like nutrition calculate. - Teaser tier:
tier: "teaser"with per-hour ranges (carb_range_g_per_hr,sodium_range_mg_per_hr,fluid_range_ml_per_hr), asubscription_ctacarrying the athlete’s subscribe link, and required attribution. Nothing is stored, soGET .../prescriptionkeeps returning the last full-tier result if there was one.
safety metadata is included on every tier.
Getting a stored prescription
calculated_at is a Unix timestamp in seconds, not an ISO 8601 string. Timestamps across the athlete and activity objects (created_at, updated_at) use the same encoding.
The
{prescription, safety} envelope is the same on every Saturday endpoint that returns prescription data. Read prescription.* for values and safety.* for guardrails. The not_instructions: true flag marks these as recommendations for a person to consider, not commands to execute.Getting an activity with prescription
Listing activities
limit defaults to 50 and is clamped to 1-200; pass pagination.next_cursor back as cursor for the next page. There are no date-range or type filters; filter on your side, or track activities by external_id.
Submitting feedback
Record how the fueling went:Feedback fields
Feedback is stored on the activity and returned with it on read, so your UI can show an athlete what they said last time and a coach can review a block of training. It does not currently feed back into the calculation: prescriptions come from the athlete’s profile and the activity’s parameters, and a rated activity does not change the next one. Update the profile fields to change future prescriptions.
Activity type inference
If your platform has activity metadata but not a clean type, Saturday can infer one:type is one of the seven activity keys or "unknown". Inference never fails the request: when the model is unavailable or the evidence is too thin, you get "unknown" with confidence: 0, so branch on the type rather than on an error.
Sending more than a title sharpens the result. The endpoint also reads pre_activity_comment, workout_type (your provider’s own coarse type), velocity in m/s, has_power, and cadence, and those structured signals resolve most cases before the model is consulted.
For multi-sport titles like “Bike/run brick”, use POST /v1/infer/brick-types. It returns sub_types (for example ["bike", "run"]) with a single confidence, and you create one activity per leg.