Scopes
#Scopes
A client holds one or more scopes, chosen by the club admin when it's created (or changed later). A token
inherits its client's scopes, optionally narrowed with scope= at the token request. Calling an endpoint
without the scope it requires is 403 API_SCOPE_MISSING.
| Scope | Grants | Endpoints |
|---|---|---|
events:read |
the club's published events, event detail, race list | GET /api/v1/events · GET /api/v1/events/{eventId} · GET /api/v1/events/{eventId}/races |
results:read |
race results, event (series) results | GET /api/v1/races/{raceId}/results · GET /api/v1/events/{eventId}/results |
Both are read-only — there is no write scope today. New endpoint families get new scopes as they ship; an existing scope never silently widens to cover new data.
#Checking a token's scopes
Full reference: Check a token.
curl -s https://sail-club-server.cloud.run/api/v1/token-info \
-H "Authorization: Bearer $TOKEN"{ "client_id": "scc_3f9a…", "club_id": "TRX1001CL", "scope": "events:read results:read", "expires_at": "2026-09-30T10:00:00Z" }Any valid token can call this — it needs no scope of its own, and is never rate-limited the way data calls are. Useful for a health check or for debugging "why am I getting 403s."
#Narrowing a request
curl -s -X POST https://sail-club-server.cloud.run/api/v1/oauth/token \
-u "$SAIL_CLUB_CLIENT_ID:$SAIL_CLUB_CLIENT_SECRET" \
-d grant_type=client_credentials -d "scope=events:read"Requesting a scope the client doesn't hold is 400 invalid_scope (API_SCOPE_INVALID). Omitting scope
entirely returns a token with every scope the client has.
#Changing scopes
The club admin can add or remove scopes for a client at any time (Settings → API access → the client → Edit). A removed scope is also removed from the client's live tokens within 60 seconds — you don't need to wait for the token to expire to see the change.