Astral Realms Documentation Help

HTTP API

The master module is a MageHic plugin that serves the punishment record over HTTP under /astralpunishments/…. It is read-only by design: issuing and lifting punishments happens on the proxy, where the immunity and duration rules live and where the disconnect actually lands. A write here would bypass every one of those and leave the game servers' caches behind.

A full OpenAPI 3 description ships with the plugin source as punishments-api.openapi.yaml — that file is the contract; this page is the orientation.

Endpoints

Endpoint

Answers

GET /capabilities

What this deployment can answer: version, whether addresses are exposed, the accepted type/status values, and the feature keys it supports.

GET /stats

Totals across the whole record and how much of it is in force, overall and per type.

GET /punishments

The record, newest first. Paged; ?type= and ?status= narrow it.

GET /punishments/{id}

One punishment.

GET /players/{idOrName}

A player's standing.

GET /players/{idOrName}/punishments

Their history. Paged.

GET /players/{idOrName}/alts

Accounts sharing an address with them.

GET /players/{idOrName}/addresses

Their address history. Gated — see Addresses.

GET /staff/{idOrName}/punishments

What a staff member has handed out. Paged.

GET /addresses/{ip}

The accounts and punishments on one address. Gated.

?type= and ?status= are applied before paging, so a filtered page is a page of matches rather than a page of everything with the misses removed.

Conventions

Uniform across every endpoint:

  • Timestamps are Unix epoch milliseconds; durations are milliseconds and suffixed Ms.

  • An absent value is null — never 0, never "".

  • An unknown resource is 404 with {"error": "unknown_<thing>"}.

  • Bad input is 400 with {"error": "<reason>"}, plus allowed where a fixed set applies.

  • List endpoints take ?limit=/?cursor= and always answer with the pagination envelope, never a bare array.

Payloads are built field by field as explicit maps rather than serialised entities, so what goes over the wire is chosen rather than inherited from the schema.

Pagination

?limit= defaults to 50 and is capped at 200. The cursor is opaque on purpose: it encodes an offset today, but nothing outside the class relies on that, so the scheme can become keyset-based without a client change. Pass it back exactly as received; an unreadable cursor is a 400.

Conditional requests

/stats answers with a weak ETag and honours If-None-Match, so a panel polling it on a timer pays a header instead of a payload once nothing has moved. The tag is a stable function of the response content (the API builds ordered maps, so the same data always hashes the same) — weak by declaration, because same content is exactly the guarantee on offer.

Addresses

IP addresses are withheld by default. The MageHic HTTP runtime authenticates only when MAGEHIC_HTTP_TOKEN is set and binds 0.0.0.0, so an address published here is an address published to whoever can reach the port.

# plugins/AstralPunishments/config.yml (master) expose-addresses: false

Key

Type

Default

Description

expose-addresses

boolean

false

Whether the API may return addresses: the ip field on a punishment, /players/{id}/addresses and /addresses/{ip}.

With it off, the two address endpoints still exist but answer 403, and ip is omitted from punishment payloads. /capabilities reports addressesExposed so a consumer can hide the feature rather than render it broken. Turn it on once the deployment sits behind a token or a private network and staff tooling needs the addresses.

See also

  • Overview — the record these endpoints read.

  • punishments-api.openapi.yaml in the plugin repository — the full schema.

Last modified: 25 September 2026