The cards the signed-in person can open
const url = 'http://localhost:8000/api/portal/cards/';const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url http://localhost:8000/api/portal/cards/ \ --header 'Authorization: Bearer <token>'Every client card the account holds an active grant on, oldest first — the portal’s card switcher. A card whose team’s plan ended or whose athlete is now a minor is listed too: opening it answers 403 access_ended with the reason. Avatars and logos are signed for two hours. 404 while client access is switched off; a partner API key gets 403; 429 past the account’s rate (client_portal, 120/min).
Authorizations
Section titled “Authorizations”Responses
Section titled “Responses”GET /api/portal/cards/.
object
One card the person can open in the portal (PortalCard).
object
The athlete’s photo, signed for two hours; empty when there is none.
The team’s own logo for the portal header (S5), signed for two hours; null when the team set none — the deployment’s brand shows instead.
athlete- Athleteguardian- Parent or guardian
view- Viewcontribute- Contribute
The person’s unread messages on the card’s conversation.
Whether the card opens now. False: opening it answers the inactive_reason page. /api/portal/cards/ lists the active cards first. A revoked grant is not listed at all.
Examples
One card
{ "results": [ { "client_id": "a1f1c0a2-0000-4000-8000-0000000000aa", "client_name": "Sofia Lebedeva", "avatar_url": "", "team_name": "North Track Academy", "team_logo_url": null, "relation": "guardian", "level": "view", "unread_count": 0, "active": true, "inactive_reason": null } ]}object
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).
Example generated
{ "detail": "example"}object
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).
Example generated
{ "detail": "example"}object
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).
Example generated
{ "detail": "example"}object
429 — throttled: this account’s (or address’s) rate for the route is used up; try again after wait seconds, which Retry-After repeats. A route with a limit of its own answers its own code instead, documented there.
With throttled: whole seconds until the next request can pass.
Example generated
{ "detail": "example", "wait": 1}