Skip to main content

Magicweave: Leaderboards

The API supports three integration styles:

  1. Atomic endpoints — fetch one resource at a time (meta, leagues, rewards, entries, users, me).
  2. Preset bundles — common combinations (/overview, /standings, /context).
  3. Mix-and-match hub/bundle?include=... to request any combination of sections in one call.

Legacy GET /{leaderboard_slug} remains available for backward compatibility.

Base Path

  • All routes are under: /leaderboards

Authentication and Authorization

All endpoints require:

  • Client credentials headers:
    • x-client-id
    • x-client-secret
  • A bearer access token in Authorization: Bearer <token>
  • Permission: client.leaderboard

If any requirement is missing or invalid, the API returns 401 or 403.

Shared Query Parameters

These parameters appear on multiple endpoints:

ParameterTypeDefaultDescription
leaguestringLeague slug filter (entries, users, rewards, bundle presets)
limitint100Page size (1..1000)
offsetint0Pagination offset (>= 0)
sourcestringrankedUser list source: ranked or assigned (see User list sources)
expandstringComma-separated expansions; currently profile
includestringComma-separated sections for list/bundle endpoints (see Include tokens)

Include tokens

Used by GET / (list) and GET /{slug}/bundle:

TokenList (GET /)Bundle (GET /{slug}/bundle)
metayesyes
leaguesyesyes
rewardsyesyes
entriesyes
usersyes
meyes

Unknown include values return 400.

User list sources

  • ranked (default) — players with a stat value on the board, ordered by rank. Respects league filter (dynamic stat bands or AT_RESET assignment cohort).
  • assigned — AT_RESET boards only. Paginates PlayerLeagueAssignment rows for the active cycle. Returns 400 on non-AT_RESET boards. Users without a stat may have rank: null and stat_value: null.

Profile expansion

Pass expand=profile on /entries, /users, /standings, /context, or /bundle to attach ClientUserProfileSnippet (nickname, avatar_url) to each row when a client profile exists.

Endpoints

List

  • GET / — List all leaderboards for the current project

Atomic

Presets and bundle

Legacy

  • GET /{leaderboard_slug} — Legacy paginated rankings (no pagination metadata). Prefer /entries for new integrations.

Response Models

ClientPaginationMeta

  • limit: integer
  • offset: integer
  • total: integer — total rows matching the current filter
  • has_more: boolean — true when offset + limit < total

ClientLeaderboardMetaResponse

  • slug, name, sort_order, leaderboard_type, stat_key: strings
  • leagues_enabled, expired: booleans
  • promotion_timing, reset_type: string or null
  • cycle_key, cycle_started_at, cycle_ends_at: present on relative boards with reset_rrule
  • expires_at: datetime or null (absolute boards)

ClientLeagueResponse

  • slug, name: strings
  • min_value, max_value: number or null — half-open band [min, max)
  • promotion_mode, demotion_mode: strings (none, top_ranks, bottom_ranks, stat_percent_from_max, stat_percent_from_min)
  • promotion_rank_count, demotion_rank_count: integer or null
  • promotion_percent, demotion_percent: number or null

ClientRewardResponse

  • reward_trigger: string (promotion, demotion, rank)
  • rank: integer or null (for rank triggers)
  • league_slug: string or null
  • items: list of reward payload objects (currency, gem, stat, etc.)

ClientLeaderboardEntryResponse

Used in /entries and /users responses:

  • rank: integer or null
  • user_id: integer
  • stat_value: number or null
  • league: string or null
  • profile: ClientUserProfileSnippet or null (when expand=profile)

ClientUserProfileSnippet

  • nickname: string
  • avatar_url: string or null

LeaderboardReadResponse (legacy)

  • leaderboard_id, leaderboard_slug, leaderboard_name, sort_order
  • league: string or null
  • expired: boolean
  • entries: list of { rank, user_id, stat_value }

CurrentUserLeaderboardResponse

  • leaderboard_id, leaderboard_slug, leaderboard_name, user_id
  • rank, stat_value, league: nullable
  • expired: boolean

Behavior Notes

  • Project scope is resolved from client credentials; leaderboard slugs are unique per project.
  • Absolute leaderboards reject league filters on entries/users (400).
  • AT_RESET league filtering uses the active cycle's assignment cohort, not live stat bands.
  • Dynamic league boards infer league from stat value bands at read time.
  • Reward payloads mirror the admin-configured bundle items; grants are not exposed on this API.

Error Cases

  • 400 Bad Request
    • Unknown include token
    • Empty include on /bundle
    • source=assigned on a non-AT_RESET board
    • league filter on an absolute leaderboard
  • 401 Unauthorized
    • Missing x-client-id or x-client-secret
    • Invalid client credentials
    • Missing or invalid bearer token
    • Expired token
  • 403 Forbidden
    • Authenticated user does not have client.leaderboard permission
  • 404 Not Found
    • Leaderboard or league slug not found for the current project

cURL Example

curl -X GET "http://localhost:8000/client/leaderboards?include=meta,leagues" \
-H "x-client-id: <your-client-id>" \
-H "x-client-secret: <your-client-secret>" \
-H "Authorization: Bearer <access-token>"