Data API (reference)
A read-only, customer-scoped HTTP API for your own tooling — killfeed bots, leaderboard sites, Discord integrations — to read the servers you own. A key can only ever see the servers belonging to the account that minted it.
Base URL: https://api.citadel-hub.com/api/v1.
Everything below lives under /data. The interactive reference (try-it-out) is at /developers, and the machine-readable OpenAPI 3.1 spec is served unauthenticated at https://api.citadel-hub.com/api/v1/openapi.json.
Getting a key
Mint a key in your Citadel dashboard under Account → API Keys. The raw value (ctk_…) is shown once at creation and never again — copy it immediately. If you lose it, revoke it and mint a new one. Keys are scoped to your account and cannot be transferred.
Authentication
Send the key on every /data request, either as a bearer token or a custom header:
Authorization: Bearer ctk_…
or
X-Citadel-Api-Key: ctk_…
A missing, unknown, or revoked key returns 401. Requesting a server you don't own returns 404 (not 403) — so a key can't probe the id space of other accounts.
Rate limits
Each key carries a tier that sets two ceilings: a per-minute request rate and a hard cap on any single page's limit. Exceeding the rate returns 429 with a retryAfter of 60 seconds; a limit above your tier's page cap is silently clamped down. The default standard tier is sufficient for a typical killfeed or leaderboard integration; contact support for a higher tier.
No coordinates, by design
This API deliberately exposes no live player coordinates (no x/y/z). Position streams are exactly what enable radar and other cheating, which cuts against the Trust Network's whole reason for existing. Online-player endpoints return identities and session info only.
Errors
Errors share one shape:
{
"error": "NOT_FOUND",
"message": "Server not found",
"statusCode": 404,
"requestId": "…"
}
Quote requestId to support when reporting a failure.
GET /data/servers
Every non-revoked server owned by the key's account, with live online status, newest activity first.
curl https://api.citadel-hub.com/api/v1/data/servers \
-H "Authorization: Bearer ctk_…"
{
"servers": [
{
"id": "0f9c2b6e-1a2b-4c3d-8e4f-5a6b7c8d9e0f",
"name": "Chernarus Hardcore",
"map": "chernarusplus",
"gameVersion": "1.29",
"online": true,
"lastSeenAt": "2026-07-16T18:42:10.000Z"
}
]
}
Use the id here as the {serverId} in every endpoint below.
GET /data/servers/
One server's status, including the latest metrics sample (player count, FPS, uptime).
curl https://api.citadel-hub.com/api/v1/data/servers/0f9c2b6e-1a2b-4c3d-8e4f-5a6b7c8d9e0f \
-H "Authorization: Bearer ctk_…"
{
"id": "0f9c2b6e-1a2b-4c3d-8e4f-5a6b7c8d9e0f",
"name": "Chernarus Hardcore",
"map": "chernarusplus",
"gameVersion": "1.29",
"online": true,
"players": 38,
"fps": 42.7,
"uptimeSeconds": 51840,
"lastSeenAt": "2026-07-16T18:42:10.000Z",
"metricsAt": "2026-07-16T18:42:05.000Z"
}
players, fps, uptimeSeconds, and metricsAt are null when no metrics have been sampled yet.
GET /data/servers//players
Players active in the last 90 seconds, identities only. No coordinates.
curl https://api.citadel-hub.com/api/v1/data/servers/0f9c2b6e-…/players \
-H "Authorization: Bearer ctk_…"
{
"players": [
{ "steamId": "76561198000000001", "name": "Survivor_Ana" },
{ "steamId": "76561198000000002", "name": "Boris" }
],
"count": 2
}
GET /data/servers//leaderboard
Ranked players for the server.
| Query | Default | Notes |
|---|---|---|
sort | points | One of points, kd, kills |
limit | 25 | 1–1000, clamped to your tier's page cap |
offset | 0 | For paging through the ranking |
curl "https://api.citadel-hub.com/api/v1/data/servers/0f9c2b6e-…/leaderboard?sort=kills&limit=2" \
-H "Authorization: Bearer ctk_…"
{
"total": 1284,
"sort": "kills",
"players": [
{
"rank": 1,
"steamId": "76561198000000010",
"name": "Reaper",
"kills": 412,
"deaths": 88,
"headshots": 190,
"kd": 4.68,
"points": 824,
"meanKillDistance": 143.2,
"playMinutes": 9820
},
{
"rank": 2,
"steamId": "76561198000000011",
"name": "Ghost",
"kills": 388,
"deaths": 121,
"headshots": 150,
"kd": 3.21,
"points": 776,
"meanKillDistance": 96.5,
"playMinutes": 11040
}
]
}
meanKillDistance (metres) is null for a player with no recorded kills. points is kills × 2. total is the full player count across the ranking (use it with offset to page).
GET /data/servers//kills
The killfeed, newest first. This is a cursor feed: pass the previous response's nextCursor back as before to page backwards in time. nextCursor is null when there are no older kills.
| Query | Default | Notes |
|---|---|---|
before | now | ISO-8601 timestamp; returns kills strictly before this instant |
limit | 50 | 1–1000, clamped to your tier's page cap |
curl "https://api.citadel-hub.com/api/v1/data/servers/0f9c2b6e-…/kills?limit=1" \
-H "Authorization: Bearer ctk_…"
{
"kills": [
{
"ts": "2026-07-16T18:41:52.000Z",
"killerSteamId": "76561198000000010",
"killerName": "Reaper",
"victimSteamId": "76561198000000022",
"victimName": "Fresh_Spawn",
"weapon": "M4-A1",
"distance": 118.4,
"isHeadshot": true,
"hitZone": "Head"
}
],
"nextCursor": "2026-07-16T18:41:52.000Z"
}
To pull the next page: ?before=2026-07-16T18:41:52.000Z. hitZone may be null.
GET /data/servers//bans
The server's ban list, newest sync first.
| Query | Default | Notes |
|---|---|---|
active | (all) | true for currently-active bans, false for expired; omit for both |
limit | 100 | 1–1000, clamped to your tier's page cap |
offset | 0 | For paging |
curl "https://api.citadel-hub.com/api/v1/data/servers/0f9c2b6e-…/bans?active=true&limit=1" \
-H "Authorization: Bearer ctk_…"
{
"bans": [
{
"steamId": "76561198000000099",
"playerName": "Cheater123",
"reason": "Aimbot",
"source": "manual",
"permanent": false,
"bannedAt": "2026-07-10T12:00:00.000Z",
"expiresAt": "2026-08-10T12:00:00.000Z"
}
]
}
permanent is true (and expiresAt null) for a ban with no expiry. source is one of manual, import, or cloud.
See also: the public Trust API for cross-community player trust lookups (no key required).