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 |
|---|---|
| What this deployment can answer: version, whether addresses are exposed, the accepted |
| Totals across the whole record and how much of it is in force, overall and per type. |
| The record, newest first. Paged; |
| One punishment. |
| A player's standing. |
| Their history. Paged. |
| Accounts sharing an address with them. |
| Their address history. Gated — see Addresses. |
| What a staff member has handed out. Paged. |
| 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— never0, never"".An unknown resource is
404with{"error": "unknown_<thing>"}.Bad input is
400with{"error": "<reason>"}, plusallowedwhere 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.
Key | Type | Default | Description |
|---|---|---|---|
| boolean |
| Whether the API may return addresses: the |
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.yamlin the plugin repository — the full schema.