Wardog Servers API
本站背后的数据以免费、只读的 JSON API 形式开放:游戏内浏览器列出的每个 WARDOGS 服务器,大约每分钟刷新一次;另有用于绘制图表的玩家历史,以及按加入码查询的单个服务器历史。
概览
基础 URL 为 https://api.wardogservers.com。所有响应均为 JSON,读取无需 API 密钥。
完整的接口规范以 OpenAPI 3.1 文档的形式发布在 https://api.wardogservers.com/openapi.json ↗。该文档是权威来源;本页只是便于阅读的摘要。
- 采集器大约每分钟轮询一次各地区的游戏内服务器浏览器。当前间隔会在每个响应的 meta.refreshSeconds 中给出。
- 只接受来自 wardogservers.com 的浏览器请求。请从你自己的服务器、机器人或脚本调用 API,不要从其他域名的网页调用。
- 未知、重复或格式错误的查询参数会被拒绝并返回 400,而不是被忽略,这样拼写错误会直接报错,而不会悄悄返回全部数据。
快速上手
三个请求就能覆盖大多数用途:当前总数、符合筛选条件的最热门服务器,以及按实例 ID 查询单个服务器。
# 当前总数
curl https://api.wardogservers.com/v1/stats
# 欧洲西部还有空位的社区服务器,人最多的在前
curl "https://api.wardogservers.com/v1/servers?region=eu-west&type=community&hideFull=true&limit=10"
# 按实例 ID 查询单个服务器
curl https://api.wardogservers.com/v1/servers/$ID /v1/stats 的精简响应如下:
{
"data": {
"serverCount": 3544,
"playerCount": 252109,
"officialServerCount": 2765,
"communityServerCount": 779
},
"meta": {
"fetchedAt": "2026-09-13T12:54:57.302Z",
"snapshotId": "95635cb938811a34…",
"refreshSeconds": 60,
"stale": false,
"requestedRegions": ["asia-east", "asia-southeast", "…"],
"observedRegions": ["asia-east", "asia-west", "…"]
}
} 接口
所有读取接口都接受 GET 和 HEAD,支持 If-None-Match,并使用下文所述的响应封装。
| 接口 | 返回 |
|---|---|
GET /v1/servers | 服务器列表,支持筛选、排序和分页。 |
GET /v1/servers/{id} | 单个服务器,带额外的详情字段:原始属性、版本、等级和资金限制。 |
GET /v1/snapshot | 当前快照中的所有服务器,按实例 ID 排序,不带筛选和分页。适合在本地保存完整列表并自行筛选的客户端。 |
GET /v1/regions | 每个地区的服务器和玩家数量,以及上次轮询中各地区是否被请求、是否被观测到。 |
GET /v1/stats | 总数:在线服务器和玩家,分为官方和社区。 |
GET /v1/history/players | 用于图表的玩家和服务器时间序列。 |
GET /v1/history/heatmap | 过去 28 天某项指标按 UTC 星期和小时的平均值。 |
GET /v1/history/peaks | 历史和每日玩家峰值,包括总体和各服务器类型。 |
GET /v1/history/servers | 采集器记录过的服务器,按加入码区分,最近出现的在前。可以找到当前离线的服务器。 |
GET /v1/history/servers/ranking | 按在线时间乘以玩家人数排名的服务器:过去一天、一周或一个月的平均玩家人数,离线时间按零计算。 |
GET /v1/history/servers/{serverId} | 单个服务器(按加入码)每个时间桶的玩家人数、峰值、人数上限、在线率和地图。 |
GET /v1/history/servers/{serverId}/events | 单个服务器的变更日志,最新的在前:上线、下线、重启、版本、地图、修饰项和限制变更。 |
GET /readyz | 有新鲜快照时返回 200,快照缺失或过期时返回 503。 |
GET /openapi.json | OpenAPI 3.1 文档。 |
筛选服务器列表
/v1/servers 的所有参数都是可选的。除 q 外,取值均区分大小写。
| 参数 | 取值 | 含义 |
|---|---|---|
q | 文本,最多 200 个字符 | 不区分大小写的搜索,范围包括实例 ID、加入码、名称、地区、服务器编号、地图和模式。 |
region | eu-west,eu-central | 一个或多个地区 ID,用逗号分隔。当前列表见 /v1/regions。 |
type | all · official · community, 默认 all | 官方服务器、社区服务器,或两者都要。 |
hideEmpty | true · false | 排除没有玩家的服务器。 |
hideFull | true · false | 排除已满的服务器,包括 0/0。 |
passwordProtected | true · false | 只看上锁的或只看未上锁的服务器。不传则两者都包括。 |
sort | -players · players · name · region | -players 表示人最多的在前,为默认值。 |
limit | 1–500, 默认 100 | 每页数量。 |
offset | 0–100000, 默认 0 | 在筛选、排序后的结果中从零开始的偏移量。 |
响应封装
每个成功的响应都包含 data 和 meta。列表接口还会加上 pagination;历史接口会加上一个 history 对象,描述时间范围、分组、指标和时间桶大小。
在把数字当作当前数据展示之前,先检查 meta.stale。当采集暂停,或快照比 refreshSeconds 加 60 秒还旧时,它为 true。过期的响应还会带上 Cache-Control: no-store 和 X-Data-Stale: true。
| 字段 | 含义 |
|---|---|
meta.fetchedAt | 采集器获取此快照的时间。 |
meta.snapshotId | 快照标识符;每当有新数据进来就会改变。也会通过 X-Snapshot-Id 响应头发送。 |
meta.refreshSeconds | 采集器的轮询间隔。不要比这个更频繁地轮询。 |
meta.stale | 当数据不应作为实时数据展示时为 true。 |
meta.requestedRegions | 采集器向游戏请求的地区。 |
meta.observedRegions | 在此快照中至少返回了一个服务器的地区。 |
服务器对象
这是 /v1/servers 和 /v1/snapshot 返回的摘要结构。/v1/servers/{id} 返回相同的字段,外加 attributes、build、level 和 cash。
{
"id": "001ab36e-9985-4a9c-8dff-9dc137826dfe",
"serverId": "756872",
"serverIdUpdatedAt": "2026-09-13T11:14:32.995Z",
"name": "Official #4",
"nativeName": "f14859cce268",
"type": "official",
"region": "eu-south",
"players": 100,
"maxPlayers": 100,
"reservedPlayers": 0,
"passwordProtected": false,
"serverNumber": 4,
"map": { "variant": "Bakurani", "base": "Europe" },
"mode": { "experience": "Bakurani_KOTH_01", "gameMode": "GM_Session_C", "modifiers": [] },
"rulesets": ["standard"]
} | 字段 | 含义 |
|---|---|
id | 游戏实例的实时 ID。服务器重启后会改变,所以不要把它当作永久键。 |
serverId | 游戏内加入码,字符串类型:官方服务器为保留前导零的十进制数字;自游戏补丁 0.11 起,社区服务器为 UUID。尚未采集时为 null。 |
serverIdUpdatedAt | 上次查询加入码的时间。serverId 为 null 时它也为 null。 |
name | 官方服务器为 Official #N,其他为解码后的服务器名称。可能为空。 |
nativeName | 游戏报告的原始服务器名称。 |
type | official 或 community。 |
region | 地区 ID,例如 eu-west。 |
players · maxPlayers · reservedPlayers | 当前、最大和预留的玩家数。 |
passwordProtected | 加入时是否需要密码。 |
serverNumber | 官方服务器编号;社区服务器为 0。 |
map | 地图变体和基础地图。两者都可能为 null。 |
mode | 体验名称和游戏模式名称,以及 experience 字符串中原始的 + 修饰项,按原有顺序排列。 |
rulesets | standard、hardcore 或 infantry-only,由修饰项推导而来。无法识别任何规则集时,恰好为 ["standard"]。 |
历史
/v1/history/players 返回列式序列:一个以 Unix 秒表示的时间桶起始时间数组,以及每个分组键各一个数值数组,按索引对齐。null 值表示该时间桶没有任何记录,通常是因为采集器暂停了。请显示为空缺,不要插值。
从历史记录功能开启起,每个快照记录一次时间桶,不会回填。分钟级时间桶保留 7 天,五分钟级保留 90 天,小时级永久保留。
| 参数 | 取值 | 含义 |
|---|---|---|
window | 24h · 7d · 30d · 90d · 1y, 默认 24h | 截至当前的时间范围。时间桶步长:24h 为 60 秒,7d 为 300 秒,30d 和 90d 为 3600 秒,1y 为 21600 秒。 |
group | total · type · region · regionType · map · ruleset, 默认 total | 每个键对应一条序列:total;official 和 community;地区;region|type;地图变体;或主要规则集。 |
metric | players · servers · full · empty · capacity · free, 默认 players | players、servers、full(已满)、empty、capacity(maxPlayers 之和)或 free(capacity 减去 players)。每个值是该时间桶内各快照的平均值。 |
GET /v1/history/players?window=24h&group=type
{
"data": {
"t": [1789217880, 1789217940, 1789218000, "…"],
"series": {
"official": [248112, 248390, null, "…"],
"community": [3902, 3911, null, "…"]
},
"peak": { "official": ["…"], "community": ["…"] }
},
"history": {
"window": "24h", "group": "type", "metric": "players",
"step": 60, "from": 1789217880, "to": 1789304280, "since": 1789257600
},
"meta": { "…": "…" }
} 当 metric=players 时,响应还会带一个 peak 对象,给出每个时间桶内单个快照的最高值。热力图接口按 UTC 星期和小时计算某项指标在过去 28 个完整天内的平均值,可选只看一个地区。峰值接口报告单个快照的最高玩家人数,包括总体和各类型,涵盖历史最高以及过去 30 个 UTC 日中的每一天。
单个服务器历史
单个服务器历史以加入码为键;与实例 ID 不同,加入码在重启和换图后保持不变。/v1/history/servers/{serverId} 返回对齐的数组:服务器在列期间的平均玩家人数和单次轮询最高值、人数上限、该时间桶内列出它的轮询所占比例(即在线率,0 到 1),以及时间桶结束时的地图,因此连续的地图值就构成了轮换。第一次看到某个加入码时才开始记录,不会回填,在此之前该路由返回 404。
| 参数 | 取值 | 含义 |
|---|---|---|
window | 24h · 7d · 30d · 90d, 默认 24h | 24h 和 7d 使用保留 7 天的五分钟级时间桶;30d 和 90d 使用保留 90 天的小时级时间桶。 |
GET /v1/history/servers/756872?window=24h
{
"data": {
"server": {
"serverId": "756872",
"name": "Official #4",
"type": "official",
"region": "eu-south",
"instanceId": "001ab36e-9985-4a9c-8dff-9dc137826dfe",
"firstSeen": "2026-09-13T00:00:39.000Z",
"lastSeen": "2026-09-14T11:53:22.000Z",
"samples": 2132,
"live": true
},
"t": [1789300800, 1789301100, 1789301400, "…"],
"players": [100, 98, null, "…"],
"peak": [100, 100, null, "…"],
"capacity": [100, 100, null, "…"],
"online": [1, 0.8, null, "…"],
"map": ["Bakurani", "Bakurani", null, "…"]
},
"history": {
"window": "24h", "step": 300,
"from": 1789300800, "to": 1789387200, "since": 1789257600
},
"meta": { "…": "…" }
} /v1/history/servers/{serverId}/events 根据连续的轮询推算出变更日志,最新的在前:tracking_started、online、offline、restart(实例改变且没有空缺)、build(changelist)、map(变体、世界或天空)、modifiers 和 limits(等级和资金范围、密码和人数上限)。每个事件带有 at、kind,以及只包含定义该类型的字段的 before 和 after 对象,没有更早或更晚状态时为 null。limit 取值 1 到 500,默认 100。
GET /v1/history/servers/756872/events?limit=3
{
"data": {
"server": { "serverId": "756872", "name": "Official #4", "…": "…" },
"events": [
{
"at": "2026-09-14T12:40:30.000Z",
"kind": "map",
"before": { "map": "Madrid", "world": "Europe", "sky": "DayEarlyFog" },
"after": { "map": "Detroit", "world": "Europe", "sky": "DayLateGray" }
},
{
"at": "2026-09-14T09:12:04.000Z",
"kind": "restart",
"before": { "instanceId": "001ab36e-9985-4a9c-8dff-9dc137826dfe" },
"after": { "instanceId": "7c1e0b52-3d9a-4e1f-9b6e-2f4c8a9d0e11" }
},
{
"at": "2026-09-13T00:00:39.000Z",
"kind": "tracking_started",
"before": null,
"after": { "instanceId": "…", "changelist": "501228", "map": "Bakurani", "…": "…" }
}
]
},
"history": { "limit": 3, "since": 1789257600 },
"meta": { "…": "…" }
} /v1/history/servers 列出已记录的服务器,最近出现的在前。q 精确匹配加入码,或不区分大小写地匹配最后已知名称,所以能找到当前离线的服务器;在线服务器在 /v1/servers 中已经带有 serverId。
| 参数 | 取值 | 含义 |
|---|---|---|
q | 文本,最多 200 个字符 | 加入码(精确匹配)或最后已知名称(不区分大小写匹配)。 |
type | all · official · community, 默认 all | 官方服务器、社区服务器,或两者都要。 |
limit | 1–100, 默认 20 | 返回多少个服务器。 |
缓存与轮询
每个响应都带有 ETag。把它作为 If-None-Match 发回来,快照未变时会返回不带响应体的 304,双方几乎都没有开销。推荐的用法是每分钟带 If-None-Match 轮询一次。
const res = await fetch('https://api.wardogservers.com/v1/snapshot', {
headers: lastEtag ? { 'if-none-match': lastEtag } : {}
});
if (res.status === 304) return; // 自上次轮询以来没有变化
lastEtag = res.headers.get('etag');
const { data, meta } = await res.json();
if (meta.stale) console.warn('stale'); // 采集器落后了;继续显示最后已知的数据 新鲜的响应会在边缘节点缓存 15 秒,所以短时间内大量相同的请求开销很低。目前没有硬性速率限制,但比 meta.refreshSeconds 更频繁地轮询并不能拿到更新的数据,将来也可能被限速。如果你需要完整列表,请获取一次 /v1/snapshot 后在本地筛选,而不是翻页遍历 /v1/servers。
错误
错误以 JSON 返回,包含稳定的 code 和人类可读的 message。message 可能会变;请根据 code 判断。
{
"error": {
"code": "bad_request",
"message": "An unsupported query parameter was supplied."
}
} | 状态码 | 何时出现 |
|---|---|
400 | 查询参数未知、重复或无效,或者 ID 不是 UUID。 |
401 | 需要 API 密钥,但缺失或错误。公开访问开启期间,读取请求不会返回此错误。 |
404 | 当前快照中没有该 ID 的服务器、该加入码没有历史记录,或路由不存在。 |
405 | 使用了 GET 或 HEAD 以外的方法。 |
503 | 没有可用的快照。请一分钟后或在 /readyz 返回 200 时重试。 |
使用条款
API 对社区项目免费开放:Discord 机器人、直播叠加层、仪表盘、研究。公开展示数据时,请附上指向 Wardog Servers 的链接注明出处,并且不要把它说成是 BULKHEAD 或 Team17 的官方数据。
读取 API 的版本路径为 /v1。同一版本内可能会新增字段,所以请兼容你不认识的键。破坏性变更将作为新版本发布,并会先在本页公布。
有问题、想展示你的项目,或需要某个字段:Discord @xcausxn。