API

Everything the site and the Discord bot show comes from one JSON service. The public reads are documented below for everyone; signing in, your account and the admin tools are shown to moderators and admins after sign-in.

Base URL https://api.hvmhfz.eclipseforge.xyz · health /actuator/health · times UTC · plain markdown version

Contents
  1. Signing in
  2. Public endpoints
  3. Errors, limits and caching
  4. Your account
  5. Admin endpoints and the audit log
  6. Users, roles and gifts
  7. Hunting Road admin
  8. Auth rules
  9. Errors, limits and caching

Signing in

Two routes return the same signed token, valid 7 days. The token names the account; no endpoint takes an account id from the caller, so one token cannot read another account's data. Sign-in itself is one of the few routes that do not need a token.

POST /api/auth/signin (programs, no captcha)

Body fields: username (game account name), password (plain, over HTTPS), token (empty string; the captcha answer is only used by the web route).

curl -s https://api.hvmhfz.eclipseforge.xyz/api/auth/signin \
  -H 'Content-Type: application/json' \
  -d '{"username":"YourGameName","password":"your-password","token":""}'
{"accessToken":"eyJhbGciOiJIUzI1NiJ9...","id":12345,"roles":["ROLE_USER"],"tokenType":"Bearer"}

Send it on every request that needs an account: Authorization: Bearer <accessToken>. The token is a JWT: sub is the account name, roles lists ROLE_USER / ROLE_MODERATOR / ROLE_ADMIN, exp is the expiry. The server checks the signature and the role on every request; editing the payload breaks the signature.

POST /api/auth/signinweb (the website)

Same body, but token carries the Cloudflare Turnstile answer. The site's form does this for you. Wrong or missing captcha answers are refused; repeated failures are rate limited (429).

Registration and password reset

POST /api/auth/signup takes username, password and token (the Turnstile answer, as for signinweb) and makes a game account: a username of 3 to 20 characters from A-Z, a-z, 0-9 and _ . -, a password of 6 to 72 plain ASCII characters. A name that differs from an existing one only by capital letters is refused (409), because logins are case-sensitive. It answers like sign-in (accessToken), or a refusal with a one-sentence message. PUT /api/auth/passwordreset takes username, password and discordId for accounts that linked Discord. Both are rate limited.

HeaderValue
AuthorizationBearer <accessToken>
Content-Typeapplication/json on requests with a body

Status codes: 400 bad body, 401 missing or expired token, 403 signed in but not allowed, 429 too many sign-in attempts.

Public endpoints

No token, cached 30 seconds unless stated. Paged endpoints return {items, page, size, total}; page starts at 0 and size is clamped to 1 to 100. Every other route, including the account and admin pages, needs an account token: sign in as described above and send it as a bearer token.

PathParametersReturns
GET /api/public/summarynonecounts: hunters, guilds, characters, online players
GET /api/public/guildsq (search, case-insensitive), sort (default rp), page (0), size (30, max 100)paged guild summaries
GET /api/public/guilds/{id}id: guild idone guild: name, rank, points, roster, board
GET /api/public/huntersq, sort (hr default, name, gr, last), page, size (30, max 100)paged hunter summaries
GET /api/public/hunters/{id}id: character idone hunter: name, HR, GR, weapon, guild, playtimeSeconds (the game's own counter), online, hunts, top monsters, weaponTime[] (weaponType, weapon, seconds; most played first) and weaponTimeSince
GET /api/public/catalog/itemsq, page, size (40, max 100)paged items: id (hex), name, type, icon
GET /api/public/catalog/equipmentslot (melee default, ranged, head, chest, arms, waist, legs), q, page, size (40)paged equipment
GET /api/public/worldsnoneworlds: name, description, players, capacity
GET /api/public/statusnonestate (online: the sign and game ports answer; degraded: only some ports answer; offline: none), online, players (hunters on all worlds; null while offline or unknown), worldsOpen, checkedAt, ports[] (name, port, open), connect (host, launcherPort, signPort, gamePort, mode, fallbackMode, version). Checked at most every 30 s
GET /api/public/weaponsnonehours played per weapon type by every hunter: since (when tracking began), seconds, hunters, weapons[] (all 14 types, most played first: weaponType, weapon, seconds, hunters)
GET /api/public/road/hunter/{id}id: character idone hunter's place on the live Road's and the Original Road's boards at any rank: [{key, name, current, open, solo}], open/solo = {rank, of, floor, points, reachedAt}, rank null with no clear
GET /api/public/worlds/historyrange (24h default, 7d, 30d, 90d, all)players online over time (sampled every minute: points[] with average and peak per bucket), active hunters per hour/day/week from the hunt log (active[]), and the players seen in the range: name, HR, GR, playtimeSeconds, sessions, secondsInRange, lastSeen, online (newest 500)
GET /api/public/monsterslimit (300 default, 1 to 300)monster kill totals
GET /api/public/leaderboards/huntsperiod (week default, lastweek, month, lastmonth, all), limit (100 default, 1 to 100)period, from, to, resetsAt, hunters[], guilds[], monsters[]
GET /api/public/road/leaderboardrotation (current default, original, or a cycle number), mode (open default, solo), limit (100 default, 1 to 100)rotation, rotations[], tracking, hunters, entries[]
GET /api/public/road/historynoneevery Road that has gone live, newest first
GET /api/public/searchq (required in practice)hunters, guilds and monsters matching q
GET /api/public/eventsnonecurrent and upcoming events

The hunt board scans the whole kill log, so it is cached for 5 minutes per period and size. Weeks start Monday 00:00 UTC and months on the 1st, so week resets every Monday.

Road leaderboard entry fields

FieldMeaning
rank1-based position on this board
characterId, name, guildName, grwho reached the floor
floorhighest floor reached in one run during the rotation
reachedAtwhen that floor was first reached (ISO 8601 UTC)
floorsClimbedhow many floors were recorded for that hunter in the rotation
pointsRoad point balance at that floor, or null when it was not recorded

rotation.sha is the sha256 of the Road data file, the map's permanent id. Rotations are listed in rotations[], newest first.

Errors, limits and caching

Errors are {"message":"..."}. 400 bad input (missing field, out of range, a minimum above its maximum), 401 missing or expired token, 403 wrong role or a character that is not yours, 404 unknown id, 409 conflicts such as an existing vote, 429 rate limit, 502 an upstream tool failed.

Public reads are cached 30 seconds; hunt boards 5 minutes per period and size. Sign-in and the public endpoints are rate limited per client: back off on 429 instead of retrying in a loop.

Paged endpoints take page (0-based) and size (1 to 100). Sizes above the maximum are clamped, not refused.

The account and admin half of this page is for moderators and admins. Sign in with one and reload; the public endpoints above stay readable by everyone. The server enforces every role regardless of what this page shows.