Skip to content

Create (or reuse) a public share link for a session

POST
/api/sessions/{id}/share/
curl --request POST \
--url http://localhost:8000/api/sessions/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/share/ \
--header 'Authorization: Bearer <token>'

Issues a public, token-gated URL for the session report — anyone with the link sees the same data the coach sees, 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 the ?lang= query param (clamped to en / ru / es, default en); the public coaching stream then always renders in that language regardless of the recipient’s browser locale — re-sharing after switching language flips the link to the new one. Expired tokens are kept as audit trail and a new token is minted alongside. Use to share reports with athletes, parents, physios, etc.; revoke with DELETE /api/sessions/<id>/share/ — NOT DELETE /api/sessions/<id>/, which this said before #1777 and which deletes the session itself. Read the shared report via GET /api/shared/<token>/.

409 session_not_completed unless the session has finished analysis — minting a public link to a pending / processing session would expose an incomplete (Score 0) report.

id
required
string format: uuid
lang
string

Active UI language (en / ru / es) to freeze on the share. The public AI coaching paragraph will always render in this language. Defaults to en when omitted or unrecognised.

Media typeapplication/json
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 (/r/<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. null only on links minted before the TTL landed (#1400).

string format: date-time
nullable
locale
required

Language frozen on this share (en / ru / es). The public shared coaching stream renders the AI paragraph in this locale regardless of the recipient’s browser settings. Re-issuing the share with a different ?lang= re-stamps it.

string
Examples
ExampleActiveShareLink

Active share link

{
"token": "kQ8r2v9xT1mWp0aZ7nLcYbE3",
"url": "/r/kQ8r2v9xT1mWp0aZ7nLcYbE3",
"expires_at": "2027-03-15T10:22:00Z",
"locale": "en"
}
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
Examplegenerated
{
"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
Example404—NoSuchSessionOnThisTeam

Absent, or owned by another team (collapsed to 404)

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

409 — the request conflicts with current state. detail is a stable code (e.g. reanalyze_in_flight, already_on_plan, email_in_use). Some 409s carry extra context fields alongside detail; those are documented on the specific endpoint that emits them.

string
Examples
Example409—SessionAnalysisNotComplete

PDF / Share rejected while the session is still pending or processing

{
"detail": "session_not_completed"
}