This site runs without ads on purpose — donate to keep it alive
← home

API

Everything this site measures is readable as JSON or CSV. No key, no sign-up, no quota beyond the rate limits below.

Before you start

All endpoints are GET, return UTF-8, and need no authentication. Timestamps are epoch seconds unless a field is named otherwise. Addresses in a path must be URL-encoded.

If a server has an alias, requesting the alias returns the canonical server's data directly rather than redirecting. Servers that don't exist and servers that have been removed both return the same 404, deliberately.

Errors are always JSON with an error field, including on the CSV endpoint — check the status code before parsing a response as CSV.

This is a hobby project running on one small box. The endpoints are stable in practice but carry no versioning promise — if you build something that depends on them, tell me at kaiwojciak@gmail.com and I'll warn you before anything breaks. A link back is appreciated, not required.

GET/api/servers

Every visible server, with its current verdict. One object per server; no history.

addressstring
The canonical address, as stored.
displayNamestring | null
Owner-set name, when there is one.
statusstring
One of major-slump, slump, stable, bump, major-bump, gathering.
verbstring
The same verdict as a phrase — “is in a slump”.
provisionalboolean
True when there isn’t enough history to stand behind the verdict yet.
pctnumber | null
Percent difference from the expected level.
znumber | null
Standard deviations from expected. Null while gathering.
onlinenumber | null
Players right now. Null when the last successful ping is over 30 minutes old.
maxnumber | null
Slot count the server reported alongside it.
offlineboolean
True when recent pings are failing.
blurbstring | null
Owner-written one-liner.
claimedboolean
Whether an owner has proven they run it.
iconstring | null
The server’s own icon as a data:image/png URI.
tags{ slug, label }[]
Categories the owner applied and a moderator approved. Empty for most servers.
GET/api/servers/{address}/history

One server’s verdict plus its 7-day chart, bucketed to 30 minutes — the same data the page draws.

/api/servers/crescenta.org/history
address, status, verb, online, max, offline
As above.
subtitlestring
The one-line explanation shown under the verdict.
chart[]array
Buckets, oldest first: ts (bucket start), online (bucket average, null if no successful ping), offline (bucket had only failures), and mu / lower / upper describing the expected band.

The chart is averaged into buckets. For the individual measurements behind it, use the export below.

GET/{address}/export.csv · /{address}/export.json

Raw per-poll measurements for one server. The unaggregated numbers every other endpoint is derived from.

/crescenta.org/export.csv?range=90d

?range= takes 1d, 7d, 30d, 90d or all, defaulting to 30d.

timestamp / tsISO 8601 / number
When the ping was sent. The CSV column is an ISO 8601 UTC string; the JSON field is epoch seconds.
onlinenumber | null
Players at that moment. Empty in CSV and null in JSON when the ping failed — not 0, which would claim the server was up and empty.
maxnumber | null
Slot count, same null rule.
reachable0 / 1 · boolean
Whether that ping got an answer.

A response is capped at 50,000 rows, keeping the most recent. When that clips something the JSON sets truncated: true and the CSV response carries X-Export-Truncated: 1. Narrow the range and fetch twice if you need the whole run.

Gaps are real: a stretch with no rows means the poller wasn't running, which is not the same as the server being down. A row with reachable=0 is the one that means down.

GET/{address}/badge.svg · /{address}/badge.png

The status badge as an image, for embedding. ?metric=players swaps the verdict for a live player count.

/crescenta.org/badge.svg?metric=players

Both formats render an “unknown” badge with a 404status for an address we don't track, so an embed shows something honest rather than a broken image. They cache for five minutes, matching the poll interval.

Rate limits

Counted per IP address, in fixed windows. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (epoch seconds); going over returns 429 with Retry-After.

  • /api/servers 120 requests per minute.
  • /api/servers/{address}/history 120 per minute.
  • export.csv and export.json10 per 5 minutes, shared between the two formats. These read raw rows and are much the most expensive thing here.

Badges are not rate limited: they exist to be embedded on pages that other people load, so throttling them would punish the wrong party.

What the numbers mean

Player counts come from the same public Server List Ping any Minecraft client sends. They are the server's own claim about itself — a proxy or a plugin can report whatever it likes — and we record what we were told.

A verdict compares the last three hours against what that specific server normally does at that weekday and hour, over the past four weeks. It is a comparison with a server's own past, not a ranking against other servers, so a “bump” on a 20-player server and on a 2,000-player one mean the same thing.

See the terms for the usual no-warranty language, which applies here too.