Code Examples
Runnable snippets for the common ways people integrate with this API. Every snippet uses the same two placeholders — fill these in before running anything:
API_BASE="https://api.prismsmp.net"
API_KEY="your-api-key-here" # from /api key, in-game
cURL
Health check
curl -s "$API_BASE/api/health" \
-H "X-API-Key: $API_KEY"
Player lookup
curl -s "$API_BASE/api/player/SomePlayer" \
-H "X-API-Key: $API_KEY"
Auction search
curl -s "$API_BASE/api/auction/search?item=netherite&sort=cheap&limit=10" \
-H "X-API-Key: $API_KEY"
Leaderboard
curl -s "$API_BASE/api/leaderboard?type=balance&limit=5" \
-H "X-API-Key: $API_KEY"
Player count
curl -s "$API_BASE/api/players/count" \
-H "X-API-Key: $API_KEY"
JavaScript (Node.js, plain fetch)
No dependencies beyond a Node version with global fetch (Node 18+). This
helper centralizes error handling so every call site gets consistent 404/429 behavior.
const API_BASE = "https://api.prismsmp.net";
const API_KEY = process.env.PRISMSMP_API_KEY;
class PrismSMPApiError extends Error {
constructor(status, message) {
super(message);
this.status = status;
}
}
async function prismsmpGet(path) {
const res = await fetch(`${API_BASE}${path}`, {
headers: { "X-API-Key": API_KEY }
});
if (res.status === 429) {
const retryAfter = Number(res.headers.get("Retry-After")) || 60;
throw new PrismSMPApiError(429, `Rate limited, retry after ${retryAfter}s`);
}
if (!res.ok) {
const body = await res.json().catch(() => ({}));
throw new PrismSMPApiError(res.status, body.error || `HTTP ${res.status}`);
}
return res.json();
}
async function main() {
const health = await prismsmpGet("/api/health");
console.log("Status:", health.status);
const player = await prismsmpGet("/api/player/SomePlayer");
console.log(`${player.name}: $${player.balance} balance, ${player.stats.kills} kills`);
const auctions = await prismsmpGet("/api/auction/search?item=netherite&sort=cheap&limit=5");
console.log(`${auctions.total_matching} listings match, showing ${auctions.count}`);
const leaderboard = await prismsmpGet("/api/leaderboard?type=balance&limit=5");
leaderboard.entries.forEach((e) => console.log(`#${e.rank} ${e.name}: ${e.value}`));
const playerCount = await prismsmpGet("/api/players/count");
console.log(`${playerCount.online} players online`);
}
main().catch((err) => {
console.error(err.message);
process.exit(1);
});
Python (requests)
import os
import time
import requests
API_BASE = "https://api.prismsmp.net"
API_KEY = os.environ["PRISMSMP_API_KEY"]
class PrismSMPApiError(Exception):
def __init__(self, status, message):
super().__init__(message)
self.status = status
def prismsmp_get(path, params=None):
res = requests.get(
f"{API_BASE}{path}",
headers={"X-API-Key": API_KEY},
params=params,
)
if res.status_code == 429:
retry_after = int(res.headers.get("Retry-After", "60"))
raise PrismSMPApiError(429, f"Rate limited, retry after {retry_after}s")
if not res.ok:
try:
message = res.json().get("error", f"HTTP {res.status_code}")
except ValueError:
message = f"HTTP {res.status_code}"
raise PrismSMPApiError(res.status_code, message)
return res.json()
def main():
health = prismsmp_get("/api/health")
print("Status:", health["status"])
try:
player = prismsmp_get("/api/player/SomePlayer")
print(f"{player['name']}: ${player['balance']} balance, {player['stats']['kills']} kills")
except PrismSMPApiError as err:
if err.status == 404:
print("No player with that name/UUID has been seen before.")
else:
raise
auctions = prismsmp_get("/api/auction/search", params={"item": "netherite", "sort": "cheap", "limit": 5})
print(f"{auctions['total_matching']} listings match, showing {auctions['count']}")
leaderboard = prismsmp_get("/api/leaderboard", params={"type": "balance", "limit": 5})
for entry in leaderboard["entries"]:
print(f"#{entry['rank']} {entry['name']}: {entry['value']}")
player_count = prismsmp_get("/api/players/count")
print(f"{player_count['online']} players online")
if __name__ == "__main__":
main()
Discord.js slash command
The main use case this API is built for: a /stats command that looks up a
player (by the Discord-provided option value, e.g. their Minecraft username) and replies with
an embed showing rank, balance, and combat stats. This example handles the two failure modes
you'll actually hit in production — 404 player not found and
429 rate limited — instead of only covering the happy path.
Command registration
const { SlashCommandBuilder } = require("discord.js");
module.exports = new SlashCommandBuilder()
.setName("stats")
.setDescription("Look up a PrismSMP player's rank, balance, and stats")
.addStringOption((option) =>
option
.setName("player")
.setDescription("Minecraft username or UUID")
.setRequired(true)
);
Command handler
const { EmbedBuilder } = require("discord.js");
const API_BASE = "https://api.prismsmp.net";
const API_KEY = process.env.PRISMSMP_API_KEY;
const RANK_COLOR = {
"0": 0x000000, "1": 0x0000AA, "2": 0x00AA00, "3": 0x00AAAA,
"4": 0xAA0000, "5": 0xAA00AA, "6": 0xFFAA00, "7": 0xAAAAAA,
"8": 0x555555, "9": 0x5555FF, "a": 0x55FF55, "b": 0x55FFFF,
"c": 0xFF5555, "d": 0xFF55FF, "e": 0xFFFF55, "f": 0xFFFFFF
};
function stripColorCodes(s) {
return s.replace(/&[0-9a-fk-or]/g, "");
}
function embedColorFor(rankDisplay) {
const match = rankDisplay.match(/&([0-9a-f])/);
return match ? RANK_COLOR[match[1]] : 0x5ec8d8;
}
async function fetchPlayer(name) {
const res = await fetch(`${API_BASE}/api/player/${encodeURIComponent(name)}`, {
headers: { "X-API-Key": API_KEY }
});
if (res.status === 404) return { notFound: true };
if (res.status === 429) {
const retryAfter = Number(res.headers.get("Retry-After")) || 60;
return { rateLimited: true, retryAfter };
}
if (!res.ok) {
const body = await res.json().catch(() => ({}));
throw new Error(body.error || `PrismSMP API returned ${res.status}`);
}
return { player: await res.json() };
}
module.exports = {
async execute(interaction) {
const query = interaction.options.getString("player", true);
await interaction.deferReply();
let result;
try {
result = await fetchPlayer(query);
} catch (err) {
await interaction.editReply(
`Something went wrong talking to the PrismSMP API: ${err.message}`
);
return;
}
if (result.notFound) {
await interaction.editReply(`No known player matches **${query}**.`);
return;
}
if (result.rateLimited) {
await interaction.editReply(
`This bot is being rate limited right now. Try again in about ${result.retryAfter}s.`
);
return;
}
const player = result.player;
const rankLabel = stripColorCodes(player.rank.display);
const embed = new EmbedBuilder()
.setTitle(player.name)
.setColor(embedColorFor(player.rank.display))
.addFields(
{ name: "Rank", value: rankLabel, inline: true },
{ name: "Balance", value: `$${player.balance.toLocaleString()}`, inline: true },
{ name: "Shards", value: player.shards.toLocaleString(), inline: true },
{ name: "Kills / Deaths", value: `${player.stats.kills} / ${player.stats.deaths}`, inline: true },
{ name: "Playtime", value: `${player.stats.playtime_hours.toFixed(1)}h`, inline: true },
{ name: "Online", value: player.online ? "Yes" : "No", inline: true }
);
if (player.stats_may_lag) {
embed.setFooter({ text: "Combat/playtime stats may be slightly out of date while online." });
}
await interaction.editReply({ embeds: [embed] });
}
};
Discord interactions expire after 3 seconds; deferReply() buys up to 15
minutes by showing a "thinking..." state while the API call completes, then
editReply() fills in the real result — including the error and rate-limit
paths above.