{"openapi":"3.1.0","info":{"title":"Valheim guild site API","version":"1.0.0","summary":"Public read API, admin API, live stream and telemetry ingest of the guild site.","description":"Conventions: JSON UTF-8; timestamps ISO 8601 UTC with Z; world day integer; coordinates x and z in world metres (the world is a disc of radius 10,000 m centred on 0,0); durations in seconds unless the field name ends in _ms. Ids: players, characters, sessions, raids and jobs are integers; events and server runs are UUID strings; boss keys and global keys are strings. Pagination: limit (1 to 200, default 50) and an opaque cursor; list responses are { items, next_cursor } ordered newest first unless stated. Errors: the HTTP status plus { error: { code, message } }. Caching: public GET responses carry Cache-Control: public, max-age=15 and an ETag; /stream and admin responses are uncacheable. Rate limit: 120 requests per minute per IP on public endpoints, answered with 429 rate_limited; ingest and stream are exempt. Admin auth: POST /admin/login sets a signed session cookie; admin endpoints answer 401 without it; state-changing requests require the Origin header to match the site origin (ORIGIN when set, otherwise the address the request was made to)."},"servers":[{"url":"http://localhost:5173","description":"Local development server (npm run dev, npm run dev:mock)."},{"url":"http://localhost:3000","description":"Local production image (docker compose up)."},{"url":"https://{host}","description":"Railway deployment.","variables":{"host":{"default":"guild.example.org","description":"The site domain."}}}],"security":[],"tags":[{"name":"status","description":"Server status and history."},{"name":"players","description":"Players, characters and their statistics."},{"name":"bosses","description":"Boss progression and timelines."},{"name":"raids","description":"Random events."},{"name":"world","description":"World, progression keys, saves and the map."},{"name":"chat","description":"Shouts, pings and relayed speech."},{"name":"structures","description":"Building activity."},{"name":"comfort","description":"The comfort pieces the running game defines and how many of each this server has built."},{"name":"activity","description":"The unified feed."},{"name":"system","description":"Health and this contract."},{"name":"stream","description":"Live updates over server-sent events."},{"name":"admin","description":"Password-protected administration."},{"name":"ingest","description":"Signed telemetry from the server plugin."},{"name":"zone","description":"Zone-leader measurements, their ranking and the probe the browser measures against."}],"paths":{"/api/v1/status":{"get":{"operationId":"getStatus","tags":["status"],"summary":"Server status","description":"Online state, player count, versions, world and run information from the plugin and, independently, from Steam A2S polling.","responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Status"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/status/history":{"get":{"operationId":"getStatusHistory","tags":["status"],"summary":"Player count history","parameters":[{"name":"range","in":"query","required":false,"description":"Window to return, downsampled to at most 600 points.","schema":{"type":"string","enum":["24h","7d","30d"],"default":"24h"}}],"responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusHistory"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/online":{"get":{"operationId":"getOnline","tags":["status"],"summary":"Players online now","responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnlineList"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/runs":{"get":{"operationId":"listRuns","tags":["status"],"summary":"Server runs","description":"One item per server process start, newest first.","parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunPage"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/players":{"get":{"operationId":"listPlayers","tags":["players"],"summary":"Player list","description":"Hidden players are omitted.","parameters":[{"name":"q","in":"query","required":false,"description":"Search by display name, character name, raw id or display id.","schema":{"type":"string"}},{"name":"sort","in":"query","required":false,"description":"Sort key.","schema":{"type":"string","enum":["playtime","last_seen","deaths","kills","name","first_seen"],"default":"last_seen"}},{"name":"order","in":"query","required":false,"description":"Sort direction.","schema":{"type":"string","enum":["asc","desc"],"default":"desc"}},{"name":"online","in":"query","required":false,"description":"Only players online right now.","schema":{"type":"boolean"}},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlayerPage"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/players/{id}":{"get":{"operationId":"getPlayer","tags":["players"],"summary":"Player profile","parameters":[{"$ref":"#/components/parameters/PlayerId"}],"responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Player"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found: no such resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/players/{id}/sessions":{"get":{"operationId":"listPlayerSessions","tags":["players"],"summary":"Session history","parameters":[{"$ref":"#/components/parameters/PlayerId"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionPage"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found: no such resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/players/{id}/deaths":{"get":{"operationId":"listPlayerDeaths","tags":["players"],"summary":"Deaths","parameters":[{"$ref":"#/components/parameters/PlayerId"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeathPage"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found: no such resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/players/{id}/kills":{"get":{"operationId":"getPlayerKills","tags":["players"],"summary":"Creature kills","description":"Credited kills come from RegisterKill RPCs relayed through the server; nearby kills are counted by proximity.","parameters":[{"$ref":"#/components/parameters/PlayerId"}],"responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlayerKills"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found: no such resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/players/{id}/positions":{"get":{"operationId":"getPlayerPositions","tags":["players"],"summary":"Position trail","parameters":[{"$ref":"#/components/parameters/PlayerId"},{"name":"range","in":"query","required":false,"description":"Window to return.","schema":{"type":"string","enum":["1h","6h","24h","7d"],"default":"24h"}},{"name":"limit","in":"query","required":false,"description":"Maximum number of points after downsampling.","schema":{"type":"integer","minimum":1,"maximum":5000,"default":500}}],"responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PositionList"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found: no such resource; or player positions are switched off on this site.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/players/{id}/structures":{"get":{"operationId":"getPlayerStructures","tags":["players"],"summary":"Structures built","parameters":[{"$ref":"#/components/parameters/PlayerId"}],"responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlayerStructures"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found: no such resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/players/{id}/activity":{"get":{"operationId":"listPlayerActivity","tags":["players"],"summary":"Player activity","parameters":[{"$ref":"#/components/parameters/PlayerId"},{"$ref":"#/components/parameters/Types"},{"$ref":"#/components/parameters/Since"},{"$ref":"#/components/parameters/Until"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivityPage"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found: no such resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/bosses":{"get":{"operationId":"listBosses","tags":["bosses"],"summary":"Boss progression","description":"The eight Forsaken in the game's kill order, then the mini-bosses, then any other boss the world has defeated, each with its kill summary. A boss that fights in several phases (Kall Fimbulbringer) is one item under its final phase's key; the earlier phase keys and prefabs are folded into it.","responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BossList"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/bosses/{key}":{"get":{"operationId":"getBoss","tags":["bosses"],"summary":"Boss detail","parameters":[{"$ref":"#/components/parameters/BossKey"}],"responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BossDetail"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found: no such resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/bosses/{key}/events":{"get":{"operationId":"listBossEvents","tags":["bosses"],"summary":"Boss timeline","parameters":[{"$ref":"#/components/parameters/BossKey"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BossEventPage"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found: no such resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/raids":{"get":{"operationId":"listRaids","tags":["raids"],"summary":"Raids","parameters":[{"$ref":"#/components/parameters/Since"},{"$ref":"#/components/parameters/Until"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RaidPage"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/raids/{id}":{"get":{"operationId":"getRaid","tags":["raids"],"summary":"Raid detail","parameters":[{"$ref":"#/components/parameters/RaidId"}],"responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RaidDetail"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found: no such resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/progression":{"get":{"operationId":"getProgression","tags":["world"],"summary":"World progression keys","responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProgressionList"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/world":{"get":{"operationId":"getWorld","tags":["world"],"summary":"World","responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/World"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/world/map.png":{"get":{"operationId":"getWorldMap","tags":["world"],"summary":"World map image","description":"The biome map rendered by the plugin for the current world uid.","responses":{"200":{"description":"The PNG.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"image/png":{"schema":{"type":"string","contentMediaType":"image/png"}}}},"404":{"description":"not_found: no such resource; or the world map is switched off on this site.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/saves":{"get":{"operationId":"listSaves","tags":["world"],"summary":"World saves","parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SavePage"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/chat":{"get":{"operationId":"listChat","tags":["chat"],"summary":"Chat","parameters":[{"name":"kind","in":"query","required":false,"description":"Only this kind.","schema":{"type":"string","enum":["shout","ping","say"]}},{"$ref":"#/components/parameters/PlayerFilter"},{"$ref":"#/components/parameters/Since"},{"$ref":"#/components/parameters/Until"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatPage"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found: chat is switched off on this site.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/structures":{"get":{"operationId":"getStructures","tags":["structures"],"summary":"Structures summary","parameters":[{"name":"range","in":"query","required":false,"description":"Window for the series and totals.","schema":{"type":"string","enum":["7d","30d","all"],"default":"30d"}}],"responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Structures"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/structures/recent":{"get":{"operationId":"listStructureEvents","tags":["structures"],"summary":"Recent structure events","parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StructureEventPage"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/comfort":{"get":{"operationId":"getComfort","tags":["comfort"],"summary":"Comfort pieces","description":"The comfort catalogue the plugin read from the running game at its latest start, with how many of each piece this server has built since the log began. catalogue is null until the first upload.","responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Comfort"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/activity":{"get":{"operationId":"listActivity","tags":["activity"],"summary":"Activity feed","description":"Every event newest first, excluding server.heartbeat, player.position, structure.* and creature.died unless requested through types.","parameters":[{"$ref":"#/components/parameters/Types"},{"$ref":"#/components/parameters/PlayerFilter"},{"$ref":"#/components/parameters/Since"},{"$ref":"#/components/parameters/Until"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivityPage"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/zone/results":{"get":{"operationId":"listZoneResults","tags":["zone"],"summary":"Ranked zone-leader results","description":"Every stored measurement, ranked best first by overall score with ties broken by failure rate, median latency, jitter, single-thread CPU, stability score and name. One entry per character name.","responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ZoneResultList"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/zone/results/{name}":{"put":{"operationId":"putZoneResult","tags":["zone"],"summary":"Store or replace a measurement","description":"Stores the result under the normalised character name (trimmed, inner whitespace collapsed, upper-cased), replacing any earlier result for that name. The body must carry the same name. Scores, rating and penalties are recomputed from the measurements on the server and tested_at is stamped with server time; the answer is the stored entry with its rank in the fresh ranking.","parameters":[{"$ref":"#/components/parameters/ZoneName"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ZoneResult"}}}},"responses":{"200":{"description":"The stored entry with its rank.","headers":{"Cache-Control":{"$ref":"#/components/headers/NoStore"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ZoneRankedResult"}}}},"400":{"description":"bad_request: the name is empty or over 48 characters, the body does not match ZoneResult, or the body names a different character.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"unprocessable: the diagnostic version is incompatible, the measurements are impossible, or the run did not complete.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"deleteZoneResult","tags":["zone"],"summary":"Remove a measurement","description":"Admin only. Storing and replacing a measurement stays open to every member; removing one needs an admin session.","security":[{"adminCookie":[]}],"parameters":[{"$ref":"#/components/parameters/ZoneName"}],"responses":{"204":{"description":"Removed."},"401":{"description":"unauthorized: no valid admin session cookie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"forbidden: the Origin header does not match the site origin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found: no such resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/zone/probe/health":{"get":{"operationId":"getZoneProbeHealth","tags":["zone"],"summary":"Probe health","description":"The probe the browser measures against. Probe routes are served by the site itself in every mode, carry no ETag and are exempt from the rate limit.","responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/NoStore"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProbeHealth"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/zone/probe/ping":{"get":{"operationId":"getZoneProbePing","tags":["zone"],"summary":"Probe round trip","description":"Answers immediately with the server clock so the browser can time a round trip.","parameters":[{"name":"t","in":"query","required":false,"description":"Cache buster; ignored.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/NoStore"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProbePing"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/zone/probe/download":{"get":{"operationId":"getZoneProbeDownload","tags":["zone"],"summary":"Probe download payload","description":"A deterministic binary payload of the requested size for timing a download.","parameters":[{"name":"bytes","in":"query","required":false,"description":"Payload size in bytes, clamped to 16 to 2097152.","schema":{"type":"integer","minimum":16,"maximum":2097152,"default":65536}}],"responses":{"200":{"description":"The payload, with its Content-Length.","headers":{"Cache-Control":{"$ref":"#/components/headers/NoStore"}},"content":{"application/octet-stream":{"schema":{"type":"string","contentMediaType":"application/octet-stream"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/zone/probe/upload":{"post":{"operationId":"postZoneProbeUpload","tags":["zone"],"summary":"Probe upload sink","description":"Accepts up to 2 MiB, discards it and answers with the byte count so the browser can time an upload.","requestBody":{"required":true,"content":{"application/octet-stream":{"schema":{"type":"string","contentMediaType":"application/octet-stream"}}}},"responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/NoStore"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProbeUpload"}}}},"413":{"description":"payload_too_large: body over 2 MiB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/health":{"get":{"operationId":"getHealth","tags":["system"],"summary":"Health","description":"Container health check.","responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/NoStore"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Health"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/site":{"get":{"operationId":"getSite","tags":["system"],"summary":"Site name, version and features","description":"The site name from the admin settings (or PUBLIC_SITE_NAME), the project version and which features are switched on.","responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Site"}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/openapi.json":{"get":{"operationId":"getOpenApi","tags":["system"],"summary":"This contract as JSON","responses":{"200":{"description":"The OpenAPI document.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"429":{"description":"rate_limited: more than 120 requests per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/stream":{"get":{"operationId":"streamEvents","tags":["stream"],"summary":"Live stream","description":"Server-sent events. Event names: status (the Status object, sent on connect and whenever it changes), online (the OnlineList object, on connect and on change) and activity (one ActivityItem per accepted event that the feed includes, with id set to the event id). A comment frame every 15 s keeps the connection alive. A reconnect with Last-Event-ID first replays activity items newer than that id (at most 100).","parameters":[{"$ref":"#/components/parameters/LastEventId"},{"name":"last_event_id","in":"query","required":false,"description":"Same as the Last-Event-ID header, for clients that reconnect manually and cannot set headers.","schema":{"type":"string"}}],"x-sse-events":{"status":{"description":"The /status object.","schema":{"$ref":"#/components/schemas/Status"}},"online":{"description":"The /online list.","schema":{"$ref":"#/components/schemas/OnlineList"}},"activity":{"description":"One activity item; the frame id is the event id.","schema":{"$ref":"#/components/schemas/ActivityItem"}}},"responses":{"200":{"description":"An event stream that stays open.","headers":{"Cache-Control":{"$ref":"#/components/headers/NoStore"}},"content":{"text/event-stream":{"schema":{"$ref":"#/components/schemas/StreamFrame"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/admin/login":{"post":{"operationId":"adminLogin","tags":["admin"],"summary":"Log in","description":"Sets an HttpOnly, SameSite=Lax (Secure in production) session cookie signed with the session secret (ADMIN_SESSION_SECRET, or one generated at first start). Limited to 5 attempts per minute per IP.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}}},"responses":{"204":{"description":"Logged in; the cookie is set.","headers":{"Set-Cookie":{"description":"The admin session cookie.","schema":{"type":"string"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized: wrong password.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited: more than 5 login attempts per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/admin/logout":{"post":{"operationId":"adminLogout","tags":["admin"],"summary":"Log out","security":[{"adminCookie":[]}],"responses":{"204":{"description":"Logged out; the cookie is cleared."},"401":{"description":"unauthorized: no valid admin session cookie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"forbidden: the Origin header does not match the site origin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/admin/session":{"get":{"operationId":"getAdminSession","tags":["admin"],"summary":"Session state","security":[{"adminCookie":[]}],"responses":{"200":{"description":"Whether the cookie is a valid session; authenticated is false without a valid cookie.","headers":{"Cache-Control":{"$ref":"#/components/headers/NoStore"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminSession"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/admin/setup":{"post":{"operationId":"adminSetup","tags":["admin"],"summary":"Set the first admin password","description":"Stores the admin password as a scrypt hash and logs in. Only allowed while no password is set and ADMIN_PASSWORD is not set. Limited to 5 attempts per minute per IP.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupRequest"}}}},"responses":{"204":{"description":"Password set and logged in; the cookie is set.","headers":{"Set-Cookie":{"description":"The admin session cookie.","schema":{"type":"string"}}}},"400":{"description":"bad_request: password is missing or not 8 to 200 characters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"forbidden: the Origin header does not match the site origin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"conflict: the admin password is already set.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rate_limited: more than 5 attempts per minute from this IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/admin/settings":{"get":{"operationId":"getAdminSettings","tags":["admin"],"summary":"Site settings","security":[{"adminCookie":[]}],"responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/NoStore"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminSettings"}}}},"401":{"description":"unauthorized: no valid admin session cookie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"operationId":"updateAdminSettings","tags":["admin"],"summary":"Change site settings","description":"Changes the given settings and keeps the others. A setting whose environment variable is set cannot be changed here.","security":[{"adminCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminSettingsUpdate"}}}},"responses":{"200":{"description":"The settings after the change.","headers":{"Cache-Control":{"$ref":"#/components/headers/NoStore"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminSettings"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized: no valid admin session cookie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"forbidden: the Origin header does not match the site origin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"conflict: the setting is set by an environment variable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/admin/plugin":{"get":{"operationId":"getAdminPlugin","tags":["admin"],"summary":"Plugin setup","description":"What the game server needs to report to this site - the plugin version this site ships, the telemetry secret, whether the DLL is in this build - and the latest server start.","security":[{"adminCookie":[]}],"responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/NoStore"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PluginInfo"}}}},"401":{"description":"unauthorized: no valid admin session cookie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/admin/plugin/secret":{"post":{"operationId":"regenerateTelemetrySecret","tags":["admin"],"summary":"Replace the telemetry secret","description":"The running plugin is refused until its config carries the new secret.","security":[{"adminCookie":[]}],"responses":{"200":{"description":"The new secret.","headers":{"Cache-Control":{"$ref":"#/components/headers/NoStore"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PluginSecret"}}}},"401":{"description":"unauthorized: no valid admin session cookie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"forbidden: the Origin header does not match the site origin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"conflict: TELEMETRY_SECRET is set in the environment.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/admin/plugin/dll":{"get":{"operationId":"getPluginDll","tags":["admin"],"summary":"Download the plugin DLL","description":"The GuildTelemetry.dll built with this site's version, for BepInEx/plugins on the game server.","security":[{"adminCookie":[]}],"responses":{"200":{"description":"The DLL as an attachment.","headers":{"Cache-Control":{"$ref":"#/components/headers/NoStore"}},"content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"401":{"description":"unauthorized: no valid admin session cookie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found: this build has no plugin DLL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/admin/players":{"get":{"operationId":"listAdminPlayers","tags":["admin"],"summary":"Players including hidden","security":[{"adminCookie":[]}],"parameters":[{"name":"include_hidden","in":"query","required":false,"description":"Include hidden players.","schema":{"type":"boolean","default":true}},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/NoStore"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPlayerPage"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized: no valid admin session cookie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/admin/players/{id}":{"patch":{"operationId":"updateAdminPlayer","tags":["admin"],"summary":"Rename or hide a player","security":[{"adminCookie":[]}],"parameters":[{"$ref":"#/components/parameters/PlayerId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlayerPatch"}}}},"responses":{"200":{"description":"The updated player.","headers":{"Cache-Control":{"$ref":"#/components/headers/NoStore"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPlayer"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized: no valid admin session cookie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"forbidden: the Origin header does not match the site origin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found: no such resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/admin/players/{id}/merge":{"post":{"operationId":"mergeAdminPlayer","tags":["admin"],"summary":"Merge a player into another","description":"All rows of {id} move to into, {id} becomes an alias of into. Reversible only through a rebuild plus alias removal.","security":[{"adminCookie":[]}],"parameters":[{"$ref":"#/components/parameters/PlayerId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MergeRequest"}}}},"responses":{"200":{"description":"The surviving player.","headers":{"Cache-Control":{"$ref":"#/components/headers/NoStore"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPlayer"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized: no valid admin session cookie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"forbidden: the Origin header does not match the site origin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found: no such resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"conflict: a player cannot be merged into itself or into an alias.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/admin/players/{id}/aliases/{alias}":{"delete":{"operationId":"deleteAdminPlayerAlias","tags":["admin"],"summary":"Remove an alias","security":[{"adminCookie":[]}],"parameters":[{"$ref":"#/components/parameters/PlayerId"},{"$ref":"#/components/parameters/Alias"}],"responses":{"204":{"description":"Removed."},"401":{"description":"unauthorized: no valid admin session cookie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"forbidden: the Origin header does not match the site origin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found: no such resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/admin/events":{"get":{"operationId":"listAdminEvents","tags":["admin"],"summary":"Raw events","security":[{"adminCookie":[]}],"parameters":[{"name":"type","in":"query","required":false,"description":"Only this event type.","schema":{"$ref":"#/components/schemas/EventType"}},{"name":"run_id","in":"query","required":false,"description":"Only this run.","schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/PlayerFilter"},{"$ref":"#/components/parameters/Since"},{"$ref":"#/components/parameters/Until"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"Raw envelopes newest first.","headers":{"Cache-Control":{"$ref":"#/components/headers/NoStore"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventPage"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized: no valid admin session cookie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/admin/events/{id}":{"get":{"operationId":"getAdminEvent","tags":["admin"],"summary":"One raw event","security":[{"adminCookie":[]}],"parameters":[{"$ref":"#/components/parameters/EventId"}],"responses":{"200":{"description":"The event with received_at.","headers":{"Cache-Control":{"$ref":"#/components/headers/NoStore"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoredEvent"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized: no valid admin session cookie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found: no such resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/admin/projections/rebuild":{"post":{"operationId":"rebuildProjections","tags":["admin"],"summary":"Rebuild projections","description":"Truncates every projection table and replays events in (ts, seq) order.","security":[{"adminCookie":[]}],"responses":{"202":{"description":"Queued.","headers":{"Cache-Control":{"$ref":"#/components/headers/NoStore"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobAccepted"}}}},"401":{"description":"unauthorized: no valid admin session cookie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"forbidden: the Origin header does not match the site origin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"conflict: a rebuild is already running.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/admin/backups/run":{"post":{"operationId":"runBackup","tags":["admin"],"summary":"Run a backup now","security":[{"adminCookie":[]}],"responses":{"202":{"description":"Queued.","headers":{"Cache-Control":{"$ref":"#/components/headers/NoStore"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobAccepted"}}}},"401":{"description":"unauthorized: no valid admin session cookie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"forbidden: the Origin header does not match the site origin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"conflict: a backup is already running.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/admin/backups":{"get":{"operationId":"listBackups","tags":["admin"],"summary":"Backups on the volume","security":[{"adminCookie":[]}],"responses":{"200":{"description":"Newest first.","headers":{"Cache-Control":{"$ref":"#/components/headers/NoStore"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupList"}}}},"401":{"description":"unauthorized: no valid admin session cookie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/admin/jobs/{id}":{"get":{"operationId":"getJob","tags":["admin"],"summary":"Job state","security":[{"adminCookie":[]}],"parameters":[{"$ref":"#/components/parameters/JobId"}],"responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/NoStore"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized: no valid admin session cookie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found: no such resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/admin/health":{"get":{"operationId":"getAdminHealth","tags":["admin"],"summary":"Telemetry health","security":[{"adminCookie":[]}],"responses":{"200":{"description":"OK","headers":{"Cache-Control":{"$ref":"#/components/headers/NoStore"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminHealth"}}}},"401":{"description":"unauthorized: no valid admin session cookie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/admin/announcements":{"get":{"operationId":"listAnnouncements","tags":["admin"],"summary":"Announcements","description":"The 50 most recent announcements, newest first, with their delivery state.","security":[{"adminCookie":[]}],"responses":{"200":{"description":"Newest first.","headers":{"Cache-Control":{"$ref":"#/components/headers/NoStore"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnnouncementList"}}}},"401":{"description":"unauthorized: no valid admin session cookie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createAnnouncement","tags":["admin"],"summary":"Announce in game","description":"Queues a one-off centre-screen message or a restart countdown. The plugin collects pending announcements with its next ingest response (within a minute while the server is idle), shows a message at once and counts a restart down with banners at 15, 10, 5 and 1 minutes before restart_at and one more at the time itself. restart_at must lie between 60 seconds and 24 hours ahead.","security":[{"adminCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnnouncementCreate"}}}},"responses":{"201":{"description":"Queued.","headers":{"Cache-Control":{"$ref":"#/components/headers/NoStore"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Announcement"}}}},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized: no valid admin session cookie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"forbidden: the Origin header does not match the site origin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/admin/announcements/{id}":{"delete":{"operationId":"cancelAnnouncement","tags":["admin"],"summary":"Cancel an announcement","description":"Cancels a pending or delivered announcement. A cancelled restart countdown stops at the plugin's next ingest response.","security":[{"adminCookie":[]}],"parameters":[{"$ref":"#/components/parameters/AnnouncementId"}],"responses":{"204":{"description":"Cancelled."},"400":{"description":"bad_request: a parameter or body field is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"unauthorized: no valid admin session cookie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"forbidden: the Origin header does not match the site origin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"not_found: no such resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"conflict: the announcement was already shown, cancelled or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/ingest":{"post":{"operationId":"ingestBatch","tags":["ingest"],"summary":"Ingest an event batch","description":"Verifies the timestamp window (5 minutes) and the HMAC with a constant-time comparison, sorts by seq, inserts events with ON CONFLICT DO NOTHING, applies projections for inserted rows in the same transaction and publishes accepted events to the stream.","security":[{"telemetrySignature":[]}],"parameters":[{"$ref":"#/components/parameters/TelemetryTimestamp"},{"$ref":"#/components/parameters/TelemetrySignature"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestBatch"}}}},"responses":{"200":{"description":"Counts for the batch.","headers":{"Cache-Control":{"$ref":"#/components/headers/NoStore"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestResult"}}}},"401":{"description":"unauthorized: bad signature or stale timestamp.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"payload_too_large: body over 1 MB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"unprocessable: malformed batch.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: database unavailable; the plugin retries.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/ingest/map":{"post":{"operationId":"ingestMap","tags":["ingest"],"summary":"Upload the world map image","description":"Body is a PNG. The signature is the HMAC over timestamp + \".\" + sha256hex(body). Stored per world uid, replacing any previous image for that uid. Limit 16 MB.","security":[{"telemetrySignature":[]}],"parameters":[{"$ref":"#/components/parameters/TelemetryTimestamp"},{"$ref":"#/components/parameters/TelemetrySignature"},{"name":"X-World-Uid","in":"header","required":true,"description":"World uid the image belongs to.","schema":{"type":"integer"}},{"name":"X-Map-Size","in":"header","required":true,"description":"Pixels per side.","schema":{"type":"integer","minimum":1}},{"name":"X-Map-Radius","in":"header","required":true,"description":"Metres represented by half the side.","schema":{"type":"number","minimum":1}}],"requestBody":{"required":true,"content":{"image/png":{"schema":{"type":"string","contentMediaType":"image/png"}}}},"responses":{"204":{"description":"Stored."},"401":{"description":"unauthorized: bad signature or stale timestamp.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"payload_too_large: body over 16 MB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"unprocessable: not a PNG or headers missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/ingest/catalogue":{"post":{"operationId":"ingestCatalogue","tags":["ingest"],"summary":"Upload the comfort catalogue","description":"Sent by the plugin at every server start. The signature is the HMAC over timestamp + \".\" + sha256hex(body), as for the map upload. Stored per game version, replacing any previous catalogue for that version. Limit 512 KB, the server's request body limit.","security":[{"telemetrySignature":[]}],"parameters":[{"$ref":"#/components/parameters/TelemetryTimestamp"},{"$ref":"#/components/parameters/TelemetrySignature"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ComfortCatalogueUpload"}}}},"responses":{"204":{"description":"Stored."},"401":{"description":"unauthorized: bad signature or stale timestamp.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"payload_too_large: body over 512 KB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"unprocessable: the body is not JSON, does not match the schema, names a prefab twice or holds a date or text the database cannot store.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"not_implemented: the handler is not built yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"unavailable: the database cannot be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"adminCookie":{"type":"apiKey","in":"cookie","name":"admin_session","description":"Session cookie set by POST /api/v1/admin/login."},"telemetrySignature":{"type":"apiKey","in":"header","name":"X-Telemetry-Signature","description":"sha256=<hex HMAC-SHA256> over X-Telemetry-Timestamp + \".\" + body with the shared telemetry secret (TELEMETRY_SECRET, or the one on the admin Plugin page)."}},"headers":{"CacheControl":{"description":"public, max-age=15 on public GET responses.","schema":{"type":"string"}},"ETag":{"description":"Entity tag of the response body.","schema":{"type":"string"}},"NoStore":{"description":"no-store on stream and admin responses.","schema":{"type":"string"}}},"parameters":{"Limit":{"name":"limit","in":"query","required":false,"description":"Page size.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},"Cursor":{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from a previous next_cursor.","schema":{"type":"string"}},"Since":{"name":"since","in":"query","required":false,"description":"Only items at or after this time.","schema":{"type":"string","format":"date-time"}},"Until":{"name":"until","in":"query","required":false,"description":"Only items before this time.","schema":{"type":"string","format":"date-time"}},"Types":{"name":"types","in":"query","required":false,"description":"Restrict to these event types.","schema":{"type":"string","description":"Comma-separated list of event types."}},"PlayerFilter":{"name":"player","in":"query","required":false,"description":"Only items involving this player id.","schema":{"type":"integer"}},"PlayerId":{"name":"id","in":"path","required":true,"description":"Player id.","schema":{"type":"integer"}},"BossKey":{"name":"key","in":"path","required":true,"description":"Boss key, for example defeated_eikthyr.","schema":{"type":"string"}},"RaidId":{"name":"id","in":"path","required":true,"description":"Raid id.","schema":{"type":"integer"}},"EventId":{"name":"id","in":"path","required":true,"description":"Event id.","schema":{"type":"string","format":"uuid"}},"JobId":{"name":"id","in":"path","required":true,"description":"Job id.","schema":{"type":"integer"}},"AnnouncementId":{"name":"id","in":"path","required":true,"description":"Announcement id.","schema":{"type":"integer"}},"Alias":{"name":"alias","in":"path","required":true,"description":"Raw platform user id of the alias.","schema":{"type":"string"}},"ZoneName":{"name":"name","in":"path","required":true,"description":"Character name, normalised: trimmed, inner whitespace collapsed, upper-cased.","schema":{"type":"string","minLength":1,"maxLength":48}},"LastEventId":{"name":"Last-Event-ID","in":"header","required":false,"description":"Sent by EventSource on reconnect; activity items newer than this id are replayed first (at most 100).","schema":{"type":"string"}},"TelemetryTimestamp":{"name":"X-Telemetry-Timestamp","in":"header","required":true,"description":"Signature timestamp.","schema":{"type":"integer","description":"Unix seconds; must be within 5 minutes of the server clock."}},"TelemetrySignature":{"name":"X-Telemetry-Signature","in":"header","required":true,"description":"HMAC-SHA256 of timestamp + \".\" + body (or the body SHA-256 hex for the map and catalogue uploads) with the shared secret.","schema":{"type":"string","pattern":"^sha256=[0-9a-f]{64}$"}}},"schemas":{"Error":{"type":"object","description":"Error envelope returned with every non-2xx status.","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["bad_request","unauthorized","forbidden","not_found","conflict","payload_too_large","unprocessable","rate_limited","unavailable","not_implemented"]},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false},"Platform":{"type":"string","enum":["Steam","Xbox","PlayStation","Nintendo"],"description":"Platform prefix of the raw platform user id."},"Biome":{"type":"string","enum":["Meadows","BlackForest","Swamp","Mountain","Plains","Mistlands","AshLands","DeepNorth","Ocean","None"],"description":"Biome identifier exactly as the game names it."},"HitType":{"type":"string","enum":["EnemyHit","PlayerHit","Fall","Drowning","Burning","Freezing","Poisoned","Water","Smoke","EdgeOfWorld","Impact","Cart","Tree","Self","Structural","Turret","Boat","Stalagtite","Catapult","CinderFire","AshlandsOcean","AshlandsLava","Incinerator","DrawBridge","Undefined"],"description":"HitData hit type of the last server-observed damage before a death."},"EventType":{"type":"string","enum":["server.started","server.stopping","server.heartbeat","server.lost","world.save_started","world.saved","world.rollback_detected","world.dusk_approaching","world.dawn_approaching","player.joined","player.spawned","player.died","player.left","player.biome_changed","player.position","boss.summoned","boss.engaged","boss.defeated","global_key.set","raid.started","raid.ended","structure.built","structure.destroyed","creature.died","chat.message","announcement.shown"],"description":"Every event type in the catalogue, including the four synthetic ones written by the backend (server.lost, world.rollback_detected, world.dusk_approaching, world.dawn_approaching)."},"LeftReason":{"type":"string","enum":["disconnect","timeout","kicked","server_stop","reconciled","server_lost"],"description":"Why a session ended. reconciled and server_lost are assigned by the backend."},"PlayerRef":{"type":"object","description":"Reference to a player wherever a player is named. Hidden players appear as null instead of this object.","properties":{"id":{"type":"integer","description":"Player id."},"display_name":{"type":"string"},"platform":{"$ref":"#/components/schemas/Platform"}},"required":["id","display_name","platform"],"additionalProperties":false},"StatusWorld":{"type":"object","properties":{"name":{"type":"string"},"uid":{"type":"integer","description":"World uid (the world seed identifier as a 64-bit integer)."},"day":{"type":"integer","description":"Current world day."},"time_of_day":{"type":"number","minimum":0,"maximum":1,"description":"Fraction of the current day that has elapsed, 0 at midnight."},"net_time":{"type":"number","description":"World time in seconds as reported by the server."}},"required":["name","uid","day","time_of_day","net_time"],"additionalProperties":false},"StatusRun":{"type":"object","properties":{"run_id":{"type":"string","format":"uuid","description":"Identifier of the current server process run."},"started_at":{"type":"string","format":"date-time"},"uptime_s":{"type":"number"},"plugin_version":{"type":"string"}},"required":["run_id","started_at","uptime_s","plugin_version"],"additionalProperties":false},"StatusTelemetry":{"type":"object","properties":{"live":{"type":"boolean","description":"True while heartbeats arrive within the watchdog window."},"last_heartbeat_at":{"type":["string","null"],"format":"date-time"},"delayed_since":{"type":["string","null"],"format":"date-time","description":"Set when the plugin has been silent for longer than 180 s."}},"required":["live","last_heartbeat_at","delayed_since"],"additionalProperties":false},"Status":{"type":"object","description":"Server status as shown on the dashboard, in the status strip and on /api/status.","properties":{"online":{"type":"boolean"},"source":{"type":"string","enum":["plugin","a2s","none"],"description":"Which signal produced this status."},"player_count":{"type":"integer","minimum":0},"max_players":{"type":"integer","minimum":0},"game_version":{"type":["string","null"]},"network_version":{"type":["integer","null"]},"server_name":{"type":"string"},"world":{"anyOf":[{"$ref":"#/components/schemas/StatusWorld"},{"type":"null"}]},"run":{"anyOf":[{"$ref":"#/components/schemas/StatusRun"},{"type":"null"}]},"last_save_at":{"type":["string","null"],"format":"date-time"},"telemetry":{"$ref":"#/components/schemas/StatusTelemetry"},"updated_at":{"type":"string","format":"date-time"}},"required":["online","source","player_count","max_players","game_version","network_version","server_name","world","run","last_save_at","telemetry","updated_at"],"additionalProperties":false},"StatusHistoryPoint":{"type":"object","properties":{"ts":{"type":"string","format":"date-time"},"online":{"type":"boolean"},"player_count":{"type":"integer","minimum":0}},"required":["ts","online","player_count"],"additionalProperties":false},"StatusHistory":{"type":"object","properties":{"range":{"type":"string","enum":["24h","7d","30d"]},"step_s":{"type":"integer","minimum":1,"description":"Seconds between points after downsampling."},"items":{"type":"array","items":{"$ref":"#/components/schemas/StatusHistoryPoint"},"maxItems":600}},"required":["range","step_s","items"],"additionalProperties":false},"OnlinePlayer":{"type":"object","properties":{"player_id":{"type":"integer"},"display_name":{"type":"string"},"platform":{"$ref":"#/components/schemas/Platform"},"character_name":{"type":"string"},"biome":{"$ref":"#/components/schemas/Biome"},"x":{"type":["number","null"],"description":"World x coordinate in metres; the world is a disc of radius 10000 m centred on 0,0. Null when the site hides player positions."},"z":{"type":["number","null"],"description":"World z coordinate in metres; the world is a disc of radius 10000 m centred on 0,0. Null when the site hides player positions."},"since":{"type":"string","format":"date-time","description":"When the current session started."}},"required":["player_id","display_name","platform","character_name","biome","x","z","since"],"additionalProperties":false},"OnlineList":{"type":"object","description":"Players online right now. Hidden players are omitted.","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/OnlinePlayer"}}},"required":["items"],"additionalProperties":false},"Run":{"type":"object","properties":{"run_id":{"type":"string","format":"uuid"},"started_at":{"type":"string","format":"date-time"},"stopped_at":{"type":["string","null"],"format":"date-time"},"stop_reason":{"type":["string","null"],"enum":["graceful","inferred",null]},"game_version":{"type":["string","null"]},"plugin_version":{"type":["string","null"]},"peak_players":{"type":"integer","minimum":0},"saves":{"type":"integer","minimum":0}},"required":["run_id","started_at","stopped_at","stop_reason","game_version","plugin_version","peak_players","saves"],"additionalProperties":false},"RunPage":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Run"}},"next_cursor":{"type":["string","null"],"description":"Opaque cursor for the next page; null on the last page."}},"required":["items","next_cursor"],"additionalProperties":false},"PlayerListItem":{"type":"object","properties":{"id":{"type":"integer"},"display_name":{"type":"string"},"platform":{"$ref":"#/components/schemas/Platform"},"platform_user_id":{"type":["string","null"],"description":"Raw platform user id, for example Steam_76561198012345678. Null when the site hides platform ids."},"display_id":{"type":"string","description":"Display form used by the F2 panel and the list files, for example V_76561198012345678."},"online":{"type":"boolean"},"current_biome":{"anyOf":[{"$ref":"#/components/schemas/Biome"},{"type":"null"}]},"first_seen":{"type":"string","format":"date-time"},"last_seen":{"type":"string","format":"date-time"},"playtime_s":{"type":"number","minimum":0},"sessions":{"type":"integer","minimum":0},"deaths":{"type":"integer","minimum":0},"kills":{"type":"integer","minimum":0,"description":"Creature kills, credited and by proximity together."},"boss_kills":{"type":"integer","minimum":0},"structures_built":{"type":"integer","minimum":0},"distance_m":{"type":"number","minimum":0},"characters":{"type":"array","items":{"type":"string"},"description":"Character names, latest first."}},"required":["id","display_name","platform","platform_user_id","display_id","online","current_biome","first_seen","last_seen","playtime_s","sessions","deaths","kills","boss_kills","structures_built","distance_m","characters"],"additionalProperties":false},"PlayerPage":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/PlayerListItem"}},"next_cursor":{"type":["string","null"],"description":"Opaque cursor for the next page; null on the last page."}},"required":["items","next_cursor"],"additionalProperties":false},"Character":{"type":"object","properties":{"character_id":{"type":"integer","description":"Character profile id (a 64-bit integer generated by the game)."},"name":{"type":"string"},"first_seen":{"type":"string","format":"date-time"},"last_seen":{"type":"string","format":"date-time"}},"required":["character_id","name","first_seen","last_seen"],"additionalProperties":false},"CurrentSession":{"type":"object","properties":{"joined_at":{"type":"string","format":"date-time"},"character_name":{"type":"string"},"biome":{"$ref":"#/components/schemas/Biome"},"x":{"type":["number","null"],"description":"World x coordinate in metres; the world is a disc of radius 10000 m centred on 0,0. Null when the site hides player positions."},"z":{"type":["number","null"],"description":"World z coordinate in metres; the world is a disc of radius 10000 m centred on 0,0. Null when the site hides player positions."}},"required":["joined_at","character_name","biome","x","z"],"additionalProperties":false},"PlayerStats":{"type":"object","properties":{"playtime_s":{"type":"number","minimum":0},"sessions":{"type":"integer","minimum":0},"deaths":{"type":"integer","minimum":0},"kills_credited":{"type":"integer","minimum":0},"kills_nearby":{"type":"integer","minimum":0},"boss_kills":{"type":"integer","minimum":0},"raids":{"type":"integer","minimum":0},"structures_built":{"type":"integer","minimum":0},"structures_destroyed":{"type":"integer","minimum":0},"shouts":{"type":"integer","minimum":0},"distance_m":{"type":"number","minimum":0}},"required":["playtime_s","sessions","deaths","kills_credited","kills_nearby","boss_kills","raids","structures_built","structures_destroyed","shouts","distance_m"],"additionalProperties":false},"PlayerBiome":{"type":"object","properties":{"biome":{"$ref":"#/components/schemas/Biome"},"first_at":{"type":"string","format":"date-time"},"first_day":{"type":"integer"},"visits":{"type":"integer","minimum":1},"last_at":{"type":"string","format":"date-time"}},"required":["biome","first_at","first_day","visits","last_at"],"additionalProperties":false},"KillsByCreature":{"type":"object","properties":{"creature":{"type":"string","description":"Resolved creature name."},"credited":{"type":"integer","minimum":0},"nearby":{"type":"integer","minimum":0}},"required":["creature","credited","nearby"],"additionalProperties":false},"BossParticipation":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"at":{"type":"string","format":"date-time"},"day":{"type":"integer"},"role":{"type":"string","enum":["credited","nearby"]}},"required":["key","name","at","day","role"],"additionalProperties":false},"PlayerRaid":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"label":{"type":"string"},"at":{"type":"string","format":"date-time"},"day":{"type":"integer"},"survived":{"type":"boolean"}},"required":["id","name","label","at","day","survived"],"additionalProperties":false},"Player":{"type":"object","description":"The player list item plus everything the player page shows.","properties":{"id":{"type":"integer"},"display_name":{"type":"string"},"platform":{"$ref":"#/components/schemas/Platform"},"platform_user_id":{"type":["string","null"],"description":"Raw platform user id, for example Steam_76561198012345678. Null when the site hides platform ids."},"display_id":{"type":"string","description":"Display form used by the F2 panel and the list files, for example V_76561198012345678."},"online":{"type":"boolean"},"current_biome":{"anyOf":[{"$ref":"#/components/schemas/Biome"},{"type":"null"}]},"first_seen":{"type":"string","format":"date-time"},"last_seen":{"type":"string","format":"date-time"},"playtime_s":{"type":"number","minimum":0},"sessions":{"type":"integer","minimum":0},"deaths":{"type":"integer","minimum":0},"kills":{"type":"integer","minimum":0,"description":"Creature kills, credited and by proximity together."},"boss_kills":{"type":"integer","minimum":0},"structures_built":{"type":"integer","minimum":0},"distance_m":{"type":"number","minimum":0},"characters":{"type":"array","items":{"$ref":"#/components/schemas/Character"}},"current_session":{"anyOf":[{"$ref":"#/components/schemas/CurrentSession"},{"type":"null"}]},"stats":{"$ref":"#/components/schemas/PlayerStats"},"biomes":{"type":"array","items":{"$ref":"#/components/schemas/PlayerBiome"}},"deaths_by_cause":{"type":"object","description":"Death counts keyed by observed hit type, with \"unknown\" for deaths whose fatal hits the server never saw.","additionalProperties":{"type":"integer","minimum":0}},"kills_by_creature":{"type":"array","items":{"$ref":"#/components/schemas/KillsByCreature"}},"boss_participation":{"type":"array","items":{"$ref":"#/components/schemas/BossParticipation"}},"raids":{"type":"array","items":{"$ref":"#/components/schemas/PlayerRaid"}},"aliases":{"type":"array","items":{"type":"string"},"description":"Raw platform user ids merged into this player."}},"required":["id","display_name","platform","platform_user_id","display_id","online","current_biome","first_seen","last_seen","playtime_s","sessions","deaths","kills","boss_kills","structures_built","distance_m","characters","current_session","stats","biomes","deaths_by_cause","kills_by_creature","boss_participation","raids","aliases"],"additionalProperties":false},"Session":{"type":"object","properties":{"id":{"type":"integer"},"joined_at":{"type":"string","format":"date-time"},"left_at":{"type":["string","null"],"format":"date-time"},"duration_s":{"type":["number","null"],"minimum":0},"left_reason":{"anyOf":[{"$ref":"#/components/schemas/LeftReason"},{"type":"null"}]},"character_name":{"type":"string"},"run_id":{"type":"string","format":"uuid"}},"required":["id","joined_at","left_at","duration_s","left_reason","character_name","run_id"],"additionalProperties":false},"SessionPage":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Session"}},"next_cursor":{"type":["string","null"],"description":"Opaque cursor for the next page; null on the last page."}},"required":["items","next_cursor"],"additionalProperties":false},"DeathCause":{"type":"object","description":"Present only when the fatal hits were relayed through the server.","properties":{"hit_type":{"$ref":"#/components/schemas/HitType"},"attacker_prefab":{"type":["string","null"]},"attacker":{"anyOf":[{"$ref":"#/components/schemas/PlayerRef"},{"type":"null"}]}},"required":["hit_type","attacker_prefab","attacker"],"additionalProperties":false},"Death":{"type":"object","properties":{"id":{"type":"integer"},"at":{"type":"string","format":"date-time"},"day":{"type":"integer"},"biome":{"$ref":"#/components/schemas/Biome"},"x":{"type":"number","description":"World x coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"z":{"type":"number","description":"World z coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"cause":{"anyOf":[{"$ref":"#/components/schemas/DeathCause"},{"type":"null"}]}},"required":["id","at","day","biome","x","z","cause"],"additionalProperties":false},"DeathPage":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Death"}},"next_cursor":{"type":["string","null"],"description":"Opaque cursor for the next page; null on the last page."}},"required":["items","next_cursor"],"additionalProperties":false},"RecentKill":{"type":"object","properties":{"at":{"type":"string","format":"date-time"},"creature":{"type":"string"},"level":{"type":"integer","minimum":1},"boss":{"type":"boolean"},"basis":{"type":"string","enum":["credited","nearby"]}},"required":["at","creature","level","boss","basis"],"additionalProperties":false},"PlayerKills":{"type":"object","properties":{"credited":{"type":"integer","minimum":0},"nearby":{"type":"integer","minimum":0},"by_creature":{"type":"array","items":{"$ref":"#/components/schemas/KillsByCreature"}},"recent":{"type":"array","items":{"$ref":"#/components/schemas/RecentKill"},"maxItems":50}},"required":["credited","nearby","by_creature","recent"],"additionalProperties":false},"Position":{"type":"object","properties":{"ts":{"type":"string","format":"date-time"},"x":{"type":"number","description":"World x coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"z":{"type":"number","description":"World z coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"biome":{"$ref":"#/components/schemas/Biome"}},"required":["ts","x","z","biome"],"additionalProperties":false},"PositionList":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Position"},"description":"Oldest first, downsampled to the requested limit."}},"required":["items"],"additionalProperties":false},"StructuresByPrefab":{"type":"object","properties":{"prefab":{"type":"string"},"built":{"type":"integer","minimum":0}},"required":["prefab","built"],"additionalProperties":false},"RecentStructure":{"type":"object","properties":{"at":{"type":"string","format":"date-time"},"prefab":{"type":"string"},"x":{"type":"number","description":"World x coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"z":{"type":"number","description":"World z coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"biome":{"$ref":"#/components/schemas/Biome"}},"required":["at","prefab","x","z","biome"],"additionalProperties":false},"PlayerStructures":{"type":"object","properties":{"built":{"type":"integer","minimum":0},"destroyed":{"type":"integer","minimum":0},"by_prefab":{"type":"array","items":{"$ref":"#/components/schemas/StructuresByPrefab"}},"recent":{"type":"array","items":{"$ref":"#/components/schemas/RecentStructure"}}},"required":["built","destroyed","by_prefab","recent"],"additionalProperties":false},"FirstKill":{"type":"object","properties":{"at":{"type":"string","format":"date-time"},"day":{"type":"integer"},"participants":{"type":"array","items":{"anyOf":[{"$ref":"#/components/schemas/PlayerRef"},{"type":"null"}]}}},"required":["at","day","participants"],"additionalProperties":false},"BossDefeat":{"type":"object","description":"The earliest evidence that the world has defeated this boss. observed is true when the plugin saw the first kill, in which case since and day equal first_kill. observed is false when the boss's key was already among the world's saved global keys when the log first saw it: the kill itself predates the log, and since and day only say when the log learned of it.","properties":{"since":{"type":"string","format":"date-time"},"day":{"type":"integer"},"observed":{"type":"boolean"}},"required":["since","day","observed"],"additionalProperties":false},"Boss":{"type":"object","properties":{"key":{"type":"string","description":"Global key the boss's defeat sets, for example defeated_eikthyr; the final phase's key for a boss with several phases."},"name":{"type":"string","description":"Resolved boss name, or the prefab or raw key when unknown."},"tier":{"type":"string","enum":["forsaken","mini","other"],"description":"forsaken for the eight bosses of the progression, mini for the named foes whose defeat sets a key without being a boss to the game, other for any further key the world has defeated."},"order":{"type":"integer","minimum":1,"description":"Position within the tier; the game's kill order for the Forsaken."},"summons":{"type":"integer","minimum":0},"engaged":{"type":"integer","minimum":0},"kills":{"type":"integer","minimum":0,"description":"Kills the plugin observed; zero for a boss defeated before the log began."},"first_kill":{"anyOf":[{"$ref":"#/components/schemas/FirstKill"},{"type":"null"}]},"last_kill_at":{"type":["string","null"],"format":"date-time"},"active":{"type":"boolean","description":"True while an instance of this boss is engaged."},"defeat":{"anyOf":[{"$ref":"#/components/schemas/BossDefeat"},{"type":"null"}],"description":"Null until the world has defeated this boss at least once, whether or not the log saw the kill."}},"required":["key","name","tier","order","summons","engaged","kills","first_kill","last_kill_at","active","defeat"],"additionalProperties":false},"BossList":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Boss"},"description":"Ordered by order."}},"required":["items"],"additionalProperties":false},"BossEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Event id."},"kind":{"type":"string","enum":["summoned","engaged","phase","defeated"],"description":"phase marks the end of an earlier phase of a boss that fights in several."},"phase":{"type":["integer","null"],"minimum":1,"description":"The phase this event belongs to for a boss with several phases, else null."},"at":{"type":"string","format":"date-time"},"day":{"type":"integer"},"x":{"type":["number","null"],"description":"World x coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"z":{"type":["number","null"],"description":"World z coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"biome":{"anyOf":[{"$ref":"#/components/schemas/Biome"},{"type":"null"}]},"participants":{"type":"array","items":{"anyOf":[{"$ref":"#/components/schemas/PlayerRef"},{"type":"null"}]}},"nearby":{"type":"array","items":{"anyOf":[{"$ref":"#/components/schemas/PlayerRef"},{"type":"null"}]}},"summoner":{"anyOf":[{"$ref":"#/components/schemas/PlayerRef"},{"type":"null"}]},"first_time":{"type":["boolean","null"],"description":"Set on defeated and phase events; true the first time the world set that key."}},"required":["id","kind","phase","at","day","x","z","biome","participants","nearby","summoner","first_time"],"additionalProperties":false},"BossDetail":{"type":"object","properties":{"key":{"type":"string","description":"Global key the boss's defeat sets, for example defeated_eikthyr; the final phase's key for a boss with several phases."},"name":{"type":"string","description":"Resolved boss name, or the prefab or raw key when unknown."},"tier":{"type":"string","enum":["forsaken","mini","other"],"description":"forsaken for the eight bosses of the progression, mini for the named foes whose defeat sets a key without being a boss to the game, other for any further key the world has defeated."},"order":{"type":"integer","minimum":1,"description":"Position within the tier; the game's kill order for the Forsaken."},"summons":{"type":"integer","minimum":0},"engaged":{"type":"integer","minimum":0},"kills":{"type":"integer","minimum":0,"description":"Kills the plugin observed; zero for a boss defeated before the log began."},"first_kill":{"anyOf":[{"$ref":"#/components/schemas/FirstKill"},{"type":"null"}]},"last_kill_at":{"type":["string","null"],"format":"date-time"},"active":{"type":"boolean","description":"True while an instance of this boss is engaged."},"defeat":{"anyOf":[{"$ref":"#/components/schemas/BossDefeat"},{"type":"null"}],"description":"Null until the world has defeated this boss at least once, whether or not the log saw the kill."},"events":{"type":"array","items":{"$ref":"#/components/schemas/BossEvent"},"maxItems":50,"description":"The last 50 events, newest first."}},"required":["key","name","tier","order","summons","engaged","kills","first_kill","last_kill_at","active","defeat","events"],"additionalProperties":false},"BossEventPage":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/BossEvent"}},"next_cursor":{"type":["string","null"],"description":"Opaque cursor for the next page; null on the last page."}},"required":["items","next_cursor"],"additionalProperties":false},"Raid":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string","description":"Raw random event name, for example army_eikthyr."},"label":{"type":"string","description":"Resolved label, for example Eikthyr rallies the creatures of the forest."},"biome":{"$ref":"#/components/schemas/Biome"},"x":{"type":"number","description":"World x coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"z":{"type":"number","description":"World z coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"day":{"type":"integer"},"started_at":{"type":"string","format":"date-time"},"ended_at":{"type":["string","null"],"format":"date-time"},"duration_s":{"type":["number","null"],"minimum":0},"planned_duration_s":{"type":"number","minimum":0},"participants":{"type":"array","items":{"anyOf":[{"$ref":"#/components/schemas/PlayerRef"},{"type":"null"}]}},"deaths_during":{"type":"integer","minimum":0},"end_reason":{"type":["string","null"],"enum":["ended","server_stop","server_lost",null],"description":"Why the raid is over, null while it runs. ended is the game's own end; server_stop and server_lost mean the server run stopped while the raid was pending and no later server start has resumed it."},"restored":{"type":"boolean","description":"The raid was already under way when the server started, so started_at is that server start rather than the raid's beginning."},"active_s":{"type":["number","null"],"minimum":0,"description":"Seconds the raid timer actually ran, reported by the plugin at raid.ended; the game pauses the timer while nobody is inside the raid area. Null while the raid runs or when the plugin did not report it."}},"required":["id","name","label","biome","x","z","day","started_at","ended_at","duration_s","planned_duration_s","participants","deaths_during","end_reason","restored","active_s"],"additionalProperties":false},"RaidPage":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Raid"}},"next_cursor":{"type":["string","null"],"description":"Opaque cursor for the next page; null on the last page."}},"required":["items","next_cursor"],"additionalProperties":false},"RaidDeath":{"type":"object","properties":{"player":{"anyOf":[{"$ref":"#/components/schemas/PlayerRef"},{"type":"null"}]},"at":{"type":"string","format":"date-time"},"x":{"type":"number","description":"World x coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"z":{"type":"number","description":"World z coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."}},"required":["player","at","x","z"],"additionalProperties":false},"RaidDetail":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string","description":"Raw random event name, for example army_eikthyr."},"label":{"type":"string","description":"Resolved label, for example Eikthyr rallies the creatures of the forest."},"biome":{"$ref":"#/components/schemas/Biome"},"x":{"type":"number","description":"World x coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"z":{"type":"number","description":"World z coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"day":{"type":"integer"},"started_at":{"type":"string","format":"date-time"},"ended_at":{"type":["string","null"],"format":"date-time"},"duration_s":{"type":["number","null"],"minimum":0},"planned_duration_s":{"type":"number","minimum":0},"participants":{"type":"array","items":{"anyOf":[{"$ref":"#/components/schemas/PlayerRef"},{"type":"null"}]}},"deaths_during":{"type":"integer","minimum":0},"end_reason":{"type":["string","null"],"enum":["ended","server_stop","server_lost",null],"description":"Why the raid is over, null while it runs. ended is the game's own end; server_stop and server_lost mean the server run stopped while the raid was pending and no later server start has resumed it."},"restored":{"type":"boolean","description":"The raid was already under way when the server started, so started_at is that server start rather than the raid's beginning."},"active_s":{"type":["number","null"],"minimum":0,"description":"Seconds the raid timer actually ran, reported by the plugin at raid.ended; the game pauses the timer while nobody is inside the raid area. Null while the raid runs or when the plugin did not report it."},"deaths":{"type":"array","items":{"$ref":"#/components/schemas/RaidDeath"}}},"required":["id","name","label","biome","x","z","day","started_at","ended_at","duration_s","planned_duration_s","participants","deaths_during","end_reason","restored","active_s","deaths"],"additionalProperties":false},"ProgressionKey":{"type":"object","properties":{"key":{"type":"string"},"value":{"type":["string","null"]},"category":{"type":"string","enum":["boss","mini_boss","modifier","other"]},"first_set_at":{"type":"string","format":"date-time"},"day":{"type":"integer"}},"required":["key","value","category","first_set_at","day"],"additionalProperties":false},"ProgressionList":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ProgressionKey"}}},"required":["items"],"additionalProperties":false},"WorldSaves":{"type":"object","properties":{"last_at":{"type":["string","null"],"format":"date-time"},"count_24h":{"type":"integer","minimum":0},"avg_duration_ms":{"type":["number","null"],"minimum":0}},"required":["last_at","count_24h","avg_duration_ms"],"additionalProperties":false},"WorldRollback":{"type":"object","properties":{"detected_at":{"type":"string","format":"date-time"},"from_net_time":{"type":"number"},"to_net_time":{"type":"number"}},"required":["detected_at","from_net_time","to_net_time"],"additionalProperties":false},"WorldMap":{"type":"object","properties":{"available":{"type":"boolean"},"image_url":{"type":["string","null"],"description":"Path of the map image, /api/v1/world/map.png when available."},"size_px":{"type":["integer","null"],"minimum":1},"radius_m":{"type":["number","null"],"minimum":1},"generated_at":{"type":["string","null"],"format":"date-time"}},"required":["available","image_url","size_px","radius_m","generated_at"],"additionalProperties":false},"World":{"type":"object","properties":{"name":{"type":"string"},"uid":{"type":"integer"},"day":{"type":"integer"},"net_time":{"type":"number"},"day_length_s":{"type":"number","minimum":1},"saves":{"$ref":"#/components/schemas/WorldSaves"},"rollbacks":{"type":"array","items":{"$ref":"#/components/schemas/WorldRollback"}},"map":{"anyOf":[{"$ref":"#/components/schemas/WorldMap"},{"type":"null"}]}},"required":["name","uid","day","net_time","day_length_s","saves","rollbacks","map"],"additionalProperties":false},"Save":{"type":"object","properties":{"at":{"type":"string","format":"date-time"},"duration_ms":{"type":"integer","minimum":0}},"required":["at","duration_ms"],"additionalProperties":false},"SavePage":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Save"}},"next_cursor":{"type":["string","null"],"description":"Opaque cursor for the next page; null on the last page."}},"required":["items","next_cursor"],"additionalProperties":false},"ChatMessage":{"type":"object","properties":{"id":{"type":"integer"},"at":{"type":"string","format":"date-time"},"day":{"type":"integer"},"kind":{"type":"string","enum":["shout","ping","say"]},"player":{"anyOf":[{"$ref":"#/components/schemas/PlayerRef"},{"type":"null"}]},"text":{"type":["string","null"]},"x":{"type":"number","description":"World x coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"z":{"type":"number","description":"World z coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"biome":{"$ref":"#/components/schemas/Biome"}},"required":["id","at","day","kind","player","text","x","z","biome"],"additionalProperties":false},"ChatPage":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ChatMessage"}},"next_cursor":{"type":["string","null"],"description":"Opaque cursor for the next page; null on the last page."}},"required":["items","next_cursor"],"additionalProperties":false},"StructuresSeriesPoint":{"type":"object","properties":{"date":{"type":"string","format":"date"},"built":{"type":"integer","minimum":0},"destroyed":{"type":"integer","minimum":0}},"required":["date","built","destroyed"],"additionalProperties":false},"StructuresByBuilder":{"type":"object","properties":{"player":{"anyOf":[{"$ref":"#/components/schemas/PlayerRef"},{"type":"null"}]},"built":{"type":"integer","minimum":0},"world":{"type":"boolean","description":"True for the pieces the game placed itself while generating villages, camps and forts; player is then null."}},"required":["player","built","world"],"additionalProperties":false},"Structures":{"type":"object","properties":{"built_total":{"type":"integer","minimum":0},"destroyed_total":{"type":"integer","minimum":0},"series":{"type":"array","items":{"$ref":"#/components/schemas/StructuresSeriesPoint"}},"by_builder":{"type":"array","items":{"$ref":"#/components/schemas/StructuresByBuilder"}},"by_prefab":{"type":"array","items":{"$ref":"#/components/schemas/StructuresByPrefab"}}},"required":["built_total","destroyed_total","series","by_builder","by_prefab"],"additionalProperties":false},"StructureEvent":{"type":"object","properties":{"at":{"type":"string","format":"date-time"},"kind":{"type":"string","enum":["built","destroyed"]},"prefab":{"type":"string"},"x":{"type":"number","description":"World x coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"z":{"type":"number","description":"World z coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"biome":{"$ref":"#/components/schemas/Biome"},"player":{"anyOf":[{"$ref":"#/components/schemas/PlayerRef"},{"type":"null"}]}},"required":["at","kind","prefab","x","z","biome","player"],"additionalProperties":false},"StructureEventPage":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/StructureEvent"}},"next_cursor":{"type":["string","null"],"description":"Opaque cursor for the next page; null on the last page."}},"required":["items","next_cursor"],"additionalProperties":false},"ComfortCondition":{"type":"string","enum":["lit","lit_dry"],"description":"lit, the piece counts only while it burns or is heated; lit_dry, only while it burns and neither rain nor strong wind has dampened it."},"ComfortSeason":{"type":"object","description":"A yearly window in which the game offers its seasonal pieces for building, on each player's own calendar.","properties":{"name":{"type":"string","minLength":1,"maxLength":64},"start_day":{"type":"integer","minimum":1,"maximum":31},"start_month":{"type":"integer","minimum":1,"maximum":12},"end_day":{"type":"integer","minimum":1,"maximum":31},"end_month":{"type":"integer","minimum":1,"maximum":12}},"required":["name","start_day","start_month","end_day","end_month"],"additionalProperties":false},"ComfortCatalogueEntry":{"type":"object","description":"A build piece that adds comfort, as the running game defines it.","properties":{"prefab":{"type":"string","minLength":1,"maxLength":128,"description":"Prefab name, the same key structure events carry."},"token":{"type":"string","maxLength":128,"description":"Localization token of the piece name; pieces without a group stack only when their tokens differ."},"name":{"type":"string","minLength":1,"maxLength":128,"description":"The name the server's localization gives the token."},"comfort":{"type":"integer","minimum":1,"maximum":1000},"group":{"type":"string","minLength":1,"maxLength":64,"description":"The game's comfort group; None means the piece belongs to no group."},"condition":{"anyOf":[{"$ref":"#/components/schemas/ComfortCondition"},{"type":"null"}],"description":"null when the piece always counts."},"season":{"type":["string","null"],"minLength":1,"maxLength":64,"description":"The season the piece can only be built in, or null when it is always available."}},"required":["prefab","token","name","comfort","group","condition","season"],"additionalProperties":false},"ComfortPiece":{"type":"object","description":"A comfort piece with this server's building record.","properties":{"prefab":{"type":"string","description":"Prefab name, the same key structure events carry."},"token":{"type":"string","description":"Localization token of the piece name; pieces without a group stack only when their tokens differ."},"name":{"type":"string"},"comfort":{"type":"integer","minimum":1},"group":{"type":"string","description":"The game's comfort group; None means the piece belongs to no group."},"condition":{"anyOf":[{"$ref":"#/components/schemas/ComfortCondition"},{"type":"null"}],"description":"null when the piece always counts."},"season":{"type":["string","null"],"description":"The season the piece can only be built in, or null when it is always available."},"built":{"type":"integer","minimum":0,"description":"Pieces players placed since the log began; pieces the game places itself when it generates villages, camps and forts are not counted."},"last_built":{"type":["string","null"],"format":"date","description":"UTC date of the latest placement by a player; null when none was placed."}},"required":["prefab","token","name","comfort","group","condition","season","built","last_built"],"additionalProperties":false},"ComfortCatalogue":{"type":"object","properties":{"game_version":{"type":"string","description":"Game version the plugin read the catalogue from."},"plugin_version":{"type":"string"},"generated_at":{"type":"string","format":"date-time"},"received_at":{"type":"string","format":"date-time"},"radius_m":{"type":["number","null"],"description":"Distance within which pieces count; null when the game no longer exposes it."},"rested_base_s":{"type":"number","minimum":0,"description":"Rested duration at comfort 1."},"rested_per_level_s":{"type":"number","minimum":0,"description":"Rested duration added per comfort level above 1."},"groups":{"type":"array","items":{"type":"string"},"description":"Every comfort group in the game's own order, None included."},"seasons":{"type":"array","items":{"$ref":"#/components/schemas/ComfortSeason"}},"items":{"type":"array","items":{"$ref":"#/components/schemas/ComfortPiece"}}},"required":["game_version","plugin_version","generated_at","received_at","radius_m","rested_base_s","rested_per_level_s","groups","seasons","items"],"additionalProperties":false},"Comfort":{"type":"object","properties":{"catalogue":{"anyOf":[{"$ref":"#/components/schemas/ComfortCatalogue"},{"type":"null"}],"description":"null until the plugin has sent a catalogue."}},"required":["catalogue"],"additionalProperties":false},"ComfortCatalogueUpload":{"type":"object","description":"The comfort catalogue the plugin reads from the running game at server start.","properties":{"game_version":{"type":"string","minLength":1,"maxLength":32},"plugin_version":{"type":"string","minLength":1,"maxLength":32},"generated_at":{"type":"string","format":"date-time"},"radius_m":{"type":["number","null"],"exclusiveMinimum":0,"description":"Distance within which pieces count; null when the game no longer exposes it."},"rested_base_s":{"type":"number","minimum":0},"rested_per_level_s":{"type":"number","minimum":0},"groups":{"type":"array","maxItems":64,"uniqueItems":true,"items":{"type":"string","minLength":1,"maxLength":64},"description":"Every comfort group in the game's own order, None included."},"seasons":{"type":"array","maxItems":32,"items":{"$ref":"#/components/schemas/ComfortSeason"}},"pieces":{"type":"array","minItems":1,"maxItems":2000,"items":{"$ref":"#/components/schemas/ComfortCatalogueEntry"},"description":"One entry per prefab; an upload that names a prefab twice is refused."}},"required":["game_version","plugin_version","generated_at","radius_m","rested_base_s","rested_per_level_s","groups","seasons","pieces"],"additionalProperties":false},"ActivityLinks":{"type":"object","properties":{"raid_id":{"type":["integer","null"]},"boss_key":{"type":["string","null"]},"run_id":{"type":["string","null"],"format":"uuid"},"session_id":{"type":["integer","null"]}},"required":["raid_id","boss_key","run_id","session_id"],"additionalProperties":false},"ActivityItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"The event id."},"at":{"type":"string","format":"date-time"},"day":{"type":"integer"},"type":{"$ref":"#/components/schemas/EventType"},"player":{"anyOf":[{"$ref":"#/components/schemas/PlayerRef"},{"type":"null"}]},"summary":{"type":"object","description":"The display fields of the event: the same names as the event data plus resolved names (boss_name, raid_label, cause). Raw platform ids are replaced by player references.","additionalProperties":true},"links":{"$ref":"#/components/schemas/ActivityLinks"}},"required":["id","at","day","type","player","summary","links"],"additionalProperties":false},"ActivityPage":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ActivityItem"}},"next_cursor":{"type":["string","null"],"description":"Opaque cursor for the next page; null on the last page."}},"required":["items","next_cursor"],"additionalProperties":false},"Health":{"type":"object","properties":{"ok":{"type":"boolean"},"db":{"type":"boolean","description":"True when the database answered."},"version":{"type":"string","description":"The project version, shared by the site and the plugin."},"mock":{"type":"boolean","description":"True when API_MOCK=1 serves fixtures."}},"required":["ok","db","version","mock"],"additionalProperties":false},"LoginRequest":{"type":"object","properties":{"password":{"type":"string"}},"required":["password"],"additionalProperties":false},"AdminSession":{"type":"object","properties":{"authenticated":{"type":"boolean"},"expires_at":{"type":["string","null"],"format":"date-time"},"setup_required":{"type":"boolean","description":"True until the first admin password is set."}},"required":["authenticated","expires_at","setup_required"],"additionalProperties":false},"PluginStart":{"type":"object","properties":{"at":{"type":"string","format":"date-time"},"plugin_version":{"type":["string","null"]},"game_version":{"type":["string","null"]}},"required":["at","plugin_version","game_version"],"additionalProperties":false},"PluginInfo":{"type":"object","properties":{"version":{"type":"string","description":"The plugin version this site ships and expects."},"telemetry_secret":{"type":"string"},"secret_from_environment":{"type":"boolean","description":"True when TELEMETRY_SECRET sets the secret, which then cannot be replaced here."},"dll_available":{"type":"boolean","description":"Whether this build carries the plugin DLL for download."},"last_start":{"description":"The latest server start the plugin reported; null until the first one.","anyOf":[{"$ref":"#/components/schemas/PluginStart"},{"type":"null"}]}},"required":["version","telemetry_secret","secret_from_environment","dll_available","last_start"],"additionalProperties":false},"PluginSecret":{"type":"object","properties":{"telemetry_secret":{"type":"string"}},"required":["telemetry_secret"],"additionalProperties":false},"SetupRequest":{"type":"object","properties":{"password":{"type":"string","minLength":8,"maxLength":200}},"required":["password"],"additionalProperties":false},"SiteFeatures":{"type":"object","properties":{"chat":{"type":"boolean","description":"Chat page, chat API and chat frames in the stream."},"positions":{"type":"boolean","description":"Player positions in the API, on the map and in the stream."},"map":{"type":"boolean","description":"The World page and the world map image."},"platform_ids":{"type":"boolean","description":"Platform user ids (Steam ids) in public player responses."}},"required":["chat","positions","map","platform_ids"],"additionalProperties":false},"Site":{"type":"object","properties":{"name":{"type":"string"},"version":{"type":"string","description":"The project version, shared by the site and the plugin."},"features":{"$ref":"#/components/schemas/SiteFeatures"}},"required":["name","version","features"],"additionalProperties":false},"AdminSettings":{"type":"object","properties":{"site_name":{"type":"string","maxLength":60},"steam_query_host":{"type":"string","description":"Host of the Steam query (A2S) poller; empty switches the poller off."},"steam_query_port":{"type":"integer","minimum":1,"maximum":65535},"features":{"$ref":"#/components/schemas/SiteFeatures"},"locked":{"type":"array","description":"Settings set by an environment variable, which win over the stored value.","items":{"type":"string","enum":["site_name","steam_query_host","steam_query_port"]}}},"required":["site_name","steam_query_host","steam_query_port","features","locked"],"additionalProperties":false},"AdminSettingsUpdate":{"type":"object","properties":{"site_name":{"type":"string","minLength":1,"maxLength":60},"steam_query_host":{"type":"string"},"steam_query_port":{"type":"integer","minimum":1,"maximum":65535},"features":{"type":"object","properties":{"chat":{"type":"boolean"},"positions":{"type":"boolean"},"map":{"type":"boolean"},"platform_ids":{"type":"boolean"}},"additionalProperties":false}},"additionalProperties":false},"AdminPlayer":{"type":"object","properties":{"id":{"type":"integer"},"display_name":{"type":"string"},"platform":{"$ref":"#/components/schemas/Platform"},"platform_user_id":{"type":"string","description":"Raw platform user id as the game formats it, for example Steam_76561198012345678."},"display_id":{"type":"string","description":"Display form used by the F2 panel and the list files, for example V_76561198012345678."},"online":{"type":"boolean"},"current_biome":{"anyOf":[{"$ref":"#/components/schemas/Biome"},{"type":"null"}]},"first_seen":{"type":"string","format":"date-time"},"last_seen":{"type":"string","format":"date-time"},"playtime_s":{"type":"number","minimum":0},"sessions":{"type":"integer","minimum":0},"deaths":{"type":"integer","minimum":0},"kills":{"type":"integer","minimum":0,"description":"Creature kills, credited and by proximity together."},"boss_kills":{"type":"integer","minimum":0},"structures_built":{"type":"integer","minimum":0},"distance_m":{"type":"number","minimum":0},"characters":{"type":"array","items":{"type":"string"}},"hidden":{"type":"boolean"},"display_name_override":{"type":["string","null"]},"aliases":{"type":"array","items":{"type":"string"}}},"required":["id","display_name","platform","platform_user_id","display_id","online","current_biome","first_seen","last_seen","playtime_s","sessions","deaths","kills","boss_kills","structures_built","distance_m","characters","hidden","display_name_override","aliases"],"additionalProperties":false},"AdminPlayerPage":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AdminPlayer"}},"next_cursor":{"type":["string","null"],"description":"Opaque cursor for the next page; null on the last page."}},"required":["items","next_cursor"],"additionalProperties":false},"PlayerPatch":{"type":"object","description":"Fields to change; omitted fields keep their value.","properties":{"display_name_override":{"type":["string","null"],"minLength":1,"maxLength":64},"hidden":{"type":"boolean"}},"required":[],"additionalProperties":false},"MergeRequest":{"type":"object","properties":{"into":{"type":"integer","description":"Id of the surviving player."}},"required":["into"],"additionalProperties":false},"AnnouncementKind":{"type":"string","enum":["message","restart"],"description":"message shows the text once; restart counts down to restart_at."},"AnnouncementStatus":{"type":"string","enum":["pending","delivered","shown","cancelled","expired"],"description":"pending: not yet collected by the plugin; delivered: the plugin has it (a restart countdown is running); shown: the message was shown or the countdown reached its end; cancelled: withdrawn by an admin; expired: never collected in time (a message older than 10 minutes, a restart whose time passed)."},"Announcement":{"type":"object","properties":{"id":{"type":"integer"},"kind":{"$ref":"#/components/schemas/AnnouncementKind"},"text":{"type":["string","null"],"description":"The message, or an optional note appended to the restart banners."},"restart_at":{"type":["string","null"],"format":"date-time","description":"When the server restarts; null for a message."},"created_at":{"type":"string","format":"date-time"},"delivered_at":{"type":["string","null"],"format":"date-time","description":"When the plugin first collected the announcement."},"shown_at":{"type":["string","null"],"format":"date-time","description":"When the first banner was shown in game."},"completed_at":{"type":["string","null"],"format":"date-time","description":"When the message was shown or the final restart banner went out."},"cancelled_at":{"type":["string","null"],"format":"date-time"},"status":{"$ref":"#/components/schemas/AnnouncementStatus"}},"required":["id","kind","text","restart_at","created_at","delivered_at","shown_at","completed_at","cancelled_at","status"],"additionalProperties":false},"AnnouncementCreate":{"type":"object","properties":{"kind":{"$ref":"#/components/schemas/AnnouncementKind"},"text":{"type":["string","null"],"minLength":1,"maxLength":200,"description":"Required for a message; optional for a restart."},"restart_at":{"type":["string","null"],"format":"date-time","description":"Required for a restart, between 60 seconds and 24 hours ahead."}},"required":["kind"],"additionalProperties":false},"AnnouncementList":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Announcement"}}},"required":["items"],"additionalProperties":false},"JobAccepted":{"type":"object","properties":{"job_id":{"type":"integer"}},"required":["job_id"],"additionalProperties":false},"Backup":{"type":"object","properties":{"at":{"type":"string","format":"date-time"},"file":{"type":"string"},"size_bytes":{"type":"integer","minimum":0},"ok":{"type":"boolean"}},"required":["at","file","size_bytes","ok"],"additionalProperties":false},"BackupList":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Backup"}}},"required":["items"],"additionalProperties":false},"Job":{"type":"object","properties":{"id":{"type":"integer"},"kind":{"type":"string","enum":["projections_rebuild","backup"]},"state":{"type":"string","enum":["queued","running","done","failed"]},"started_at":{"type":["string","null"],"format":"date-time"},"finished_at":{"type":["string","null"],"format":"date-time"},"progress":{"type":["number","null"],"minimum":0,"maximum":1},"error":{"type":["string","null"]}},"required":["id","kind","state","started_at","finished_at","progress","error"],"additionalProperties":false},"AdminHealthA2s":{"type":"object","properties":{"last_ok_at":{"type":["string","null"],"format":"date-time"},"last_error":{"type":["string","null"]},"online":{"type":["boolean","null"]},"player_count":{"type":["integer","null"],"minimum":0}},"required":["last_ok_at","last_error","online","player_count"],"additionalProperties":false},"AdminHealthIngest":{"type":"object","properties":{"last_batch_at":{"type":["string","null"],"format":"date-time"},"batches_24h":{"type":"integer","minimum":0},"events_24h":{"type":"integer","minimum":0},"duplicates_24h":{"type":"integer","minimum":0},"rejected_24h":{"type":"integer","minimum":0}},"required":["last_batch_at","batches_24h","events_24h","duplicates_24h","rejected_24h"],"additionalProperties":false},"AdminHealthDb":{"type":"object","properties":{"events_total":{"type":"integer","minimum":0},"size_mb":{"type":"number","minimum":0}},"required":["events_total","size_mb"],"additionalProperties":false},"AdminHealthBackup":{"type":"object","properties":{"last_at":{"type":["string","null"],"format":"date-time"},"size_mb":{"type":["number","null"],"minimum":0},"kept":{"type":"integer","minimum":0}},"required":["last_at","size_mb","kept"],"additionalProperties":false},"AdminHealthMap":{"type":"object","properties":{"available":{"type":"boolean"},"generated_at":{"type":["string","null"],"format":"date-time"}},"required":["available","generated_at"],"additionalProperties":false},"AdminHealthJob":{"type":"object","properties":{"name":{"type":"string"},"last_run_at":{"type":["string","null"],"format":"date-time"},"last_ok":{"type":["boolean","null"]},"last_error":{"type":["string","null"]}},"required":["name","last_run_at","last_ok","last_error"],"additionalProperties":false},"AdminHealth":{"type":"object","properties":{"run":{"anyOf":[{"$ref":"#/components/schemas/Run"},{"type":"null"}]},"last_heartbeat_at":{"type":["string","null"],"format":"date-time"},"heartbeat_age_s":{"type":["number","null"],"minimum":0},"plugin_version":{"type":["string","null"]},"game_version":{"type":["string","null"]},"missing_hooks":{"type":"array","items":{"type":"string"}},"queue_depth":{"type":["integer","null"],"minimum":0},"dropped_events":{"type":["integer","null"],"minimum":0},"a2s":{"$ref":"#/components/schemas/AdminHealthA2s"},"ingest":{"$ref":"#/components/schemas/AdminHealthIngest"},"db":{"$ref":"#/components/schemas/AdminHealthDb"},"backup":{"$ref":"#/components/schemas/AdminHealthBackup"},"map":{"$ref":"#/components/schemas/AdminHealthMap"},"jobs":{"type":"array","items":{"$ref":"#/components/schemas/AdminHealthJob"}}},"required":["run","last_heartbeat_at","heartbeat_age_s","plugin_version","game_version","missing_hooks","queue_depth","dropped_events","a2s","ingest","db","backup","map","jobs"],"additionalProperties":false},"ServerStartedData":{"type":"object","properties":{"game_version":{"type":"string"},"network_version":{"type":"integer"},"plugin_version":{"type":"string"},"bepinex_version":{"type":"string"},"unity_version":{"type":"string"},"world_name":{"type":"string"},"world_uid":{"type":"integer"},"net_time":{"type":"number"},"world_day":{"type":"integer"},"global_keys":{"type":"array","items":{"type":"string"}},"missing_hooks":{"type":"array","items":{"type":"string"}},"creators":{"type":"array","maxItems":1000,"items":{"$ref":"#/components/schemas/CreatorAccount"},"description":"Every piece creator found on the standing pieces of the world at start, with the platform account the world's player history gives it. Sent from plugin 0.6.0."}},"required":["game_version","network_version","plugin_version","bepinex_version","unity_version","world_name","world_uid","net_time","world_day","global_keys","missing_hooks"],"additionalProperties":false},"CreatorAccount":{"type":"object","properties":{"creator_id":{"type":"integer","description":"The creator id the game stamps on every piece a player places; the same value structure events carry as creator_character_id."},"platform_user_id":{"type":"string","minLength":1,"maxLength":128,"description":"Raw platform user id as the game formats it, for example Steam_76561198012345678."}},"required":["creator_id","platform_user_id"],"additionalProperties":false},"ServerStoppingData":{"type":"object","properties":{"uptime_s":{"type":"number","minimum":0},"online_count":{"type":"integer","minimum":0}},"required":["uptime_s","online_count"],"additionalProperties":false},"HeartbeatPlayer":{"type":"object","properties":{"platform_user_id":{"type":"string","description":"Raw platform user id as the game formats it, for example Steam_76561198012345678."},"name":{"type":"string"},"character_id":{"type":"integer"},"biome":{"$ref":"#/components/schemas/Biome"},"x":{"type":"number","description":"World x coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"z":{"type":"number","description":"World z coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"distance_since_last_m":{"type":"number","minimum":0}},"required":["platform_user_id","name","character_id","biome","x","z","distance_since_last_m"],"additionalProperties":false},"ServerHeartbeatData":{"type":"object","properties":{"uptime_s":{"type":"number","minimum":0},"net_time":{"type":"number"},"world_day":{"type":"integer"},"last_save_age_s":{"type":["number","null"],"minimum":0},"queue_depth":{"type":"integer","minimum":0},"dropped_events":{"type":"integer","minimum":0},"players":{"type":"array","items":{"$ref":"#/components/schemas/HeartbeatPlayer"}}},"required":["uptime_s","net_time","world_day","last_save_age_s","queue_depth","dropped_events","players"],"additionalProperties":false},"ServerLostData":{"type":"object","description":"Synthetic, written by the watchdog when a run stops sending heartbeats.","properties":{"last_heartbeat_at":{"type":"string","format":"date-time"}},"required":["last_heartbeat_at"],"additionalProperties":false},"WorldSaveStartedData":{"type":"object","description":"No fields.","properties":{},"required":[],"additionalProperties":false},"WorldSavedData":{"type":"object","properties":{"duration_ms":{"type":"integer","minimum":0}},"required":["duration_ms"],"additionalProperties":false},"WorldRollbackDetectedData":{"type":"object","description":"Synthetic, written by the ingest when net_time regresses by more than 60 s.","properties":{"from_net_time":{"type":"number"},"to_net_time":{"type":"number"}},"required":["from_net_time","to_net_time"],"additionalProperties":false},"WorldDuskApproachingData":{"type":"object","description":"Synthetic, written once per world day while players are on: the world clock has reached 17:00 on the sun clock (dawn at 06:00, nightfall at 18:00), 105 real seconds before nightfall.","properties":{"net_time":{"type":"number","description":"World time in seconds at the moment of the bell."},"dusk_at":{"type":"string","format":"date-time","description":"When nightfall is due if the world keeps running."},"dusk_in_s":{"type":"integer","minimum":0,"description":"Real seconds from the bell to nightfall."}},"required":["net_time","dusk_at","dusk_in_s"],"additionalProperties":false},"WorldDawnApproachingData":{"type":"object","description":"Synthetic, written once per world day while players are on: the world clock has reached 05:00 on the sun clock (dawn at 06:00, nightfall at 18:00), 45 real seconds before dawn.","properties":{"net_time":{"type":"number","description":"World time in seconds at the moment of the crow."},"dawn_at":{"type":"string","format":"date-time","description":"When dawn is due if the world keeps running."},"dawn_in_s":{"type":"integer","minimum":0,"description":"Real seconds from the crow to dawn."}},"required":["net_time","dawn_at","dawn_in_s"],"additionalProperties":false},"PlayerJoinedData":{"type":"object","properties":{"platform_user_id":{"type":"string","description":"Raw platform user id as the game formats it, for example Steam_76561198012345678."},"display_id":{"type":"string"},"platform":{"$ref":"#/components/schemas/Platform"},"name":{"type":"string"},"peer_uid":{"type":"integer"},"playfab_id":{"type":["string","null"]}},"required":["platform_user_id","display_id","platform","name","peer_uid","playfab_id"],"additionalProperties":false},"PlayerSpawnedData":{"type":"object","properties":{"platform_user_id":{"type":"string","description":"Raw platform user id as the game formats it, for example Steam_76561198012345678."},"name":{"type":"string"},"character_id":{"type":"integer"},"respawn":{"type":"boolean"},"x":{"type":"number","description":"World x coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"z":{"type":"number","description":"World z coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"biome":{"$ref":"#/components/schemas/Biome"}},"required":["platform_user_id","name","character_id","respawn","x","z","biome"],"additionalProperties":false},"ObservedCause":{"type":"object","description":"The last damage RPC to the player relayed through the server within the 10 s before the death.","properties":{"hit_type":{"$ref":"#/components/schemas/HitType"},"attacker_prefab":{"type":["string","null"]},"attacker_platform_user_id":{"type":["string","null"],"description":"Raw platform user id as the game formats it, for example Steam_76561198012345678."},"at":{"type":"string","format":"date-time"}},"required":["hit_type","attacker_prefab","attacker_platform_user_id","at"],"additionalProperties":false},"PlayerDiedData":{"type":"object","properties":{"platform_user_id":{"type":"string","description":"Raw platform user id as the game formats it, for example Steam_76561198012345678."},"name":{"type":"string"},"character_id":{"type":"integer"},"x":{"type":"number","description":"World x coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"z":{"type":"number","description":"World z coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"biome":{"$ref":"#/components/schemas/Biome"},"observed_cause":{"anyOf":[{"$ref":"#/components/schemas/ObservedCause"},{"type":"null"}]}},"required":["platform_user_id","name","character_id","x","z","biome","observed_cause"],"additionalProperties":false},"PlayerLeftData":{"type":"object","properties":{"platform_user_id":{"type":"string","description":"Raw platform user id as the game formats it, for example Steam_76561198012345678."},"name":{"type":"string"},"session_s":{"type":"number","minimum":0},"reason":{"type":"string","enum":["disconnect","timeout","kicked","server_stop"]}},"required":["platform_user_id","name","session_s","reason"],"additionalProperties":false},"PlayerBiomeChangedData":{"type":"object","properties":{"platform_user_id":{"type":"string","description":"Raw platform user id as the game formats it, for example Steam_76561198012345678."},"from":{"$ref":"#/components/schemas/Biome"},"to":{"$ref":"#/components/schemas/Biome"},"x":{"type":"number","description":"World x coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"z":{"type":"number","description":"World z coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."}},"required":["platform_user_id","from","to","x","z"],"additionalProperties":false},"PlayerPositionData":{"type":"object","properties":{"platform_user_id":{"type":"string","description":"Raw platform user id as the game formats it, for example Steam_76561198012345678."},"x":{"type":"number","description":"World x coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"z":{"type":"number","description":"World z coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"biome":{"$ref":"#/components/schemas/Biome"}},"required":["platform_user_id","x","z","biome"],"additionalProperties":false},"BossSummonedData":{"type":"object","properties":{"prefab":{"type":"string"},"name_key":{"type":"string"},"x":{"type":"number","description":"World x coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"z":{"type":"number","description":"World z coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"biome":{"$ref":"#/components/schemas/Biome"},"summoner_platform_user_id":{"type":["string","null"],"description":"Raw platform user id as the game formats it, for example Steam_76561198012345678."},"method":{"type":"string","enum":["spawn_rpc","zdo"]}},"required":["prefab","name_key","x","z","biome","summoner_platform_user_id","method"],"additionalProperties":false},"BossEngagedData":{"type":"object","properties":{"prefab":{"type":"string"},"name_key":{"type":"string"},"x":{"type":"number","description":"World x coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"z":{"type":"number","description":"World z coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"biome":{"$ref":"#/components/schemas/Biome"},"alert_message":{"type":"string"},"nearby":{"type":"array","items":{"type":"string","description":"Raw platform user id as the game formats it, for example Steam_76561198012345678."}}},"required":["prefab","name_key","x","z","biome","alert_message","nearby"],"additionalProperties":false},"BossDefeatedData":{"type":"object","properties":{"key":{"type":"string"},"first_time":{"type":"boolean"},"sender_platform_user_id":{"type":["string","null"],"description":"The owner peer of the boss, not necessarily the killer."},"nearby":{"type":"array","items":{"type":"string","description":"Raw platform user id as the game formats it, for example Steam_76561198012345678."},"description":"Platform user ids within 200 m of the sender."},"prefab":{"type":["string","null"]},"name_key":{"type":["string","null"]},"participants":{"type":"array","items":{"type":"string","description":"Raw platform user id as the game formats it, for example Steam_76561198012345678."},"description":"Platform ids of players whose attackers flag is set on the boss ZDO; empty when the ZDO was not located."}},"required":["key","first_time","sender_platform_user_id","nearby","prefab","name_key","participants"],"additionalProperties":false},"GlobalKeySetData":{"type":"object","properties":{"key":{"type":"string"},"value":{"type":["string","null"]},"first_time":{"type":"boolean"},"prefab":{"type":["string","null"],"description":"The creature whose death sets this key, when the key belongs to one."},"name_key":{"type":["string","null"]},"sender_platform_user_id":{"type":["string","null"],"description":"The owner peer of the creature, not necessarily the killer."},"nearby":{"type":"array","items":{"type":"string","description":"Raw platform user id as the game formats it, for example Steam_76561198012345678."},"description":"Platform user ids within 100 m of the sender."}},"required":["key","value","first_time"],"additionalProperties":false},"RaidStartedData":{"type":"object","properties":{"name":{"type":"string"},"x":{"type":"number","description":"World x coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"z":{"type":"number","description":"World z coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"biome":{"$ref":"#/components/schemas/Biome"},"duration_s":{"type":"number","minimum":0},"nearby":{"type":"array","items":{"type":"string","description":"Raw platform user id as the game formats it, for example Steam_76561198012345678."}}},"required":["name","x","z","biome","duration_s","nearby"],"additionalProperties":false},"RaidEndedData":{"type":"object","properties":{"name":{"type":"string"},"elapsed_s":{"type":"number","minimum":0},"active_s":{"type":["number","null"],"minimum":0,"description":"The game's own raid timer at the end, in seconds; it pauses while nobody is inside the raid area. Absent from plugins before 0.2.0."}},"required":["name","elapsed_s"],"additionalProperties":false},"StructureBuiltData":{"type":"object","properties":{"prefab":{"type":"string"},"x":{"type":"number","description":"World x coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"z":{"type":"number","description":"World z coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"biome":{"$ref":"#/components/schemas/Biome"},"creator_character_id":{"type":"integer"},"creator_platform_user_id":{"type":["string","null"],"description":"Raw platform user id of the builder as the game formats it, for example Steam_76561198012345678; read from the piece's own creator record from plugin 0.6.0, null for pieces the world generates."}},"required":["prefab","x","z","biome","creator_character_id","creator_platform_user_id"],"additionalProperties":false},"StructureDestroyedData":{"type":"object","properties":{"prefab":{"type":"string"},"x":{"type":"number","description":"World x coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"z":{"type":"number","description":"World z coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"biome":{"$ref":"#/components/schemas/Biome"},"creator_character_id":{"type":["integer","null"]},"creator_platform_user_id":{"type":["string","null"],"description":"Raw platform user id of the piece's builder, read from the piece's own creator record. Sent from plugin 0.6.0; null for pieces the world generated."}},"required":["prefab","x","z","biome","creator_character_id"],"additionalProperties":false},"CreatureDiedData":{"type":"object","properties":{"prefab":{"type":"string"},"level":{"type":"integer","minimum":1},"x":{"type":"number","description":"World x coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"z":{"type":"number","description":"World z coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"biome":{"$ref":"#/components/schemas/Biome"},"credited":{"type":"array","items":{"type":"string","description":"Raw platform user id as the game formats it, for example Steam_76561198012345678."}},"nearby":{"type":"array","items":{"type":"string","description":"Raw platform user id as the game formats it, for example Steam_76561198012345678."}}},"required":["prefab","level","x","z","biome","credited","nearby"],"additionalProperties":false},"ChatMessageData":{"type":"object","properties":{"platform_user_id":{"type":"string","description":"Raw platform user id as the game formats it, for example Steam_76561198012345678."},"kind":{"type":"string","enum":["shout","ping","say"]},"text":{"type":["string","null"]},"x":{"type":"number","description":"World x coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"z":{"type":"number","description":"World z coordinate in metres; the world is a disc of radius 10000 m centred on 0,0."},"biome":{"$ref":"#/components/schemas/Biome"}},"required":["platform_user_id","kind","text","x","z","biome"],"additionalProperties":false},"AnnouncementShownData":{"type":"object","description":"Written by the plugin for every banner it shows through the ShowMessage routed RPC.","properties":{"announcement_id":{"type":"integer","description":"The admin announcement the banner belongs to."},"kind":{"$ref":"#/components/schemas/AnnouncementKind"},"text":{"type":"string","description":"The banner text exactly as shown."},"remaining_s":{"type":["integer","null"],"minimum":0,"description":"Seconds left until the restart when the banner went out; null for a message."},"final":{"type":"boolean","description":"True for a message and for the restart banner shown at the restart time."}},"required":["announcement_id","kind","text","remaining_s","final"],"additionalProperties":false},"ServerStartedEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID v4 generated by the plugin."},"seq":{"type":"integer","minimum":0,"description":"Monotonic per run."},"run_id":{"type":"string","format":"uuid","description":"Identifies one server process start."},"ts":{"type":"string","format":"date-time","description":"UTC time from the game host clock."},"type":{"type":"string","const":"server.started"},"world_day":{"type":"integer"},"data":{"$ref":"#/components/schemas/ServerStartedData"},"received_at":{"type":"string","format":"date-time","description":"When the ingest endpoint accepted the event; present on stored events, absent in batches."}},"required":["id","seq","run_id","ts","type","world_day","data"],"additionalProperties":false},"ServerStoppingEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID v4 generated by the plugin."},"seq":{"type":"integer","minimum":0,"description":"Monotonic per run."},"run_id":{"type":"string","format":"uuid","description":"Identifies one server process start."},"ts":{"type":"string","format":"date-time","description":"UTC time from the game host clock."},"type":{"type":"string","const":"server.stopping"},"world_day":{"type":"integer"},"data":{"$ref":"#/components/schemas/ServerStoppingData"},"received_at":{"type":"string","format":"date-time","description":"When the ingest endpoint accepted the event; present on stored events, absent in batches."}},"required":["id","seq","run_id","ts","type","world_day","data"],"additionalProperties":false},"ServerHeartbeatEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID v4 generated by the plugin."},"seq":{"type":"integer","minimum":0,"description":"Monotonic per run."},"run_id":{"type":"string","format":"uuid","description":"Identifies one server process start."},"ts":{"type":"string","format":"date-time","description":"UTC time from the game host clock."},"type":{"type":"string","const":"server.heartbeat"},"world_day":{"type":"integer"},"data":{"$ref":"#/components/schemas/ServerHeartbeatData"},"received_at":{"type":"string","format":"date-time","description":"When the ingest endpoint accepted the event; present on stored events, absent in batches."}},"required":["id","seq","run_id","ts","type","world_day","data"],"additionalProperties":false},"ServerLostEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID v4 generated by the plugin."},"seq":{"type":"integer","minimum":0,"description":"Monotonic per run."},"run_id":{"type":"string","format":"uuid","description":"Identifies one server process start."},"ts":{"type":"string","format":"date-time","description":"UTC time from the game host clock."},"type":{"type":"string","const":"server.lost"},"world_day":{"type":"integer"},"data":{"$ref":"#/components/schemas/ServerLostData"},"received_at":{"type":"string","format":"date-time","description":"When the ingest endpoint accepted the event; present on stored events, absent in batches."}},"required":["id","seq","run_id","ts","type","world_day","data"],"additionalProperties":false},"WorldSaveStartedEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID v4 generated by the plugin."},"seq":{"type":"integer","minimum":0,"description":"Monotonic per run."},"run_id":{"type":"string","format":"uuid","description":"Identifies one server process start."},"ts":{"type":"string","format":"date-time","description":"UTC time from the game host clock."},"type":{"type":"string","const":"world.save_started"},"world_day":{"type":"integer"},"data":{"$ref":"#/components/schemas/WorldSaveStartedData"},"received_at":{"type":"string","format":"date-time","description":"When the ingest endpoint accepted the event; present on stored events, absent in batches."}},"required":["id","seq","run_id","ts","type","world_day","data"],"additionalProperties":false},"WorldSavedEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID v4 generated by the plugin."},"seq":{"type":"integer","minimum":0,"description":"Monotonic per run."},"run_id":{"type":"string","format":"uuid","description":"Identifies one server process start."},"ts":{"type":"string","format":"date-time","description":"UTC time from the game host clock."},"type":{"type":"string","const":"world.saved"},"world_day":{"type":"integer"},"data":{"$ref":"#/components/schemas/WorldSavedData"},"received_at":{"type":"string","format":"date-time","description":"When the ingest endpoint accepted the event; present on stored events, absent in batches."}},"required":["id","seq","run_id","ts","type","world_day","data"],"additionalProperties":false},"WorldRollbackDetectedEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID v4 generated by the plugin."},"seq":{"type":"integer","minimum":0,"description":"Monotonic per run."},"run_id":{"type":"string","format":"uuid","description":"Identifies one server process start."},"ts":{"type":"string","format":"date-time","description":"UTC time from the game host clock."},"type":{"type":"string","const":"world.rollback_detected"},"world_day":{"type":"integer"},"data":{"$ref":"#/components/schemas/WorldRollbackDetectedData"},"received_at":{"type":"string","format":"date-time","description":"When the ingest endpoint accepted the event; present on stored events, absent in batches."}},"required":["id","seq","run_id","ts","type","world_day","data"],"additionalProperties":false},"WorldDuskApproachingEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID v4 generated by the plugin."},"seq":{"type":"integer","minimum":0,"description":"Monotonic per run."},"run_id":{"type":"string","format":"uuid","description":"Identifies one server process start."},"ts":{"type":"string","format":"date-time","description":"UTC time from the game host clock."},"type":{"type":"string","const":"world.dusk_approaching"},"world_day":{"type":"integer"},"data":{"$ref":"#/components/schemas/WorldDuskApproachingData"},"received_at":{"type":"string","format":"date-time","description":"When the ingest endpoint accepted the event; present on stored events, absent in batches."}},"required":["id","seq","run_id","ts","type","world_day","data"],"additionalProperties":false},"WorldDawnApproachingEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID v4 generated by the plugin."},"seq":{"type":"integer","minimum":0,"description":"Monotonic per run."},"run_id":{"type":"string","format":"uuid","description":"Identifies one server process start."},"ts":{"type":"string","format":"date-time","description":"UTC time from the game host clock."},"type":{"type":"string","const":"world.dawn_approaching"},"world_day":{"type":"integer"},"data":{"$ref":"#/components/schemas/WorldDawnApproachingData"},"received_at":{"type":"string","format":"date-time","description":"When the ingest endpoint accepted the event; present on stored events, absent in batches."}},"required":["id","seq","run_id","ts","type","world_day","data"],"additionalProperties":false},"PlayerJoinedEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID v4 generated by the plugin."},"seq":{"type":"integer","minimum":0,"description":"Monotonic per run."},"run_id":{"type":"string","format":"uuid","description":"Identifies one server process start."},"ts":{"type":"string","format":"date-time","description":"UTC time from the game host clock."},"type":{"type":"string","const":"player.joined"},"world_day":{"type":"integer"},"data":{"$ref":"#/components/schemas/PlayerJoinedData"},"received_at":{"type":"string","format":"date-time","description":"When the ingest endpoint accepted the event; present on stored events, absent in batches."}},"required":["id","seq","run_id","ts","type","world_day","data"],"additionalProperties":false},"PlayerSpawnedEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID v4 generated by the plugin."},"seq":{"type":"integer","minimum":0,"description":"Monotonic per run."},"run_id":{"type":"string","format":"uuid","description":"Identifies one server process start."},"ts":{"type":"string","format":"date-time","description":"UTC time from the game host clock."},"type":{"type":"string","const":"player.spawned"},"world_day":{"type":"integer"},"data":{"$ref":"#/components/schemas/PlayerSpawnedData"},"received_at":{"type":"string","format":"date-time","description":"When the ingest endpoint accepted the event; present on stored events, absent in batches."}},"required":["id","seq","run_id","ts","type","world_day","data"],"additionalProperties":false},"PlayerDiedEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID v4 generated by the plugin."},"seq":{"type":"integer","minimum":0,"description":"Monotonic per run."},"run_id":{"type":"string","format":"uuid","description":"Identifies one server process start."},"ts":{"type":"string","format":"date-time","description":"UTC time from the game host clock."},"type":{"type":"string","const":"player.died"},"world_day":{"type":"integer"},"data":{"$ref":"#/components/schemas/PlayerDiedData"},"received_at":{"type":"string","format":"date-time","description":"When the ingest endpoint accepted the event; present on stored events, absent in batches."}},"required":["id","seq","run_id","ts","type","world_day","data"],"additionalProperties":false},"PlayerLeftEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID v4 generated by the plugin."},"seq":{"type":"integer","minimum":0,"description":"Monotonic per run."},"run_id":{"type":"string","format":"uuid","description":"Identifies one server process start."},"ts":{"type":"string","format":"date-time","description":"UTC time from the game host clock."},"type":{"type":"string","const":"player.left"},"world_day":{"type":"integer"},"data":{"$ref":"#/components/schemas/PlayerLeftData"},"received_at":{"type":"string","format":"date-time","description":"When the ingest endpoint accepted the event; present on stored events, absent in batches."}},"required":["id","seq","run_id","ts","type","world_day","data"],"additionalProperties":false},"PlayerBiomeChangedEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID v4 generated by the plugin."},"seq":{"type":"integer","minimum":0,"description":"Monotonic per run."},"run_id":{"type":"string","format":"uuid","description":"Identifies one server process start."},"ts":{"type":"string","format":"date-time","description":"UTC time from the game host clock."},"type":{"type":"string","const":"player.biome_changed"},"world_day":{"type":"integer"},"data":{"$ref":"#/components/schemas/PlayerBiomeChangedData"},"received_at":{"type":"string","format":"date-time","description":"When the ingest endpoint accepted the event; present on stored events, absent in batches."}},"required":["id","seq","run_id","ts","type","world_day","data"],"additionalProperties":false},"PlayerPositionEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID v4 generated by the plugin."},"seq":{"type":"integer","minimum":0,"description":"Monotonic per run."},"run_id":{"type":"string","format":"uuid","description":"Identifies one server process start."},"ts":{"type":"string","format":"date-time","description":"UTC time from the game host clock."},"type":{"type":"string","const":"player.position"},"world_day":{"type":"integer"},"data":{"$ref":"#/components/schemas/PlayerPositionData"},"received_at":{"type":"string","format":"date-time","description":"When the ingest endpoint accepted the event; present on stored events, absent in batches."}},"required":["id","seq","run_id","ts","type","world_day","data"],"additionalProperties":false},"BossSummonedEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID v4 generated by the plugin."},"seq":{"type":"integer","minimum":0,"description":"Monotonic per run."},"run_id":{"type":"string","format":"uuid","description":"Identifies one server process start."},"ts":{"type":"string","format":"date-time","description":"UTC time from the game host clock."},"type":{"type":"string","const":"boss.summoned"},"world_day":{"type":"integer"},"data":{"$ref":"#/components/schemas/BossSummonedData"},"received_at":{"type":"string","format":"date-time","description":"When the ingest endpoint accepted the event; present on stored events, absent in batches."}},"required":["id","seq","run_id","ts","type","world_day","data"],"additionalProperties":false},"BossEngagedEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID v4 generated by the plugin."},"seq":{"type":"integer","minimum":0,"description":"Monotonic per run."},"run_id":{"type":"string","format":"uuid","description":"Identifies one server process start."},"ts":{"type":"string","format":"date-time","description":"UTC time from the game host clock."},"type":{"type":"string","const":"boss.engaged"},"world_day":{"type":"integer"},"data":{"$ref":"#/components/schemas/BossEngagedData"},"received_at":{"type":"string","format":"date-time","description":"When the ingest endpoint accepted the event; present on stored events, absent in batches."}},"required":["id","seq","run_id","ts","type","world_day","data"],"additionalProperties":false},"BossDefeatedEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID v4 generated by the plugin."},"seq":{"type":"integer","minimum":0,"description":"Monotonic per run."},"run_id":{"type":"string","format":"uuid","description":"Identifies one server process start."},"ts":{"type":"string","format":"date-time","description":"UTC time from the game host clock."},"type":{"type":"string","const":"boss.defeated"},"world_day":{"type":"integer"},"data":{"$ref":"#/components/schemas/BossDefeatedData"},"received_at":{"type":"string","format":"date-time","description":"When the ingest endpoint accepted the event; present on stored events, absent in batches."}},"required":["id","seq","run_id","ts","type","world_day","data"],"additionalProperties":false},"GlobalKeySetEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID v4 generated by the plugin."},"seq":{"type":"integer","minimum":0,"description":"Monotonic per run."},"run_id":{"type":"string","format":"uuid","description":"Identifies one server process start."},"ts":{"type":"string","format":"date-time","description":"UTC time from the game host clock."},"type":{"type":"string","const":"global_key.set"},"world_day":{"type":"integer"},"data":{"$ref":"#/components/schemas/GlobalKeySetData"},"received_at":{"type":"string","format":"date-time","description":"When the ingest endpoint accepted the event; present on stored events, absent in batches."}},"required":["id","seq","run_id","ts","type","world_day","data"],"additionalProperties":false},"RaidStartedEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID v4 generated by the plugin."},"seq":{"type":"integer","minimum":0,"description":"Monotonic per run."},"run_id":{"type":"string","format":"uuid","description":"Identifies one server process start."},"ts":{"type":"string","format":"date-time","description":"UTC time from the game host clock."},"type":{"type":"string","const":"raid.started"},"world_day":{"type":"integer"},"data":{"$ref":"#/components/schemas/RaidStartedData"},"received_at":{"type":"string","format":"date-time","description":"When the ingest endpoint accepted the event; present on stored events, absent in batches."}},"required":["id","seq","run_id","ts","type","world_day","data"],"additionalProperties":false},"RaidEndedEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID v4 generated by the plugin."},"seq":{"type":"integer","minimum":0,"description":"Monotonic per run."},"run_id":{"type":"string","format":"uuid","description":"Identifies one server process start."},"ts":{"type":"string","format":"date-time","description":"UTC time from the game host clock."},"type":{"type":"string","const":"raid.ended"},"world_day":{"type":"integer"},"data":{"$ref":"#/components/schemas/RaidEndedData"},"received_at":{"type":"string","format":"date-time","description":"When the ingest endpoint accepted the event; present on stored events, absent in batches."}},"required":["id","seq","run_id","ts","type","world_day","data"],"additionalProperties":false},"StructureBuiltEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID v4 generated by the plugin."},"seq":{"type":"integer","minimum":0,"description":"Monotonic per run."},"run_id":{"type":"string","format":"uuid","description":"Identifies one server process start."},"ts":{"type":"string","format":"date-time","description":"UTC time from the game host clock."},"type":{"type":"string","const":"structure.built"},"world_day":{"type":"integer"},"data":{"$ref":"#/components/schemas/StructureBuiltData"},"received_at":{"type":"string","format":"date-time","description":"When the ingest endpoint accepted the event; present on stored events, absent in batches."}},"required":["id","seq","run_id","ts","type","world_day","data"],"additionalProperties":false},"StructureDestroyedEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID v4 generated by the plugin."},"seq":{"type":"integer","minimum":0,"description":"Monotonic per run."},"run_id":{"type":"string","format":"uuid","description":"Identifies one server process start."},"ts":{"type":"string","format":"date-time","description":"UTC time from the game host clock."},"type":{"type":"string","const":"structure.destroyed"},"world_day":{"type":"integer"},"data":{"$ref":"#/components/schemas/StructureDestroyedData"},"received_at":{"type":"string","format":"date-time","description":"When the ingest endpoint accepted the event; present on stored events, absent in batches."}},"required":["id","seq","run_id","ts","type","world_day","data"],"additionalProperties":false},"CreatureDiedEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID v4 generated by the plugin."},"seq":{"type":"integer","minimum":0,"description":"Monotonic per run."},"run_id":{"type":"string","format":"uuid","description":"Identifies one server process start."},"ts":{"type":"string","format":"date-time","description":"UTC time from the game host clock."},"type":{"type":"string","const":"creature.died"},"world_day":{"type":"integer"},"data":{"$ref":"#/components/schemas/CreatureDiedData"},"received_at":{"type":"string","format":"date-time","description":"When the ingest endpoint accepted the event; present on stored events, absent in batches."}},"required":["id","seq","run_id","ts","type","world_day","data"],"additionalProperties":false},"ChatMessageEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID v4 generated by the plugin."},"seq":{"type":"integer","minimum":0,"description":"Monotonic per run."},"run_id":{"type":"string","format":"uuid","description":"Identifies one server process start."},"ts":{"type":"string","format":"date-time","description":"UTC time from the game host clock."},"type":{"type":"string","const":"chat.message"},"world_day":{"type":"integer"},"data":{"$ref":"#/components/schemas/ChatMessageData"},"received_at":{"type":"string","format":"date-time","description":"When the ingest endpoint accepted the event; present on stored events, absent in batches."}},"required":["id","seq","run_id","ts","type","world_day","data"],"additionalProperties":false},"AnnouncementShownEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID v4 generated by the plugin."},"seq":{"type":"integer","minimum":0,"description":"Monotonic per run."},"run_id":{"type":"string","format":"uuid","description":"Identifies one server process start."},"ts":{"type":"string","format":"date-time","description":"UTC time from the game host clock."},"type":{"type":"string","const":"announcement.shown"},"world_day":{"type":"integer"},"data":{"$ref":"#/components/schemas/AnnouncementShownData"},"received_at":{"type":"string","format":"date-time","description":"When the ingest endpoint accepted the event; present on stored events, absent in batches."}},"required":["id","seq","run_id","ts","type","world_day","data"],"additionalProperties":false},"TelemetryEvent":{"description":"One event as sent by the plugin: the envelope with the data shape of its type.","oneOf":[{"$ref":"#/components/schemas/ServerStartedEvent"},{"$ref":"#/components/schemas/ServerStoppingEvent"},{"$ref":"#/components/schemas/ServerHeartbeatEvent"},{"$ref":"#/components/schemas/WorldSaveStartedEvent"},{"$ref":"#/components/schemas/WorldSavedEvent"},{"$ref":"#/components/schemas/PlayerJoinedEvent"},{"$ref":"#/components/schemas/PlayerSpawnedEvent"},{"$ref":"#/components/schemas/PlayerDiedEvent"},{"$ref":"#/components/schemas/PlayerLeftEvent"},{"$ref":"#/components/schemas/PlayerBiomeChangedEvent"},{"$ref":"#/components/schemas/PlayerPositionEvent"},{"$ref":"#/components/schemas/BossSummonedEvent"},{"$ref":"#/components/schemas/BossEngagedEvent"},{"$ref":"#/components/schemas/BossDefeatedEvent"},{"$ref":"#/components/schemas/GlobalKeySetEvent"},{"$ref":"#/components/schemas/RaidStartedEvent"},{"$ref":"#/components/schemas/RaidEndedEvent"},{"$ref":"#/components/schemas/StructureBuiltEvent"},{"$ref":"#/components/schemas/StructureDestroyedEvent"},{"$ref":"#/components/schemas/CreatureDiedEvent"},{"$ref":"#/components/schemas/ChatMessageEvent"},{"$ref":"#/components/schemas/AnnouncementShownEvent"}],"discriminator":{"propertyName":"type","mapping":{"server.started":"#/components/schemas/ServerStartedEvent","server.stopping":"#/components/schemas/ServerStoppingEvent","server.heartbeat":"#/components/schemas/ServerHeartbeatEvent","world.save_started":"#/components/schemas/WorldSaveStartedEvent","world.saved":"#/components/schemas/WorldSavedEvent","player.joined":"#/components/schemas/PlayerJoinedEvent","player.spawned":"#/components/schemas/PlayerSpawnedEvent","player.died":"#/components/schemas/PlayerDiedEvent","player.left":"#/components/schemas/PlayerLeftEvent","player.biome_changed":"#/components/schemas/PlayerBiomeChangedEvent","player.position":"#/components/schemas/PlayerPositionEvent","boss.summoned":"#/components/schemas/BossSummonedEvent","boss.engaged":"#/components/schemas/BossEngagedEvent","boss.defeated":"#/components/schemas/BossDefeatedEvent","global_key.set":"#/components/schemas/GlobalKeySetEvent","raid.started":"#/components/schemas/RaidStartedEvent","raid.ended":"#/components/schemas/RaidEndedEvent","structure.built":"#/components/schemas/StructureBuiltEvent","structure.destroyed":"#/components/schemas/StructureDestroyedEvent","creature.died":"#/components/schemas/CreatureDiedEvent","chat.message":"#/components/schemas/ChatMessageEvent","announcement.shown":"#/components/schemas/AnnouncementShownEvent"}}},"EventEnvelope":{"description":"Raw event envelope as stored: every plugin event type plus the four synthetic ones.","oneOf":[{"$ref":"#/components/schemas/ServerStartedEvent"},{"$ref":"#/components/schemas/ServerStoppingEvent"},{"$ref":"#/components/schemas/ServerHeartbeatEvent"},{"$ref":"#/components/schemas/ServerLostEvent"},{"$ref":"#/components/schemas/WorldSaveStartedEvent"},{"$ref":"#/components/schemas/WorldSavedEvent"},{"$ref":"#/components/schemas/WorldRollbackDetectedEvent"},{"$ref":"#/components/schemas/WorldDuskApproachingEvent"},{"$ref":"#/components/schemas/WorldDawnApproachingEvent"},{"$ref":"#/components/schemas/PlayerJoinedEvent"},{"$ref":"#/components/schemas/PlayerSpawnedEvent"},{"$ref":"#/components/schemas/PlayerDiedEvent"},{"$ref":"#/components/schemas/PlayerLeftEvent"},{"$ref":"#/components/schemas/PlayerBiomeChangedEvent"},{"$ref":"#/components/schemas/PlayerPositionEvent"},{"$ref":"#/components/schemas/BossSummonedEvent"},{"$ref":"#/components/schemas/BossEngagedEvent"},{"$ref":"#/components/schemas/BossDefeatedEvent"},{"$ref":"#/components/schemas/GlobalKeySetEvent"},{"$ref":"#/components/schemas/RaidStartedEvent"},{"$ref":"#/components/schemas/RaidEndedEvent"},{"$ref":"#/components/schemas/StructureBuiltEvent"},{"$ref":"#/components/schemas/StructureDestroyedEvent"},{"$ref":"#/components/schemas/CreatureDiedEvent"},{"$ref":"#/components/schemas/ChatMessageEvent"},{"$ref":"#/components/schemas/AnnouncementShownEvent"}],"discriminator":{"propertyName":"type","mapping":{"server.started":"#/components/schemas/ServerStartedEvent","server.stopping":"#/components/schemas/ServerStoppingEvent","server.heartbeat":"#/components/schemas/ServerHeartbeatEvent","server.lost":"#/components/schemas/ServerLostEvent","world.save_started":"#/components/schemas/WorldSaveStartedEvent","world.saved":"#/components/schemas/WorldSavedEvent","world.rollback_detected":"#/components/schemas/WorldRollbackDetectedEvent","world.dusk_approaching":"#/components/schemas/WorldDuskApproachingEvent","world.dawn_approaching":"#/components/schemas/WorldDawnApproachingEvent","player.joined":"#/components/schemas/PlayerJoinedEvent","player.spawned":"#/components/schemas/PlayerSpawnedEvent","player.died":"#/components/schemas/PlayerDiedEvent","player.left":"#/components/schemas/PlayerLeftEvent","player.biome_changed":"#/components/schemas/PlayerBiomeChangedEvent","player.position":"#/components/schemas/PlayerPositionEvent","boss.summoned":"#/components/schemas/BossSummonedEvent","boss.engaged":"#/components/schemas/BossEngagedEvent","boss.defeated":"#/components/schemas/BossDefeatedEvent","global_key.set":"#/components/schemas/GlobalKeySetEvent","raid.started":"#/components/schemas/RaidStartedEvent","raid.ended":"#/components/schemas/RaidEndedEvent","structure.built":"#/components/schemas/StructureBuiltEvent","structure.destroyed":"#/components/schemas/StructureDestroyedEvent","creature.died":"#/components/schemas/CreatureDiedEvent","chat.message":"#/components/schemas/ChatMessageEvent","announcement.shown":"#/components/schemas/AnnouncementShownEvent"}}},"StoredEvent":{"description":"One raw event with received_at.","allOf":[{"$ref":"#/components/schemas/EventEnvelope"},{"type":"object","properties":{"received_at":{"type":"string","format":"date-time"}},"required":["received_at"]}]},"EventPage":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/EventEnvelope"}},"next_cursor":{"type":["string","null"],"description":"Opaque cursor for the next page; null on the last page."}},"required":["items","next_cursor"],"additionalProperties":false},"IngestBatch":{"type":"object","description":"Signed batch posted by the plugin. The HMAC-SHA256 signature is computed over timestamp + \".\" + body.","properties":{"plugin":{"type":"object","properties":{"name":{"type":"string"},"version":{"type":"string"}},"required":["name","version"],"additionalProperties":false},"game":{"type":"object","properties":{"version":{"type":"string"},"network_version":{"type":"integer"}},"required":["version","network_version"],"additionalProperties":false},"server":{"type":"object","properties":{"name":{"type":"string"},"world":{"type":"string"},"world_uid":{"type":"integer"}},"required":["name","world","world_uid"],"additionalProperties":false},"events":{"type":"array","items":{"$ref":"#/components/schemas/TelemetryEvent"},"maxItems":200,"description":"Sorted by seq before processing. At most 200 events and 512 KB per request."}},"required":["plugin","game","server","events"],"additionalProperties":false},"PluginAnnouncement":{"type":"object","description":"An active announcement handed to the plugin. The plugin shows a message once per id and keeps a restart countdown only while its id keeps appearing, so a cancellation takes effect at the next response.","properties":{"id":{"type":"integer"},"kind":{"$ref":"#/components/schemas/AnnouncementKind"},"text":{"type":["string","null"]},"restart_at":{"type":["string","null"],"format":"date-time"},"restart_in_s":{"type":["number","null"],"description":"Seconds from this response until restart_at, computed by the site so the plugin needs no wall clock; null for a message."}},"required":["id","kind","text","restart_at","restart_in_s"],"additionalProperties":false},"IngestResult":{"type":"object","properties":{"accepted":{"type":"integer","minimum":0},"duplicates":{"type":"integer","minimum":0},"last_seq":{"type":["integer","null"],"minimum":0,"description":"Highest seq in the batch, null for an empty batch."},"announcements":{"type":"array","items":{"$ref":"#/components/schemas/PluginAnnouncement"},"description":"Every active announcement at the time of the response, oldest first."}},"required":["accepted","duplicates","last_seq","announcements"],"additionalProperties":false},"StreamFrame":{"type":"object","description":"One server-sent event as the stream serializes it: an event line with the event name, an id line for activity frames and a data line holding the JSON document.","properties":{"event":{"type":"string","enum":["status","online","activity"]},"id":{"type":["string","null"],"description":"The event id for activity frames, null otherwise."},"data":{"description":"Status for status frames, OnlineList for online frames, ActivityItem for activity frames.","oneOf":[{"$ref":"#/components/schemas/Status"},{"$ref":"#/components/schemas/OnlineList"},{"$ref":"#/components/schemas/ActivityItem"}]}},"required":["event","id","data"],"additionalProperties":false},"ZoneRating":{"type":"string","enum":["excellent","strong","acceptable","weak","poor"],"description":"Band of the overall score, 90, 75, 60 and 40 being the lower bounds of the first four."},"ZoneRecommendation":{"type":"string","enum":["primary","backup","avoid"],"description":"Whether the guild should hand this player a zone."},"ZoneTestStatus":{"type":"string","enum":["ok","failed","partial","skipped"]},"ZoneValueSource":{"type":"string","enum":["measured","reported","unavailable"],"description":"Whether a system value was measured, reported by the browser or unavailable."},"ZonePenaltyId":{"type":"string","enum":["net-fail-severe","net-fail-high","net-fail-moderate","jitter-extreme","jitter-high","latency-extreme","latency-high","cpu-failed","network-failed","unstable-bench"]},"ZoneTarget":{"type":"object","description":"The probe the network figures were measured against.","properties":{"label":{"type":"string","minLength":1,"maxLength":80},"endpoint":{"type":"string","minLength":1,"maxLength":500}},"required":["label","endpoint"],"additionalProperties":false},"ZoneSystem":{"type":"object","description":"What the browser reports about the machine.","properties":{"logicalProcessors":{"type":["integer","null"],"minimum":1},"logicalProcessorsSource":{"$ref":"#/components/schemas/ZoneValueSource"},"deviceMemoryGB":{"type":["number","null"]},"deviceMemorySource":{"$ref":"#/components/schemas/ZoneValueSource"},"gpuRenderer":{"type":["string","null"],"maxLength":200},"gpuVendor":{"type":["string","null"],"maxLength":200},"gpuSource":{"$ref":"#/components/schemas/ZoneValueSource"},"browser":{"type":["string","null"],"maxLength":80},"browserSource":{"$ref":"#/components/schemas/ZoneValueSource"},"platform":{"type":["string","null"],"maxLength":80},"platformSource":{"$ref":"#/components/schemas/ZoneValueSource"},"hardwareConcurrency":{"type":["integer","null"],"minimum":1},"userAgentDataBrands":{"type":["array","null"],"items":{"type":"string"}}},"required":["logicalProcessors","logicalProcessorsSource","deviceMemoryGB","deviceMemorySource","gpuRenderer","gpuVendor","gpuSource","browser","browserSource","platform","platformSource","hardwareConcurrency","userAgentDataBrands"],"additionalProperties":false},"ZoneCpu":{"type":"object","description":"Throughput of the fixed integer kernel in iterations per millisecond.","properties":{"singleThread":{"type":["number","null"]},"multiThread":{"type":["number","null"]},"variance":{"type":["number","null"],"description":"Coefficient of variation of the single-thread samples."},"samples":{"type":"array","items":{"type":"number"},"maxItems":32},"workersUsed":{"type":["integer","null"],"minimum":0},"kernel":{"type":"string","const":"vzd-cpu-1.0.0"}},"required":["singleThread","multiThread","variance","samples","workersUsed","kernel"],"additionalProperties":false},"ZoneNetwork":{"type":"object","description":"Round trips and transfers against the probe.","properties":{"latencyMedianMs":{"type":["number","null"]},"latencyP95Ms":{"type":["number","null"]},"jitterMs":{"type":["number","null"],"description":"Mean absolute successive difference of the round trips."},"uploadMbps":{"type":["number","null"]},"downloadMbps":{"type":["number","null"]},"failureRate":{"type":["number","null"],"description":"Failed requests over total requests, 0 to 1."},"latencySamplesMs":{"type":"array","items":{"type":"number"},"maxItems":40},"failedRequests":{"type":"integer","minimum":0},"totalRequests":{"type":"integer","minimum":0},"endpointReachable":{"type":"boolean"}},"required":["latencyMedianMs","latencyP95Ms","jitterMs","uploadMbps","downloadMbps","failureRate","latencySamplesMs","failedRequests","totalRequests","endpointReachable"],"additionalProperties":false},"ZoneStability":{"type":"object","description":"Frame timing on the page and a GPU fill probe.","properties":{"frameTimeP95Ms":{"type":["number","null"]},"frameTimeMedianMs":{"type":["number","null"]},"stallCount":{"type":["integer","null"],"minimum":0,"description":"Frames longer than 50 ms during the sample."},"gpuFrameMs":{"type":["number","null"]},"gpuApi":{"type":"string","enum":["webgl2","webgl","none"]}},"required":["frameTimeP95Ms","frameTimeMedianMs","stallCount","gpuFrameMs","gpuApi"],"additionalProperties":false},"ZoneMeasurements":{"type":"object","properties":{"cpu":{"$ref":"#/components/schemas/ZoneCpu"},"network":{"$ref":"#/components/schemas/ZoneNetwork"},"stability":{"$ref":"#/components/schemas/ZoneStability"}},"required":["cpu","network","stability"],"additionalProperties":false},"ZoneScores":{"type":"object","description":"Component scores and the weighted overall, 0 to 100 integers.","properties":{"network":{"type":"integer","minimum":0,"maximum":100},"cpu":{"type":"integer","minimum":0,"maximum":100},"stability":{"type":"integer","minimum":0,"maximum":100},"secondary":{"type":"integer","minimum":0,"maximum":100},"overall":{"type":"integer","minimum":0,"maximum":100}},"required":["network","cpu","stability","secondary","overall"],"additionalProperties":false},"ZonePenalty":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/ZonePenaltyId"},"amount":{"type":"number","minimum":0,"description":"Points subtracted from the overall score."},"message":{"type":"string"}},"required":["id","amount","message"],"additionalProperties":false},"ZoneCompletion":{"type":"object","properties":{"cpu":{"$ref":"#/components/schemas/ZoneTestStatus"},"network":{"$ref":"#/components/schemas/ZoneTestStatus"},"stability":{"$ref":"#/components/schemas/ZoneTestStatus"},"tabLostFocus":{"type":"boolean"},"interrupted":{"type":"boolean"},"warnings":{"type":"array","items":{"type":"string"}}},"required":["cpu","network","stability","tabLostFocus","interrupted","warnings"],"additionalProperties":false},"ZoneResult":{"type":"object","description":"One zone-leader measurement, schema version 1 of the zone-leader diagnostic: the same document the browser downloads.","properties":{"schemaVersion":{"type":"integer","const":1},"diagnosticVersion":{"type":"string","minLength":1,"description":"Semantic version of the scoring model; major and minor must match the site's."},"player":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":48}},"required":["name"],"additionalProperties":false},"testedAt":{"type":"string","format":"date-time"},"diagnosticTarget":{"$ref":"#/components/schemas/ZoneTarget"},"system":{"$ref":"#/components/schemas/ZoneSystem"},"measurements":{"$ref":"#/components/schemas/ZoneMeasurements"},"scores":{"$ref":"#/components/schemas/ZoneScores"},"rating":{"$ref":"#/components/schemas/ZoneRating"},"penalties":{"type":"array","items":{"$ref":"#/components/schemas/ZonePenalty"}},"completion":{"$ref":"#/components/schemas/ZoneCompletion"}},"required":["schemaVersion","diagnosticVersion","player","testedAt","diagnosticTarget","system","measurements","scores","rating","penalties","completion"],"additionalProperties":false},"ZoneExplanation":{"type":"object","description":"Deterministic sentences derived from the measurements.","properties":{"summary":{"type":"string"},"strongest":{"type":"array","items":{"type":"string"}},"limiting":{"type":"array","items":{"type":"string"}},"reason":{"type":"string","description":"Why the recommendation is what it is."}},"required":["summary","strongest","limiting","reason"],"additionalProperties":false},"ZoneRankedResult":{"type":"object","properties":{"rank":{"type":"integer","minimum":1},"name":{"type":"string","description":"The normalised character name the result is stored under."},"tested_at":{"type":"string","format":"date-time"},"rating":{"$ref":"#/components/schemas/ZoneRating"},"recommendation":{"$ref":"#/components/schemas/ZoneRecommendation"},"scores":{"$ref":"#/components/schemas/ZoneScores"},"explanation":{"$ref":"#/components/schemas/ZoneExplanation"},"result":{"$ref":"#/components/schemas/ZoneResult"}},"required":["rank","name","tested_at","rating","recommendation","scores","explanation","result"],"additionalProperties":false},"ZoneResultList":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ZoneRankedResult"},"description":"Ranked best first."}},"required":["items"],"additionalProperties":false},"ProbeHealth":{"type":"object","properties":{"ok":{"type":"boolean"},"service":{"type":"string"},"version":{"type":"string","description":"The diagnostic version the site scores with."}},"required":["ok","service","version"],"additionalProperties":false},"ProbePing":{"type":"object","properties":{"t":{"type":"integer","description":"Server clock in milliseconds since the epoch."}},"required":["t"],"additionalProperties":false},"ProbeUpload":{"type":"object","properties":{"received":{"type":"integer","minimum":0,"description":"Bytes received."}},"required":["received"],"additionalProperties":false}}}}