Skip to main content

Results & Leaderboards

The Results & Leaderboards APIs provide access to real-time tournament rankings, final results, prize distributions, and historical tournament data for casino operators.

Real-time Leaderboards

Get Tournament Leaderboard

Retrieve current tournament rankings and player positions:
GET /api/tournaments/{tournamentId}/leaderboard
Authorization: Bearer {your-api-key}
Query Parameters:
  • limit - Number of players to return (default: 50, max: 200)
  • offset - Pagination offset
  • includeEliminated - Include eliminated players (default: false)
Response:
{
  "tournamentId": "12345",
  "status": "in_progress",
  "currentRound": 3,
  "totalRounds": 5,
  "lastUpdated": "2024-01-15T20:25:30Z",
  "leaderboard": [
    {
      "position": 1,
      "playerId": "tp_player_456",
      "displayName": "PlayerName",
      "points": 2150,
      "status": "active",
      "entryCount": 2,
      "totalPaid": 20.00,
      "currentRound": 3,
      "lastActivity": "2024-01-15T20:24:45Z"
    },
    {
      "position": 2,
      "playerId": "tp_player_789",
      "displayName": "TopPlayer",
      "points": 1980,
      "status": "active",
      "entryCount": 1,
      "totalPaid": 10.00,
      "currentRound": 3,
      "lastActivity": "2024-01-15T20:25:20Z"
    }
  ],
  "pagination": {
    "total": 67,
    "limit": 50,
    "offset": 0,
    "hasMore": true
  },
  "prizePool": {
    "totalAmount": 870.00,
    "distribution": {
      "1st": 435.00,
      "2nd": 261.00,
      "3rd": 174.00
    }
  }
}

Live Leaderboard Updates

For real-time leaderboard updates, use polling or WebSocket connections:
class LiveLeaderboard {
  constructor(tournamentId, apiKey) {
    this.tournamentId = tournamentId;
    this.apiKey = apiKey;
    this.updateInterval = null;
    this.lastUpdate = null;
  }
  
  startPolling(intervalMs = 5000) {
    this.updateInterval = setInterval(async () => {
      try {
        await this.updateLeaderboard();
      } catch (error) {
        console.error('Leaderboard update failed:', error);
      }
    }, intervalMs);
  }
  
  async updateLeaderboard() {
    const url = `/api/tournaments/${this.tournamentId}/leaderboard`;
    const params = this.lastUpdate ? `?since=${this.lastUpdate}` : '';
    
    const response = await fetch(`${url}${params}`, {
      headers: {
        'Authorization': `Bearer ${this.apiKey}`
      }
    });
    
    if (response.ok) {
      const leaderboard = await response.json();
      this.onLeaderboardUpdate(leaderboard);
      this.lastUpdate = leaderboard.lastUpdated;
    }
  }
  
  onLeaderboardUpdate(leaderboard) {
    // Update UI with new leaderboard data
    this.displayLeaderboard(leaderboard.leaderboard);
    this.updatePrizePool(leaderboard.prizePool);
  }
  
  stopPolling() {
    if (this.updateInterval) {
      clearInterval(this.updateInterval);
      this.updateInterval = null;
    }
  }
}

Final Tournament Results

Get Tournament Results

Retrieve complete tournament results after completion:
GET /api/tournaments/{tournamentId}/results
Authorization: Bearer {your-api-key}
Response:
{
  "tournamentId": "12345",
  "name": "Daily Championship",
  "status": "completed",
  "startTime": "2024-01-15T20:00:00Z",
  "endTime": "2024-01-15T21:15:30Z",
  "duration": 4530,
  "gameSlug": "crash-classic",
  "totalPlayers": 87,
  "totalRounds": 5,
  "prizePool": {
    "totalAmount": 870.00,
    "currency": "USD",
    "entryFees": 870.00,
    "operatorFee": 87.00,
    "netPrizePool": 783.00
  },
  "winners": [
    {
      "position": 1,
      "playerId": "tp_player_456",
      "displayName": "ChampionPlayer",
      "finalScore": 2150,
      "entryCount": 2,
      "totalPaid": 20.00,
      "prizeAmount": 391.50,
      "netWinnings": 371.50,
      "survivalTime": 4530,
      "eliminationRound": null
    },
    {
      "position": 2,
      "playerId": "tp_player_789",
      "displayName": "SecondPlace",
      "finalScore": 1980,
      "entryCount": 1,
      "totalPaid": 10.00,
      "prizeAmount": 234.90,
      "netWinnings": 224.90,
      "survivalTime": 4530,
      "eliminationRound": null
    },
    {
      "position": 3,
      "playerId": "tp_player_321",
      "displayName": "ThirdPlace",
      "finalScore": 1750,
      "entryCount": 1,
      "totalPaid": 10.00,
      "prizeAmount": 156.60,
      "netWinnings": 146.60,
      "survivalTime": 4485,
      "eliminationRound": 5
    }
  ],
  "statistics": {
    "averageScore": 1245.5,
    "medianScore": 1150.0,
    "averageSurvivalTime": 2890,
    "totalEntryFees": 870.00,
    "totalRebuys": 23,
    "rebuyRevenue": 230.00,
    "operatorRevenue": 110.00
  },
  "completedAt": "2024-01-15T21:15:30Z"
}

Detailed Player Results

Get individual player performance data:
GET /api/tournaments/{tournamentId}/results/players/{playerId}
Authorization: Bearer {your-api-key}
Response:
{
  "tournamentId": "12345",
  "playerId": "tp_player_456",
  "displayName": "ChampionPlayer",
  "finalResults": {
    "position": 1,
    "finalScore": 2150,
    "prizeAmount": 391.50,
    "netWinnings": 371.50
  },
  "participation": {
    "registeredAt": "2024-01-15T19:30:00Z",
    "entryCount": 2,
    "totalPaid": 20.00,
    "rebuyCount": 1,
    "survivalTime": 4530
  },
  "gameplayStats": {
    "totalRounds": 5,
    "roundScores": [
      { "round": 1, "score": 285, "position": 12 },
      { "round": 2, "score": 520, "position": 8 },
      { "round": 3, "score": 890, "position": 5 },
      { "round": 4, "score": 1450, "position": 3 },
      { "round": 5, "score": 2150, "position": 1 }
    ],
    "bestRoundScore": 660,
    "averageRoundScore": 430,
    "positionProgression": [12, 8, 5, 3, 1],
    "gameActions": {
      "totalActions": 47,
      "successfulCashouts": 23,
      "failedCashouts": 12,
      "cashoutRate": 0.489
    }
  }
}

Prize Pool Information

Get Prize Pool Details

Retrieve current prize pool calculation and distribution:
GET /api/tournaments/{tournamentId}/prize-pool
Authorization: Bearer {your-api-key}
Response:
{
  "tournamentId": "12345",
  "status": "in_progress",
  "currentPlayers": 87,
  "prizePool": {
    "type": "percentage",
    "totalAmount": 870.00,
    "currency": "USD",
    "breakdown": {
      "entryFees": 870.00,
      "rebuyFees": 230.00,
      "totalRevenue": 1100.00,
      "operatorFee": 110.00,
      "netPrizePool": 990.00
    },
    "distribution": {
      "percentages": [50, 30, 20],
      "amounts": {
        "1st": 495.00,
        "2nd": 297.00,
        "3rd": 198.00
      }
    },
    "guaranteedPrize": 500.00,
    "lastUpdated": "2024-01-15T20:25:30Z"
  },
  "playerContributions": {
    "totalEntries": 87,
    "totalRebuys": 23,
    "averageEntriesPerPlayer": 1.26
  }
}

Prize Pool Calculations

// Calculate prize distribution
const calculatePrizeDistribution = (totalPrizePool, distribution, guaranteedPrize) => {
  const actualPrize = Math.max(totalPrizePool, guaranteedPrize);
  const prizes = {};
  
  distribution.forEach((percentage, index) => {
    const position = index + 1;
    const amount = (actualPrize * percentage) / 100;
    prizes[`${position}${getOrdinalSuffix(position)}`] = amount.toFixed(2);
  });
  
  return prizes;
};

const getOrdinalSuffix = (position) => {
  const suffixes = ['th', 'st', 'nd', 'rd'];
  const v = position % 100;
  return suffixes[(v - 20) % 10] || suffixes[v] || suffixes[0];
};

Historical Tournament Data

List Tournament Results

Retrieve historical tournament results with filtering:
GET /api/tournaments?status=completed&gameSlug=crash-classic&limit=20
Authorization: Bearer {your-api-key}
Query Parameters:
  • status - Filter by status (completed for results)
  • gameSlug - Filter by game type
  • startDate - Results from tournaments starting after date
  • endDate - Results from tournaments starting before date
  • minPlayers - Minimum player count
  • limit - Results per page (default: 50, max: 100)
  • offset - Pagination offset
Response:
{
  "tournaments": [
    {
      "tournamentId": "12345",
      "name": "Daily Championship",
      "gameSlug": "crash-classic",
      "status": "completed",
      "startTime": "2024-01-15T20:00:00Z",
      "endTime": "2024-01-15T21:15:30Z",
      "duration": 4530,
      "totalPlayers": 87,
      "prizePool": 870.00,
      "winner": {
        "playerId": "tp_player_456",
        "displayName": "ChampionPlayer",
        "prizeAmount": 391.50
      }
    }
  ],
  "pagination": {
    "total": 156,
    "limit": 20,
    "offset": 0,
    "hasMore": true
  },
  "aggregateStats": {
    "totalTournaments": 156,
    "totalPlayers": 13542,
    "totalPrizePool": 135420.00,
    "averagePlayersPerTournament": 86.8
  }
}

Player Tournament History

Get a player’s tournament participation history:
GET /api/players/{playerId}/tournaments?status=completed&limit=10
Authorization: Bearer {your-api-key}
Response:
{
  "playerId": "tp_player_456",
  "tournaments": [
    {
      "tournamentId": "12345",
      "name": "Daily Championship",
      "gameSlug": "crash-classic",
      "participatedAt": "2024-01-15T19:30:00Z",
      "result": {
        "position": 1,
        "finalScore": 2150,
        "prizeAmount": 391.50,
        "netWinnings": 371.50
      },
      "participation": {
        "entryCount": 2,
        "totalPaid": 20.00,
        "survivalTime": 4530
      }
    }
  ],
  "playerStats": {
    "totalTournaments": 24,
    "totalWinnings": 1248.50,
    "totalSpent": 890.00,
    "netProfit": 358.50,
    "averagePosition": 12.3,
    "winRate": 0.125,
    "bestResult": {
      "position": 1,
      "tournamentId": "12345",
      "prizeAmount": 391.50
    }
  }
}

Analytics & Reporting

Tournament Performance Metrics

class TournamentAnalytics {
  constructor(apiKey) {
    this.apiKey = apiKey;
  }
  
  async getTournamentMetrics(tournamentId) {
    const [results, prizePool] = await Promise.all([
      this.getResults(tournamentId),
      this.getPrizePool(tournamentId)
    ]);
    
    return {
      tournament: results,
      performance: {
        participationRate: this.calculateParticipationRate(results),
        playerRetention: this.calculateRetentionRate(results),
        revenueMetrics: this.calculateRevenueMetrics(results, prizePool),
        engagementMetrics: this.calculateEngagementMetrics(results)
      }
    };
  }
  
  calculateParticipationRate(results) {
    const playersWithRebuys = results.winners.filter(w => w.entryCount > 1).length;
    return {
      totalPlayers: results.totalPlayers,
      playersWithRebuys: playersWithRebuys,
      rebuyRate: playersWithRebuys / results.totalPlayers,
      averageEntriesPerPlayer: results.statistics.totalEntryFees / (results.totalPlayers * 10) // Assuming $10 entry
    };
  }
  
  calculateRevenueMetrics(results, prizePool) {
    return {
      totalRevenue: results.statistics.totalEntryFees + results.statistics.rebuyRevenue,
      operatorRevenue: results.statistics.operatorRevenue,
      prizePoolDistributed: prizePool.totalAmount,
      operatorMargin: results.statistics.operatorRevenue / (results.statistics.totalEntryFees + results.statistics.rebuyRevenue),
      revenuePerPlayer: results.statistics.operatorRevenue / results.totalPlayers
    };
  }
}

Real-time Result Streaming

class ResultsStreamer {
  constructor(tournamentId, apiKey) {
    this.tournamentId = tournamentId;
    this.apiKey = apiKey;
    this.eventSource = null;
  }
  
  startStreaming(onUpdate) {
    const url = `/api/tournaments/${this.tournamentId}/results/stream`;
    
    this.eventSource = new EventSource(url, {
      headers: {
        'Authorization': `Bearer ${this.apiKey}`
      }
    });
    
    this.eventSource.onmessage = (event) => {
      try {
        const update = JSON.parse(event.data);
        onUpdate(update);
      } catch (error) {
        console.error('Failed to parse result update:', error);
      }
    };
    
    this.eventSource.onerror = (error) => {
      console.error('Results stream error:', error);
    };
  }
  
  stopStreaming() {
    if (this.eventSource) {
      this.eventSource.close();
      this.eventSource = null;
    }
  }
}

// Usage
const streamer = new ResultsStreamer('12345', 'your-api-key');
streamer.startStreaming((update) => {
  if (update.type === 'leaderboard_update') {
    updateLeaderboardUI(update.leaderboard);
  } else if (update.type === 'player_eliminated') {
    showEliminationNotification(update.player);
  }
});

Integration Best Practices

Polling Frequency

Use appropriate polling intervals - 5s for active tournaments, 30s for completed tournaments

Caching Strategy

Cache leaderboard data to reduce API calls and improve user experience

Error Handling

Handle API failures gracefully with fallback data and retry mechanisms

Data Validation

Validate result data consistency before displaying to users

Next Steps