This API provides programmatic access to leaderboard rankings, player statistics, and match history for the SlugBot PvP Leaderboard system.
Base URL
https://api.slugbot.xyz/pvplb/{server_id}/{leaderboard_id}
server_id: ID of the Discord server the leaderboard is in.- The user tied to the API key must be a member of this server to have access to the leaderboard data.
leaderboard_id: The name of the leaderboard. Special characters must be URL encoded.
Authorisation
A valid API key must be provided in the Authorization header:
Authorization: Bearer {API_KEY}
Note: An API key can be generated using the command api get_new_key in any Discord server with SlugBot.
Error Codes
All error responses return a JSON body in the form:
{
"error": "Not Found",
"message": "Could not find match with ID: 6961335332de57bd419e3b16"
}error: The standard HTTP reason phrase for the status code.message: A specific description of what went wrong.
| Status | Meaning |
|---|---|
| 400 | The match ID is not in a valid format (must be a MongoDB ObjectId). |
| 401 | The Authorization header is missing or malformed. |
| 403 | The API key is invalid, the key’s user is not a member of the target server, or the endpoint requires higher permissions (e.g. ladder admin for Declare Match Result). |
| 404 | The match, player, or path was not found. |
| 409 | The match is already completed and cannot be updated (Declare Match Result). |
| 422 | The declaration body is malformed (Declare Match Result). |
| 500 | An internal server error occurred. |
Player Endpoints
Get Player Stats
Retrieves leaderboard statistics for a single player.
- URL:
/player/{player_id} - Method:
GET - Path Parameters:
player_id(string): The Discord User ID of the player. For teams, use the team’s leaderboard ID (theuserIdreturned in batch responses), not a member’s Discord ID.
- Returns
404if the player has no data on this leaderboard.
Example
https://api.slugbot.xyz/pvplb/123123123123123123/test%20lb/player/2290978510728123123
Example response:
{
"userId": "2290978510728123123",
"guildId": "123123123123123123",
"leaderBoardId": "test lb",
"displayName": "Narcolept",
"members": ["2290978510728123123"],
"rank": 1,
"matchesPlayed": 8,
"matchesWon": 7,
"points": 30.10524021259957,
"decayedPoints": 0,
"elo": 1029.0332436228407,
"lastMatchPlayedAt": 1767985291309
}Response fields:
teamLeaderId: Discord ID of the team leader. Present on team entries only.members: Discord User IDs of all members of the entry (a single ID for solo players).rank: The player’s stored rank. Omitted if no rank has been recorded yet.lastMatchPlayedAt: Unix timestamp in milliseconds.- All other fields are self-explanatory.
Get All Players (Batch)
Retrieves a paginated list of all ranked participants on the specified leaderboard.
- URL:
/player/batch - Method:
GET - Query Parameters:
limit(number): Maximum number of records to return. Defaults to 10, capped at 500.nextCursor(number): The rank of the last player on the previous page.
- Results are sorted by rank, starting from 1.
- Only players with a recorded rank appear in this list. New players without a rank are excluded.
- Each item in
datais the same player object returned by Get Player Stats.
Example
https://api.slugbot.xyz/pvplb/123123123123123123/test%20lb/player/batch?limit=3
Example Response:
{
"success": true,
"data": [{...}, {...}, {...}],
"paging": {
"nextCursor": 3,
"hasNextPage": true
}
}Match Endpoints
Get Match Info
Retrieves match info on a specific match.
- URL:
/match/{match_id} - Method:
GET - Path Parameters:
match_id(string): The unique identifier for the match (MongoDB ObjectId).
- Returns
400if the ID is not in a valid format, and404if no match with that ID exists on the leaderboard.
Example
https://api.slugbot.xyz/pvplb/123123123123123123/test%20lb/match/6961335332de57bd419e3b16
Example response:
{
"matchId": "6961335332de57bd419e3b16",
"guildId": "123123123123123123",
"leaderBoardId": "test lb",
"timestamp": 1767985291309,
"rankRangeLimit": -1,
"platformLimit": [],
"regionLimit": [],
"isResolvePending": false,
"declaredResults": {
"team0": [1, 0],
"team1": [0, 1]
},
"winTeam": 0,
"participants": [
{
"teamId": 0,
"playerId": "2290978510728123123",
"initialRank": 1,
"initialPoints": 29.61793872377991,
"initialElo": 1022.40341488487301,
"pointsReceived": 0.4873014888196579,
"eloReceived": 4.623613044190915,
"pointDecayRegened": 0
},
{
"teamId": 1,
"playerId": "460530474897567567",
"initialRank": 2,
"initialPoints": 15.58222222222222,
"initialElo": 994.40341488487301,
"pointsReceived": 0.2222222222222221,
"eloReceived": -4.623613044190915,
"pointDecayRegened": 0
}
]
}Response fields:
timestamp: Unix timestamp in milliseconds.rankRangeLimit,platformLimit,regionLimit: Restrictions the match was created with.-1/ empty arrays mean no restriction.isResolvePending:trueonce both teams have declared matching results and the match is waiting to be resolved.declaredResults: The score each team declared, in[own score, opponent score]form. Values arenulluntil that team declares.winTeam: The outcome of the match (see table below).participants: Per-player stats for the match.initialRank,initialPoints,initialElo: The player’s stats at the time the match started.pointsReceived,eloReceived,pointDecayRegened: The rewards applied when the match completed.- While a match is incomplete (
winTeamis-1), all of these stat fields arenull.
winTeam values:
| Value | Meaning |
|---|---|
| -1 | Incomplete, no winner yet |
| 0 | Team 0 won |
| 1 | Team 1 won |
| 2 | Draw |
Get Match History (Batch)
Retrieves a paginated list of matches for the leaderboard. Includes filters for specific users or match status.
- URL:
/match/batch - Method:
GET - Query Parameters:
userId(string): Filter history to matches the player accepted.complete(boolean): Include finished matches.incomplete(boolean): Include ongoing/pending matches.limit(number): Maximum number of records to return. Defaults to 10, capped at 50.nextCursor(number): The timestamp of the last match on the previous page.
- Results are sorted by timestamp, newest first.
- Leaving both
completeandincompleteunset (or setting both totrue) applies no status filter and returns all matches. - Each item in
datais the same match object returned by Get Match Info.
Example
https://api.slugbot.xyz/pvplb/123123123123123123/test%20lb/match/batch?limit=3&userId=2290978510728123123&complete=true&incomplete=false
Example Response:
{
"success": true,
"data": [{...}, {...}, {...}],
"paging": {
"nextCursor": 1748195916815,
"hasNextPage": true
}
}Note: This query will return completed matches played by user 2290978510728123123
Declare Match Result
Submits a score declaration for a team in an ongoing match. Both teams must declare matching results before the match completes.
- URL:
/match/{match_id}/declare - Method:
POST - Permissions: The API key’s user must be a ladder admin (whitelisted for the
laddercommand in the target server). - Body (JSON):
{
"teamIndex": 0,
"result": [1, 0]
}teamIndex(number): The index of the team making the declaration (0or1).result(number[]): The declared score in[own score, opponent score]form. Both values must be non-negative numbers.- Returns
409if the match is already completed, and422if the declaration is malformed. - Returns the updated match object on success.
Pagination Logic
Both /batch endpoints use cursor-based pagination.
- Initial Request: Leave the
nextCursorparameter empty. - Handling Response: The API will return a list of items and a
pagingobject containing anextCursornumber and ahasNextPageboolean. - Subsequent Request: Pass that number into the
nextCursorquery parameter to fetch the next page of results. IfhasNextPageisfalse, you have reached the end of the data. Note:hasNextPageistruewhenever the page came back full, even if no more data exists. A final request may return an emptydataarray.
Rate Limiting
All endpoints are rate limited per IP address:
- Rate: 10 requests per second.
- Exceeding the limit returns a
429 Too Many Requestsresponse.