diff --git a/guides/activities.mdx b/guides/activities.mdx index 7ca7779..e5b0e12 100644 --- a/guides/activities.mdx +++ b/guides/activities.mdx @@ -149,7 +149,7 @@ Returns the most recently calculated prescription for this activity, wrapped wit GET /v1/athletes/{athlete_id}/activities/{activity_id} ``` -The activity response carries the stored prescription inline. +The activity response carries the stored prescription inline. An athlete's synced activity read through the [Claude connector](/guides/coach-connector) can also carry `source_attributions`, the credit its data source requires; see [Data source credits](/guides/attribution#data-source-credits). ## Listing activities diff --git a/guides/attribution.mdx b/guides/attribution.mdx index 2a8ea23..af61bc0 100644 --- a/guides/attribution.mdx +++ b/guides/attribution.mdx @@ -73,6 +73,32 @@ Scope it by surface: When your integration also relays a third party's data alongside Saturday's (for example a wearable's device data), honor that source's attribution too. Name the origin, not only the vendor. +[Data source credits](#data-source-credits) below gives you the exact text for every activity Saturday +sends you. + +## Data source credits + +Some of an athlete's activities reach Saturday from a connected app or device whose terms require +credit wherever that data, or anything built from it, is shown. Saturday works out the credit for +you: a response carrying such data has a `source_attributions` array, one line per source. A workout +recorded on a Garmin device, for example, carries `["Garmin Edge 1040"]`, or `["Garmin"]` when the +device model is unknown. The array is absent when no source behind the data requires credit. + +- **Show each line verbatim and untranslated**, beside the activity and beside anything you build from + it: a summary, a chart, a trend, a plan, an AI answer. +- **Keep it visible without interaction**, the same rule as the Saturday mark: never in a tooltip, + footnote, or collapsed panel. +- **Carry it downstream.** An export, a file, or another system you pass the data to keeps the lines + with the data. + +| Surface | Where `source_attributions` appears | +|---|---| +| The athlete's activities through the [Claude connector](/guides/coach-connector) | Each activity from `GET /v1/athletes/{athlete_id}/activities`, `GET` and `PATCH .../activities/{activity_id}`, and the `list_activities` and `get_activity` tools | +| Insights | `GET /v1/athletes/{athlete_id}/insights` and the `get_athlete_insights` tool, for every activity analyzed | +| [Coach API](/guides/coach-api#data-sources) and coach tools | Each rollup and session-detail session, the AI report, and each roster and digest row | +| [Coach webhooks](/guides/coach-api#webhooks) | Each coach concern event, for the sessions it is about | + +Activities a partner creates through the API carry no credit lines: their data is the partner's own. ## How it should look diff --git a/guides/coach-api.mdx b/guides/coach-api.mdx index 81885f6..c6bdc32 100644 --- a/guides/coach-api.mdx +++ b/guides/coach-api.mdx @@ -103,7 +103,7 @@ curl -H "Authorization: Bearer cp_live_..." \ } ``` -The markers come from Saturday's single shared concern definition, so they match the coach portal table and the digest exactly. An athlete who fueled well shows `flagged: false`. +The markers come from Saturday's single shared concern definition, so they match the coach portal table and the digest exactly. An athlete who fueled well shows `flagged: false`. A row computed from sessions whose source requires credit also carries `source_attributions` (see [Data sources](#data-sources)). ### Roster digest (flagged-only) @@ -190,7 +190,9 @@ A session recorded on a connected device names where it came from. | `device_model` | The device model that service reported (for example `ELEMNT BOLT`). Absent when none was reported. | | `source_attributions` | Attribution text a source requires wherever its data, or anything built from it, is shown. Show it verbatim and untranslated beside the session and beside anything you build from it. Absent when no source behind the session requires one. | -The AI report and AI plan responses carry `source_attributions` too, for the sessions the narrative was written from (absent or empty when none requires one). Show them with the narrative. +The AI report and AI plan responses carry `source_attributions` too, for the sessions the narrative was written from (absent or empty when none requires one). Show them with the narrative. So does each roster and digest row, for the sessions its markers and count are computed from. + +A workout recorded on a Garmin device that reached Saturday through another service, such as intervals.icu, carries that service's `source_provider` and a Garmin line in `source_attributions`: `"Garmin Edge 1040"`, or `"Garmin"` when the device model is unknown. [Brand & Attribution](/guides/attribution#data-source-credits) covers how to show these lines. Sessions from some connected services stay on Saturday and are never returned by the Coach API, so no response carries them or anything built from them. A workout recorded by Garmin or COROS alone is withheld; when the same workout also reached Saturday from another service, it comes back with only that other service's details. When an athlete has connected such a service, the fueling rollup, AI report and AI plan responses, and that athlete's roster row, carry a `withheld` object (`kind`: `connected_app_sessions`, plus a `message` to show). Treat the sessions you do get as incomplete: a short list does not mean the athlete trained less. @@ -399,11 +401,14 @@ Each delivery is a `POST` carrying the event name in `X-Saturday-Event-Type` and "value_pct": 0.42, "threshold_pct": 0.6, "detected_at": 1749480000000, - "evaluation": "urgent_scanner" + "evaluation": "urgent_scanner", + "source_attributions": ["Garmin Edge 1040"] } } ``` +`source_attributions` lists the credit the session's sources require, `[]` when none does; an `athlete.needs_attention` event carries the union across its concerns. Show the lines with anything you build from the event. + Each event is delivered once. A non-2xx response or a connection failure is recorded and counts toward the endpoint's `fail_count`; a 2xx resets it, and the endpoint is disabled automatically after 15 consecutive failures. Re-enabling it clears the count. ## Billing (read-only) diff --git a/guides/mcp-integration.mdx b/guides/mcp-integration.mdx index 4f1d977..b72dd38 100644 --- a/guides/mcp-integration.mdx +++ b/guides/mcp-integration.mdx @@ -251,6 +251,7 @@ When building AI agents that consume Saturday via MCP: - **Surface all safety warnings** to the human user - **Present prescriptions as recommendations**, not commands - **Include "Powered by Saturday"** attribution for teaser-tier responses +- **Show `source_attributions` lines** verbatim beside the data they credit and anything built from it ([Data source credits](/guides/attribution#data-source-credits)) - **Cache results** when inputs haven't changed. Prescriptions are deterministic - **Handle errors gracefully.** If a tool call fails, explain why to the user