Skip to content

GetLadderQuery — Reference

Source-of-truth reference for GetLadderQuery: the read-model query that returns competition ladder (standings) data sourced from the FoxSports feed provider. A single query powers both the season ladder (standings as of the current round) and the live ladder (in-round standings that shift as matches complete), selected by one isLive flag. Both variants return the same LadderContract[] shape — the live variant simply populates three extra movement fields.

  • Query / handler: src/Integration/LBS.Fantasy.Integration/Queries/Ladder/ (GetLadderQuery.cs, GetLadderQueryHandler.cs, LadderContract.cs)
  • Feed model: src/DataHarvesters/LBS.Data.Harvester/FoxSports/Models/Ladder.cs
  • Module: requires BallrFoxIntegration ([RequiresModule("BallrFoxIntegration")]).

Query

Endpoint: POST /api/readmodel — the query object is sent inside a query envelope.

{
  "query": {
    "queryType": "GetLadder",
    "sport": "RugbyLeague",
    "isLive": false
  }
}

Via the generated SDK you don't build this by hand: ballrQueries.getLadder({ sport, isLive }) sets queryType: "GetLadder", and authStore.client.query(...) wraps it in the query envelope and POSTs to /api/readmodel. The examples below show only the inner query object for brevity.

Parameter Type Default Description
sport string — (required) Sport key. Only RugbyLeague and Cricket are supported; any other value returns an empty ladder.
isLive bool false false = season ladder (FoxSports detailed feed for the current season). true = live ladder (FoxSports live feed, in-round standings).

There are no other parameters — no paging, no round selector. The feed always returns the full ladder for the sport (one entry per team), already ordered by the provider; sort/render client-side by position if you want to be defensive.

GetLadderQuery is an IPublicCacheableQuery and IRequireUserContext.

Response shape:

The query returns the standard read-model envelope:

{ data: LadderContract[], totalCount, skip }
  • data — one LadderContract per team, ordered by the provider (lowest position first).
  • totalCount — number of ladder entries (equals data.length; there is no server-side paging).
  • skip — always 0.

Behaviour

Supported sports

The handler maps each supported sport to a FoxSports series ID:

Sport FoxSports series ID
RugbyLeague 1
Cricket 9

Any other sport (or a blank sport name) is logged as unsupported and returns an empty ladder.

Live vs. detailed feed

One query, one contract, two feeds — selected by isLive:

View isLive FoxSports endpoint Season resolution When standings change Cache TTL
Season ladder false (default) .../series/{seriesId}/seasons/{seasonId}/detailedladder.json Resolves the current season first (CurrentSeason.GetCurrentSeasonAsync) Once per round 5 min
Live ladder true .../series/{seriesId}/liveladder.json None — the live endpoint has no season segment As matches complete mid-round 30 sec

The only payload difference: the three live-only fields (isLive, previousPoints, previousPosition) are populated only when the request had isLive: true. On the season ladder they are always null. (Conversely the detailed/sport-specific fields are still populated normally on the live feed when the provider supplies them.)

Caching

  • Distinct cache per variant: the cache key is FeedLadder_{Sport}_{Live|Detailed}, so the live and season ladders never collide and can be fetched/cached independently.
  • Season ladder (isLive: false): cached 5 min — it only changes once per round.
  • Live ladder (isLive: true): cached 30 sec — standings shift as matches complete mid-round.
  • Cache tags: ["ladder", <sport>].

Graceful degradation

The handler returns data: [], totalCount: 0 (rather than throwing) when:

  • the sport is blank or unsupported, or
  • the upstream feed is unavailable — an HTTP 404 is caught in Ladder.GetLadderAsync and surfaced as a null ladder, or
  • the payload is missing its round or teams.

Individual teams with no stats block are filtered out before projection. The UI should render an empty / "ladder unavailable" state for an empty data array.


LadderContract fields

One object per team. Many fields are sport-specific and arrive null when not applicable — 0 is a genuine zero, null means "not provided for this sport/feed".

Identity & round context (always present)

Field Type Description
teamId string (TeamId) Canonical Luckbox team ID
name string Full team name (e.g. "Newcastle")
teamLogo string Badge URL, /{teamId}/{shortName-slug}.png
code string Abbreviation (e.g. "NEW")
shortName string Colloquial nickname (e.g. "Knights")
pool string \| null Pool/group label, when the competition is pooled
roundName string Round the ladder reflects (e.g. "Round 12")
roundNumber number Round number
roundShortName string Short round label (e.g. "R12")

Common standings (always present)

Field Type Description
position number Ladder position (1 = top) — primary sort key
played number Matches played
won number Wins
lost number Losses
drawn number Draws
points number Competition points

NRL / RugbyLeague-specific (nullable)

Field Type Description
for number \| null Points scored for
against number \| null Points scored against
difference number \| null Points differential (for - against)
byes number \| null Byes taken
home string \| null Home record (e.g. "5-2")
away string \| null Away record
streak string \| null Current streak (e.g. "W3")
pastFive string \| null Form over last five (summary)
lastFiveResults string \| null Last five results detail (e.g. "WWLWD")

Cricket-specific (nullable)

Field Type Description
netRunRate number \| null Net run rate
quotient number \| null Quotient
tied number \| null Tied matches
noResult number \| null No-result matches
bonusPoints number \| null Bonus points
notes string \| null Free-text notes

Live-ladder-specific (populated only when isLive: true)

Field Type Description
isLive bool \| null true when this row is from the live feed; null on the season ladder
previousPoints number \| null Points before the current in-round movement — diff vs points
previousPosition number \| null Position before the current in-round movement — diff vs position

Movement indicators (live only): compare the current value to the "previous" snapshot to render up/down arrows and point deltas:

const positionDelta = entry.previousPosition != null
  ? entry.previousPosition - entry.position   // > 0 = moved up, < 0 = moved down
  : 0;
const pointsDelta = entry.previousPoints != null
  ? entry.points - entry.previousPoints
  : 0;

Example response

Abridged live-ladder response (isLive: true) for RugbyLeague — note the populated movement fields:

{
  "data": [
    {
      "teamId": "b62bd105-8d29-5ad4-ac67-dca09af0d68a",
      "name": "Newcastle", "code": "NEW", "shortName": "Knights",
      "teamLogo": "/b62bd105-.../knights.png", "pool": null,
      "roundName": "Round 12", "roundNumber": 12, "roundShortName": "R12",
      "position": 3, "played": 11, "won": 8, "lost": 3, "drawn": 0, "points": 16,
      "for": 264, "against": 198, "difference": 66, "byes": 1,
      "home": "5-1", "away": "3-2", "streak": "W3",
      "pastFive": "WWWLW", "lastFiveResults": "WWWLW",
      "netRunRate": null, "quotient": null, "tied": null, "noResult": null,
      "bonusPoints": null, "notes": null,
      "isLive": true, "previousPoints": 14, "previousPosition": 5
      // moved up 2 places (5 -> 3), +2 points (14 -> 16) as its match finished
    }
    // … one entry per team, provider-ordered by position
  ],
  "totalCount": 17,
  "skip": 0
}

On the season ladder (isLive: false) the same shape is returned with "isLive": null, "previousPoints": null, "previousPosition": null.


Summary

View isLive Reads Cache
Season ladder false LadderContract[] (common + sport-specific fields) 5 min
Live ladder true same LadderContract[] + isLive / previousPoints / previousPosition movement fields 30 sec

Both views issue the same getLadder request (just toggling isLive), against separate cache keys, so the live and season ladders are fetched and cached independently.