PrismSMP API Docs

API Reference

Three endpoints. Every one of them requires X-API-Key and returns JSON.

Base URL

All paths below are relative to https://api.prismsmp.net.

Try it — enter your API key

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-Key

Confirms the API is reachable and that your key is valid. No query or path parameters.

Example request

bash
curl -s "$API_BASE/api/health" \
  -H "X-API-Key: $API_KEY"

Example response — 200 OK

json
{
  "status": "ok"
}
Try it

Errors

StatusWhen
401Missing or invalid X-API-Key.
429Rate limit exceeded.

Player Lookup

GET /api/player/{name-or-uuid} Requires X-API-Key

Looks 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

ParamTypeNotes
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

bash
curl -s "$API_BASE/api/player/SomePlayer" \
  -H "X-API-Key: $API_KEY"

Example response — 200 OK

json
{
  "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
}
Try it

Field reference

FieldMeaning
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.
stats_may_lag — read this before showing kills/deaths/playtime

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:

CodeNameHex
&0black#000000
&1dark_blue#0000AA
&2dark_green#00AA00
&3dark_aqua#00AAAA
&4dark_red#AA0000
&5dark_purple#AA00AA
&6gold#FFAA00
&7gray#AAAAAA
&8dark_gray#555555
&9blue#5555FF
&agreen#55FF55
&baqua#55FFFF
&cred#FF5555
&dlight_purple#FF55FF
&eyellow#FFFF55
&fwhite#FFFFFF
&rreset

Discord embeds don't render & codes — either strip them for plain text, or map the first color code to the embed's accent color:

javascript
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

StatusWhenBody
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": "..."}
GET /api/auction/search Requires X-API-Key

Searches current (non-expired) auction house listings. All query parameters are optional.

Query parameters

ParamDefaultNotes
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

bash
curl -s "$API_BASE/api/auction/search?item=netherite&sort=cheap&limit=10" \
  -H "X-API-Key: $API_KEY"

Example response — 200 OK

json
{
  "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
    }
  ]
}
Try it

Field reference

FieldMeaning
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.
javascriptformat time_left_seconds
// 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 that don't show up yet

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

StatusWhen
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.
401Missing or invalid X-API-Key.
429Rate limit exceeded.

Leaderboard

GET /api/leaderboard Requires X-API-Key

Top players ranked by balance, shards, or kills.

Query parameters

ParamDefaultNotes
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

bash
curl -s "$API_BASE/api/leaderboard?type=balance&limit=5" \
  -H "X-API-Key: $API_KEY"

Example response — 200 OK

json
{
  "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 }
  ]
}
Try it

Field reference

FieldMeaning
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.
This isn't computed live

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

StatusWhenBody
400 Missing or invalid type. {"error": "type must be one of: balance, shards, kills"}
401Missing or invalid X-API-Key.{"error": "..."}
429Rate limit exceeded.{"error": "..."}

Player Count

GET /api/players/count Requires X-API-Key

How many players are online right now, network-wide — not broken down by individual backend. No query or path parameters.

Example request

bash
curl -s "$API_BASE/api/players/count" \
  -H "X-API-Key: $API_KEY"

Example response — 200 OK

json
{
  "online": 342
}
Try it

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

StatusWhen
401Missing or invalid X-API-Key.
429Rate 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.