POST /v1/post/fetch
The full request and response contract for live server payloads.
Returns the most recent payload for every requested address, registers valid unknown addresses, and reports per-row validation problems without failing the batch.
https://api.gamequery.dev/v1/post/fetch
Request headers
Content-Type: application/json
X-API-Token: YOUR_API_KEY
X-API-Token-Type: FREE
X-API-Token-Email: [email protected]Request body
{
"servers": [
{
"game_id": "counterstrike16",
"servers": ["192.168.0.1:27015", "192.168.0.2:27015"]
}
]
}| Field | Type | Rules |
|---|---|---|
servers | array | Required. Must be an array or the request returns POST_2. |
servers[].game_id | string | Must match an id from GET /v1/get/games. |
servers[].servers | string array | IPv4 ip:port entries. Max 1000 across all groups. |
Duplicate game_id + address pairs within one request are collapsed before the
lookup, so repeating an address costs nothing but does not fetch it twice.
Success response
Status 200, Content-Encoding: gzip. The body is an object keyed by
ip:port, plus exactly one non-address key, _meta.
{
"192.168.0.1:27015": {
"name": "Example Server",
"map": "de_dust2",
"password": false,
"numplayers": 16,
"maxplayers": 32,
"players": [
{ "name": "player-one", "raw": { "score": 61, "time": 10225.85 } }
],
"bots": [],
"connect": "192.168.0.1:27015",
"queryPort": 27015,
"ping": 46,
"version": "1.1.2.7/Stdio",
"raw": {
"protocol": 48,
"folder": "cstrike",
"game": "example.mod",
"appId": 10,
"numbots": 0,
"secure": 1
},
"updated": "2026-08-30 13:22:36",
"_updater": {
"status": "online",
"firewall_interval_minutes": 1,
"firewall_label": "none",
"next_probe_at": "2026-08-30T13:23:00.000Z",
"last_probe_at": "2026-08-30T13:22:36.000Z",
"last_online_at": "2026-08-30T13:22:36.000Z"
}
},
"_meta": {
"auto_inserted": 1,
"inserted_servers": [
{ "game_id": "counterstrike16", "server": "192.168.0.1:27015" }
],
"invalid_servers": []
}
}Payload fields
| Field | Type | Notes |
|---|---|---|
name | string | Server hostname as the server reports it. |
map | string | Current map. |
password | boolean | Whether the server is password protected. |
numplayers | number | Current player count. This is the player count, not players. |
maxplayers | number | Slot count. |
players | array | Roster. Entry shape varies by game; name is the stable field. |
bots | array | Bot roster, often empty. |
connect | string | Address a client should connect to. |
queryPort | number | Port that answered the query. |
ping | number | Milliseconds measured by the probing worker, not by you. |
version | string | Game or protocol version string. |
raw | object | Protocol-specific fields, passed through unnormalised. Shape differs per game. |
updated | string | YYYY-MM-DD HH:MM:SS in UTC, not ISO 8601. |
_updater | object | Probe metadata. See Data Freshness. |
Only name, connect, updated and _updater are dependable across every
game. Everything else, raw above all, follows whatever the game's own
protocol exposes. Treat missing fields as unknown rather than as zero.
_meta
| Field | Type | Meaning |
|---|---|---|
auto_inserted | number | How many game_id + address pairs were newly registered. |
inserted_servers | array | Those pairs, as { game_id, server }. |
invalid_servers | array | Rejected rows, as { game_id, servers }. |
A row lands in invalid_servers when game_id is empty, is not in the
catalogue, has an empty servers array, or when an address does not match IPv4
ip:port. The rest of the batch still succeeds with 200, so this array is the
only place validation failures are reported. Log it.
Address with no data yet
{
"192.168.0.5:27015": {
"message": "Server not updated yet, or not existing in database",
"_updater": { "status": "unknown", "firewall_interval_minutes": 1 }
}
}Stale payload
{
"192.168.0.1:27015": {
"name": "Example Server",
"numplayers": 16,
"updated": "2026-08-30 12:04:11",
"message": "Server data is stale and awaiting a fresh updater refresh",
"_stale": true,
"_stale_age_seconds": 4705,
"_stale_expected_max_age_seconds": 180
}
}The original fields are kept. Render it as last-known state rather than discarding it.
Failure responses
| Status | Body |
|---|---|
400 | {"error":"POST_2","message":"Invalid request format"} |
400 | {"error":"POST_3","message":"Exceeded maximum server request limit (1000)"} |
400 | {"error":"POST_4","message":"Invalid JSON format"} |
401 | {"message":"API token is required"} and the other credential messages |
403 | {"message":"Request origin is blocked by API key whitelist settings"} |
405 | {"error":"POST_1","message":"Method Not Allowed. Only POST requests are accepted."} |
429 | {"message":"Daily quota exceeded for this API key","quota":1440,"used":1440} |
500 | {"message":"Internal server error"} |
See Errors and Limits for when each one fires.