API Reference
Three endpoints. Every one of them requires X-API-Key and
returns JSON.
All paths below are relative to https://api.prismsmp.net.
Set this once and every "Try it" box below uses it. Requests
go straight from your browser to this site's own /api/* routes — nothing passes
through anywhere else. Kept in this browser's local storage only.
Health
GET /api/health Requires X-API-KeyConfirms the API is reachable and that your key is valid. No query or path parameters.
Example request
curl -s "$API_BASE/api/health" \
-H "X-API-Key: $API_KEY"
Example response — 200 OK
{
"status": "ok"
}
Errors
| Status | When |
|---|---|
401 | Missing or invalid X-API-Key. |
429 | Rate limit exceeded. |
Player Lookup
GET /api/player/{name-or-uuid} Requires X-API-KeyLooks up a player by Minecraft username or UUID. Works for offline players too — the player doesn't need to be online right now for this to return data.
Path parameter
| Param | Type | Notes |
|---|---|---|
name-or-uuid |
string | Either a Minecraft username, or a UUID in standard dashed 8-4-4-4-12 hex format
(e.g. 3242b7bb-5969-42fe-adc9-b0ac88ceea92). |
Example request
curl -s "$API_BASE/api/player/SomePlayer" \
-H "X-API-Key: $API_KEY"
Example response — 200 OK
{
"uuid": "3242b7bb-5969-42fe-adc9-b0ac88ceea92",
"name": "SomePlayer",
"online": true,
"rank": { "id": "vip", "display": "&b[VIP]&r", "weight": 10 },
"balance": 15230.5,
"shards": 42.0,
"stats": {
"kills": 120,
"deaths": 45,
"playtime_ticks": 720000,
"playtime_hours": 10.0
},
"stats_may_lag": true
}
Field reference
| Field | Meaning |
|---|---|
online |
Whether the player is online right now, network-wide. Which specific backend they're connected to isn't exposed by this API. |
rank.display |
Contains legacy Minecraft color codes using & (e.g.
&b = aqua, &r = reset). See the conversion table
below — Discord embeds don't render these natively. |
balance / shards |
The server's two currencies: in-game money and a secondary "shards" currency. Both are plain numbers with no formatting applied — round/format them yourself. |
stats.playtime_ticks / playtime_hours |
Minecraft measures time in ticks (20 per second). playtime_hours is
pre-converted so you don't have to do that math — playtime_ticks / 72000. |
stats_may_lag |
See the callout below — this is the field most worth reading carefully. |
kills, deaths, and playtime_* are only refreshed
in the background — on the player's disconnect, a periodic autosave, or a server transfer.
They are not updated live, every second, while a player is playing.
When stats_may_lag is true (the player is currently online),
those three numbers can be a few minutes stale. When it's false (player
offline), they're the last known-good values and won't change again until the player
reconnects.
If your bot displays these numbers, treat true as a signal to add a small
"may be slightly out of date" note rather than presenting the figure as live — see the
Discord.js example for how that looks in an embed.
Color code reference
Legacy Minecraft formatting codes appear after & in rank.display.
Use this table to map them to hex/CSS/Discord embed colors:
| Code | Name | Hex |
|---|---|---|
&0 | black | #000000 |
&1 | dark_blue | #0000AA |
&2 | dark_green | #00AA00 |
&3 | dark_aqua | #00AAAA |
&4 | dark_red | #AA0000 |
&5 | dark_purple | #AA00AA |
&6 | gold | #FFAA00 |
&7 | gray | #AAAAAA |
&8 | dark_gray | #555555 |
&9 | blue | #5555FF |
&a | green | #55FF55 |
&b | aqua | #55FFFF |
&c | red | #FF5555 |
&d | light_purple | #FF55FF |
&e | yellow | #FFFF55 |
&f | white | #FFFFFF |
&r | reset | — |
Discord embeds don't render & codes — either strip them for plain text, or
map the first color code to the embed's accent color:
const COLOR_HEX = {
"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
};
// "&b[VIP]&r" -> "[VIP]" (plain text, codes stripped)
function stripColorCodes(s) {
return s.replace(/&[0-9a-fk-or]/g, "");
}
// "&b[VIP]&r" -> 0x55FFFF (first color code, for an embed's accent color)
function firstEmbedColor(s) {
const match = s.match(/&([0-9a-f])/);
return match ? COLOR_HEX[match[1]] : null;
}
Errors
| Status | When | Body |
|---|---|---|
404 |
No player has ever been seen with that name/UUID. | {"error": "No known player matches \"...\"."} |
400 |
Empty or missing identifier in the path. | {"error": "..."} |
401 |
Missing or invalid X-API-Key. |
{"error": "..."} |
429 |
Rate limit exceeded. | {"error": "..."} |
Auction Search
GET /api/auction/search Requires X-API-KeySearches current (non-expired) auction house listings. All query parameters are optional.
Query parameters
| Param | Default | Notes |
|---|---|---|
item |
(none — no filter) | Free-text search. Matches against the item's Minecraft type name, the item's
custom display name (if the seller renamed it), or the seller's username. If
item parses as a number, it instead matches any listing priced within
10% of that value. |
sort |
recent |
One of recent, oldest, cheap, expensive. |
limit |
50 |
Max results to return. Hard-capped at 200 server-side — asking for
more silently gets capped, it's not an error. |
Example request
curl -s "$API_BASE/api/auction/search?item=netherite&sort=cheap&limit=10" \
-H "X-API-Key: $API_KEY"
Example response — 200 OK
{
"count": 2,
"total_matching": 2,
"results": [
{
"id": 1234,
"seller": "SomeSeller",
"material": "NETHERITE_INGOT",
"display_name": "Netherite Ingot",
"amount": 4,
"price": 5000.0,
"formatted_price": "$5k",
"created_at_epoch": 1752300000,
"expires_at_epoch": 1752400000,
"time_left_seconds": 82000
}
]
}
Field reference
| Field | Meaning |
|---|---|
count vs total_matching |
count is how many listings are actually in results
(after limit is applied). total_matching is how many matched
before the limit — useful for a "showing 50 of 214 results" style message. |
material |
A vanilla Minecraft item ID (e.g. NETHERITE_INGOT), 1:1 with
Minecraft's own item ID list. Handy if you want to map results to icons yourself —
this API doesn't provide icons/images. |
time_left_seconds |
Raw seconds until the listing expires. Format it yourself for display — see below. |
// 8100 -> "2h 15m"
function formatTimeLeft(seconds) {
const h = Math.floor(seconds / 3600);
const m = Math.floor((seconds % 3600) / 60);
return `${h}h ${m}m`;
}
Listings in a temporary "premium priority" window (a head-start visibility perk for some players) are excluded from API results entirely. If a listing you know exists doesn't appear right after being posted, that's why — it'll show up once the window passes. This is expected behavior, not a bug. Expired listings, by contrast, never appear again.
Errors
| Status | When |
|---|---|
503 |
The auction house isn't available on the backend currently running the API. This is a rare, server-side configuration issue — not something caused by your request. |
401 | Missing or invalid X-API-Key. |
429 | Rate limit exceeded. |
Leaderboard
GET /api/leaderboard Requires X-API-KeyTop players ranked by balance, shards, or kills.
Query parameters
| Param | Default | Notes |
|---|---|---|
type |
(required) | One of balance, shards, kills. Anything
else is a 400. |
limit |
10 |
Max entries to return. Hard-capped at 100 server-side — asking for
more silently gets capped, it's not an error. |
Example request
curl -s "$API_BASE/api/leaderboard?type=balance&limit=5" \
-H "X-API-Key: $API_KEY"
Example response — 200 OK
{
"type": "balance",
"count": 2,
"entries": [
{ "rank": 1, "uuid": "3242b7bb-5969-42fe-adc9-b0ac88ceea92", "name": "RichGuy", "value": 1500000.0 },
{ "rank": 2, "uuid": "a1b2c3d4-5678-42fe-adc9-b0ac88ceea92", "name": "SecondPlace", "value": 980000.0 }
]
}
Field reference
| Field | Meaning |
|---|---|
count vs entries.length |
These are always equal — count is just a convenience so you don't
need entries.length in your own code. |
entries |
May have fewer than limit items if fewer players have a value for
that type at all (e.g. a brand new server with under 10 players who've ever earned
shards). Not an error. |
Balance/shards leaderboards refresh roughly every 45 seconds; the kills leaderboard (which is far more expensive to compute — it touches one Redis key per player who's ever been seen) refreshes roughly every 5 minutes. During busy periods the numbers you see can lag behind reality by up to that interval — this is intentional, not a bug, and keeps the endpoint fast regardless of how many players the server has ever had.
Errors
| Status | When | Body |
|---|---|---|
400 |
Missing or invalid type. |
{"error": "type must be one of: balance, shards, kills"} |
401 | Missing or invalid X-API-Key. | {"error": "..."} |
429 | Rate limit exceeded. | {"error": "..."} |
Player Count
GET /api/players/count Requires X-API-KeyHow many players are online right now, network-wide — not broken down by individual backend. No query or path parameters.
Example request
curl -s "$API_BASE/api/players/count" \
-H "X-API-Key: $API_KEY"
Example response — 200 OK
{
"online": 342
}
Unlike the leaderboard, this one is computed live on every request — it's a single, cheap Redis operation, so there's no caching lag to account for.
Errors
| Status | When |
|---|---|
401 | Missing or invalid X-API-Key. |
429 | Rate limit exceeded. |
CORS
The API sends Access-Control-Allow-Origin: * on every response, so it can be
called directly from browser JavaScript — you're not limited to building a backend/bot
process. A client-side web tool works just as well as a Discord bot, if that's what you'd
rather build.