Skip to content

Create (or reuse) a public share link for a Solution run

POST
/api/solutions/runs/{run_id}/share/
curl --request POST \
--url 'http://localhost:8000/api/solutions/runs/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/share/?audience=athlete' \
--header 'Authorization: Bearer <token>'

Issues a public, token-gated URL for the run’s report — anyone with the link sees a read-only copy, no auth required. Reuses the most recent active token rather than minting a fresh one on every call (the URL the coach sent yesterday keeps working). Each call (re-)stamps the share’s locale from ?lang= (clamped to en / ru / es, default en); the public report + its AI paragraph then render in that language regardless of the recipient’s browser locale. Read the shared report via GET /api/solutions/shared/<token>/.

One link per audience tier (#2040): ?audience= picks the tier of the link (default: the run’s own). The reuse above is within one tier — a share in another tier returns ANOTHER token, so the link already sent keeps answering the report it was sent as.

403 guardian_consent_required when the athlete (any athlete, for a share that covers several) is under 18 and has no parent’s or guardian’s consent on record. Record it on the client (guardian_consent) first.

run_id
required
string format: uuid
audience
string
Allowed values: athlete coach practitioner

The tier this link shows (#2040), frozen for its life. Defaults to the run’s own tier; an unknown value is a 400.

lang
string

Active UI language (en / ru / es) to freeze on the share. Defaults to en when omitted or unrecognised.

units
string

Active unit system (metric / imperial) to freeze on the share so the public report + PDF render as the coach sees them (#1042). Defaults to metric when omitted.

Media typeapplication/json

POST /api/solutions/runs/<id>/share/ — a public, token-gated link to the run’s read-only report. Mirrors the Sessions / Clients share response shape (issue #695).

object
token
required

Opaque, URL-safe share token. Treat as a secret — anyone with it can read the report.

string
url
required

Relative public path (/solutions/shared/<token>). Prefix with your web origin to share.

string
expires_at
required

ISO-8601 UTC expiry — SHARE_LINK_TTL_DAYS out (30 by default), re-stamped to a full window on every re-share, past which the public route returns 410. Never null: every link expires (#2754).

string format: date-time
locale
required

Language frozen on this share (en / ru / es). The public report + its AI paragraph render in this locale regardless of the recipient’s browser settings. Re-sharing with a different ?lang= re-stamps it.

string
audience
required

The tier this link shows, frozen for its life (#2040). A share in another ?audience= returns a different link; the one already sent keeps answering the report it was sent as.

  • practitioner - practitioner
  • coach - coach
  • athlete - athlete
string
Allowed values: practitioner coach athlete
reader_mode
required

Reader mode frozen on this share (#2867): whose words the public report and its AI are written in. Re-sharing in the other mode re-stamps it, like locale.

  • coach - Coach
  • amateur - Amateur
string
Allowed values: coach amateur

Examples

ExampleALinkInTheAthleteTier

Frozen for its life; a share in another tier returns another link

{
"token": "q4Lw0bX2mY7tR1sKcN8vA3fZ",
"url": "/solutions/shared/q4Lw0bX2mY7tR1sKcN8vA3fZ",
"expires_at": "2026-11-20T09:30:00Z",
"locale": "en",
"audience": "athlete",
"reader_mode": "coach"
}
Media typeapplication/json
object
detail
required

Human-readable message, or a stable machine code for the cases a client branches on. The standard envelope for 400 (validation — a field-keyed object may appear instead), 401 (missing / invalid credentials), 403 (authenticated but not permitted), and 404 (absent — cross-team records are collapsed to 404 so the API never leaks the existence of another team’s data).

string

Example generated

{
"detail": "example"
}
Media typeapplication/json
object
detail
required

Human-readable message, or a stable machine code for the cases a client branches on. The standard envelope for 400 (validation — a field-keyed object may appear instead), 401 (missing / invalid credentials), 403 (authenticated but not permitted), and 404 (absent — cross-team records are collapsed to 404 so the API never leaks the existence of another team’s data).

string

Example generated

{
"detail": "example"
}
Media typeapplication/json
object
detail
required

Human-readable message, or a stable machine code for the cases a client branches on. The standard envelope for 400 (validation — a field-keyed object may appear instead), 401 (missing / invalid credentials), 403 (authenticated but not permitted), and 404 (absent — cross-team records are collapsed to 404 so the API never leaks the existence of another team’s data).

string

Examples

Example403—AthleteUnder18WithoutAGuardian'sConsent

403 — Athlete under 18 without a guardian's consent

{
"detail": "guardian_consent_required"
}
Media typeapplication/json
object
detail
required

Human-readable message, or a stable machine code for the cases a client branches on. The standard envelope for 400 (validation — a field-keyed object may appear instead), 401 (missing / invalid credentials), 403 (authenticated but not permitted), and 404 (absent — cross-team records are collapsed to 404 so the API never leaks the existence of another team’s data).

string

Example generated

{
"detail": "example"
}