Skip to content

What the person may send this month

GET
/api/portal/{client_id}/uploads/allowance/
curl --request GET \
--url http://localhost:8000/api/portal/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/uploads/allowance/ \
--header 'Authorization: Bearer <token>'

The coach’s monthly cap (0: uploads are off), this calendar month’s (UTC) uploads whose analysis did not fail, the day the count starts again, and the activities and exercises a clip can be sent as — the team’s own list, filtered by what its plan covers and this server can analyse — with, per exercise, the camera views a send may carry and the recording guide (the coach upload wizard’s), in ?lang.

The Contribute level only: a View grant gets 403 contribute_required.

The signed-in person’s grant on the card in the path. Every route answers 404 while client access is switched off on the environment. 404 card_not_found for a card the account never held — another athlete’s, a card of the account’s own team, or an id that names nothing. 403 access_ended (reason: revoked · team_plan · minor) for a card it held and can no longer open, consent_required when the consent texts changed since the person accepted them (consent again with POST /api/portal/{client_id}/consent/). A partner API key gets 403. 429 past the account’s rate (client_portal, 120/min; the PDFs client_portal_pdf, 20/min).

Only what a coach released is visible, curated on the server: the team’s hidden metrics are absent, the coach’s AI text and internal fields are not sent, and media URLs are signed for two hours.

client_id
required
string format: uuid
lang
string

The guides’ language: en · ru · es (default: the grant’s).

Media typeapplication/json

GET /api/portal/<client_id>/uploads/allowance/ (PortalUploadAllowance).

object
monthly_cap
required

Set by the coach; 0 means uploads are off.

integer
used_this_month
required

This calendar month’s (UTC) uploads whose analysis did not fail.

integer
resets_on
required

The day the count starts again.

string format: date
activities
required

What a clip can be sent as.

Array<string>
exercises
required

Per activity, the exercises it can be sent as (contract change 8); an empty list offers the activity’s default analysis (exercise: "").

object
key
additional properties
Array<string>
views_by_exercise
required

Activity → exercise → the camera views (side, front, back) the analysis takes — the values camera_view may carry on the send; one view: show no picker. The default analysis is keyed "".

object
key
additional properties
object
key
additional properties
Array<string>
guides_by_exercise
required

Activity → exercise → the recording guide in ?lang (else the grant’s language), the coach upload wizard’s: a dict of short texts keyed by part (the same shape as /api/exercises/’s guides_by_exercise). The default analysis is keyed "".

object
key
additional properties
object
key
additional properties
object
key
additional properties
string
guides_by_exercise_view
required

Activity → exercise → camera view → its guide, for the exercises with more than one view: what to show once the view is picked.

object
key
additional properties
object
key
additional properties
object
key
additional properties
object
key
additional properties
string

Examples

ExampleAllowance
{
"monthly_cap": 4,
"used_this_month": 1,
"resets_on": "2026-12-01",
"activities": [
"running"
],
"exercises": {
"running": [
"Treadmill",
"Overground"
]
},
"views_by_exercise": {
"running": {
"Treadmill": [
"side",
"front",
"back"
],
"Overground": [
"side",
"front",
"back"
]
}
},
"guides_by_exercise": {
"running": {
"Treadmill": {
"Camera": "Side or back view; phone on a tripod at waist height, kept still",
"Duration": "15–30 s steady pace (skip warm-up)"
},
"Overground": {
"Camera": "Side view at hip height; the whole stride in frame"
}
}
},
"guides_by_exercise_view": {
"running": {
"Treadmill": {
"side": {
"Camera": "Side view at waist height, kept still"
},
"front": {
"Camera": "Facing the runner at waist height"
},
"back": {
"Camera": "From behind at waist height"
}
}
}
}
}
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

access_ended, consent_required, or DRF’s message for a partner API key.

string
reason

With access_ended: why the card no longer opens — revoked, team_plan or minor.

string
client_name
string
team_name
string
consent_version

With consent_required: the version to accept.

string
kinds

With consent_required: the texts to show.

Array<string>

Examples

Example403—AViewGrant

403 — a View grant

{
"detail": "contribute_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

Examples

Example404—NotACardOfThisAccount

404 — not a card of this account

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

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.

string
wait

With throttled: whole seconds until the next request can pass.

integer
nullable

Example generated

{
"detail": "example",
"wait": 1
}