Quick start
Every public endpoint lives under the /api-platform/v1 base and is authenticated with an API key sent in the x-api-key header. One call gets you live cross-game data:
# Recent kills across CS2, CS1.6 and Rust curl https://api.24hgaming.com/api-platform/v1/killboard/feed?limit=5 \ -H "x-api-key: 24hg_your_key_here"
Responses are JSON. All v1 endpoints are read-only — the developer API never mutates platform data. Get a key in under a minute below.
Get an API key
API keys are tied to your 24HG account. Sign in at accounts.24hgaming.com to get a session token, then create a key:
# Create a named key (returns the secret ONCE — save it) curl -X POST https://api.24hgaming.com/api-platform/keys \ -H "Authorization: Bearer <your_session_jwt>" \ -H "Content-Type: application/json" \ -d '{ "name": "my-app", "scopes": ["read"] }'
{
"key": {
"id": 12, "name": "my-app",
"key_prefix": "24hg_a1b2c3",
"tier": "free", "rate_limit": 100,
"api_key": "24hg_a1b2c3..." // shown once — store it now
}
}
api_key is returned only on creation and never again. You can hold up to 10 active keys, list them with GET /api-platform/developer/my-keys, and revoke with DELETE /api-platform/keys/:id. Keys expire one year after creation.Authentication
Send your key in the x-api-key request header on every v1 call. Keys are hashed at rest and scoped to read access.
x-api-key: 24hg_a1b2c3d4e5f6...
Error responses
| Status | Meaning |
|---|---|
| 401 | Missing, invalid, revoked or expired API key |
| 429 | Rate limit exceeded — see the limit, window and retry_after fields, plus the Retry-After response header |
| 400 | Bad request — an unsupported query value (e.g. an unknown game) |
Rate limits
Each key has an hourly request budget set by your subscription tier. Limits are counted per key over a rolling one-hour window; exceeding one returns 429.
Need more? Apply for partner access on Discord.
Response headers
Every authenticated v1 response carries your live budget so you can throttle client-side without guessing:
| Header | Meaning |
|---|---|
| X-RateLimit-Limit | Your tier's request budget per rolling hour. |
| X-RateLimit-Remaining | Requests left in the current window (after this call). |
| X-RateLimit-Reset | Unix epoch (seconds) when the window frees up a slot. |
| Retry-After | On a 429 only: seconds to wait before retrying. |
Endpoints
All paths below are relative to https://api.24hgaming.com/api-platform/v1.
Recent kills across every game (CS2, CS1.6, Rust) from the unified cross-game killboard.
| Param | In | Description |
|---|---|---|
| game | query · optional | cs2, cs16 or rust |
| player | query · optional | Filter to a player — Steam ID or u<userId> (e.g. u42) |
| limit | query · optional | Max results, 1–100 (default 50) |
{
"kills": [{
"id": 12, "game": "cs2", "server_id": 3,
"killer": { "steam_id": "7656...", "user_id": 4, "name": "gamer42" },
"victim": { "steam_id": "7656...", "user_id": 6, "name": "rival" },
"weapon": "ak47", "headshot": true, "distance": 18,
"round_number": 5, "occurred_at": "2026-06-15T12:00:00Z"
}]
}
Top fraggers across every game over a time window, with headshot percentage.
| Param | In | Description |
|---|---|---|
| period | query · optional | week, month or all (default all) |
| game | query · optional | cs2, cs16 or rust |
| limit | query · optional | Max results, 1–100 (default 25) |
{
"period": "all",
"leaders": [{
"rank": 1, "user_id": 4, "steam_id": "7656...",
"name": "gamer42", "game": "cs2",
"kills": 120, "headshots": 48, "hs_pct": 40
}]
}
The Counter-Strike competitive ELO ladder — ranked rating, games, wins and win %. Distinct from the XP-based /leaderboards.
| Param | In | Description |
|---|---|---|
| game | query · optional | cs2 or cs16 (default cs2) |
| limit | query · optional | Max results, 1–200 (default 100) |
{
"game": "cs2",
"leaderboard": [{
"rank": 1, "user_id": 4, "steam_id": "7656...",
"name": "gamer42", "rating": 1240,
"games": 30, "wins": 18, "win_pct": 60
}]
}
The platform-wide XP leaderboard — users ranked by total cross-game XP.
| Param | In | Description |
|---|---|---|
| limit | query · optional | Max results, 1–100 (default 100) |
{
"leaderboard": [{
"rank": 1, "user_id": 1, "username": "gamer42",
"level": 50, "total_xp": 99000
}]
}
All active game servers with live player counts and current map.
| Param | In | Description |
|---|---|---|
| game | query · optional | Filter by game, e.g. cs2, rust, minecraft |
{
"servers": [{
"id": 1, "name": "24HG CS2 Main", "game": "cs2",
"ip": "49.12.36.159", "port": 27015, "status": "online",
"players": 12, "max_players": 20, "map": "de_dust2"
}]
}
Upcoming, active and completed tournaments.
| Param | In | Description |
|---|---|---|
| status | query · optional | upcoming, active or completed |
{
"tournaments": [{
"id": 1, "name": "CS2 Weekly Cup", "game": "cs2",
"status": "upcoming", "max_teams": 16,
"starts_at": "2026-04-01T18:00:00Z"
}]
}
Public profile for a user by ID.
| Param | In | Description |
|---|---|---|
| id | path · required | User ID (integer) |
{
"user": {
"id": 1, "username": "gamer42", "avatar": "/uploads/avatar.png",
"level": 15, "achievements_count": 8, "joined": "2025-01-01T00:00:00Z"
}
}
XP, level, achievement count, forum post count and tournament participation for a user.
| Param | In | Description |
|---|---|---|
| id | path · required | User ID (integer) |
{
"stats": {
"xp": 4500, "level": 15, "total_xp": 12000,
"achievements": 8, "forum_posts": 42, "tournaments_played": 3
}
}
Recent forum threads with author info. Fetch a thread's posts with GET /forum/threads/{id}/posts.
| Param | In | Description |
|---|---|---|
| category_id | query · optional | Filter by category ID |
| limit | query · optional | Max results, 1–50 (default 25) |
| offset | query · optional | Pagination offset (default 0) |
{
"threads": [{
"id": 1, "title": "Welcome!", "author": "admin",
"views": 150, "created_at": "2025-06-01T00:00:00Z"
}]
}
Every available achievement with descriptions, categories and XP rewards.
| Param | In | Description |
|---|---|---|
| category | query · optional | Filter by category |
{
"achievements": [{
"id": 1, "name": "First Blood", "description": "Win your first match",
"icon": "🏆", "category": "general", "xp_reward": 100
}]
}
Webhooks
The v1 endpoints above are pull — you ask, we answer. Webhooks are the push side: register an HTTPS endpoint and 24HG will POST a signed JSON event to it the moment something happens across any game — a kill on the cross-game killboard, a match or tournament result, a server going up or down, or a ban. No polling, every game, one subscription.
https://api.24hgaming.com/webhooks and is authenticated with your account session token (Authorization: Bearer <jwt>), not the x-api-key header. Registering is gated by the API-key tiers — you must hold at least one active key, and your tier sets how many subscriptions you can create.Event types
Subscribe to any subset of these, or to ["*"] for all of them. Each delivery's event field and the X-24HG-Event header tell you which fired.
| Event | Fires when |
|---|---|
| killboard.kill | A kill is recorded on the unified cross-game killboard. |
| match.result | A match (hub / quickmatch / tournament) finishes with a result. |
| tournament.result | A tournament concludes with final standings. |
| server.up | A game server comes online. |
| server.down | A game server goes offline. |
| ban.created | A player ban is issued. |
Register a subscription
POST your endpoint URL and the events you care about. The response returns a signing secret exactly once — store it now; it is never shown again and is used to verify every delivery.
# Subscribe to cross-game kills + match results curl -X POST https://api.24hgaming.com/webhooks \ -H "Authorization: Bearer <your_session_jwt>" \ -H "Content-Type: application/json" \ -d '{ "url": "https://your-app.example.com/hooks/24hg", "events": ["killboard.kill", "match.result"], "description": "my killfeed bot" }'
{
"subscription": {
"id": 7, "url": "https://your-app.example.com/hooks/24hg",
"events": ["killboard.kill", "match.result"],
"tier": "free", "active": true, "secret_set": true
},
"secret": "whsec_3f9a...e21", // shown once — store it now
"message": "Store this signing secret now — it will not be shown again."
}
Manage subscriptions with GET /webhooks (list), PUT /webhooks/:id (change url / events / active / description), POST /webhooks/:id/rotate-secret (issue a fresh secret) and DELETE /webhooks/:id.
Payload & headers
Every delivery is an HTTP POST with a JSON envelope. data is the event-specific body; the rest is constant across event types.
{
"id": "a1b2c3d4-...", // unique delivery id (also X-24HG-Delivery)
"event": "killboard.kill",
"created_at": "2026-06-15T19:30:00Z",
"data": {
"id": 12, "game": "cs2", "server_id": 3, "weapon": "ak47",
"headshot": true, "distance": 18, "round": 5,
"killer": { "user_id": 4, "steam_id": "7656...", "name": "gamer42" },
"victim": { "user_id": 6, "steam_id": "7656...", "name": "rival" }
}
}
Each request carries these headers:
| Header | Meaning |
|---|---|
| X-24HG-Event | The event type, e.g. killboard.kill. |
| X-24HG-Delivery | Unique delivery id — use it to dedupe retries idempotently. |
| X-24HG-Timestamp | ISO-8601 time the delivery was created. |
| X-24HG-Signature | sha256=<hex> HMAC of the raw body — see below. |
Verify signatures
The X-24HG-Signature header is sha256= followed by the hex HMAC-SHA256 of the exact raw request body, keyed by your subscription's signing secret. Compute the same HMAC and compare in constant time before trusting a payload — reject anything that doesn't match.
// Node.js / Express — verify a 24HG webhook const crypto = require('crypto'); app.post('/hooks/24hg', express.raw({ type: 'application/json' }), (req, res) => { const sig = req.get('X-24HG-Signature') || ''; const expected = 'sha256=' + crypto .createHmac('sha256', process.env.WH_SECRET) // your whsec_… secret .update(req.body) // the raw Buffer, not parsed JSON .digest('hex'); const ok = sig.length === expected.length && crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected)); if (!ok) return res.sendStatus(401); const evt = JSON.parse(req.body); // { id, event, created_at, data } // …handle evt.event… then ACK fast: res.sendStatus(200); });
2xx as soon as you've stored the event; do heavy work asynchronously. Any non-2xx (or a timeout past 10s) is treated as a failure and retried.Retries & testing
A delivery is attempted up to 3 times with exponential backoff (≈1s, then ≈3s) until your endpoint returns a 2xx. Each attempt and its outcome is recorded in a per-subscription delivery log. Send yourself a signed sample event any time with the test endpoint:
# Fire a one-off signed test delivery to a subscription curl -X POST https://api.24hgaming.com/webhooks/7/test \ -H "Authorization: Bearer <your_session_jwt>"
{ "delivery_id": "…", "success": true, "attempts": 1,
"status_code": 200, "duration_ms": 142 }
Inspect recent attempts (status code, retries, latency, errors) with GET /webhooks/:id/deliveries. Repeated failures increment the subscription's consecutive_failures counter, surfaced on GET /webhooks.
SDK & resources
The complete machine-readable spec is served live as OpenAPI 3.0 — point Swagger UI, Postman or a codegen tool straight at it:
GET https://api.24hgaming.com/api-platform/docs
| OpenAPI spec | api.24hgaming.com/api-platform/docs |
| Developer portal | /api-platform/developer/portal — SDK, key management, rate limits |
| Community | 24HG Discord — support & partner access |
| Platform | 24HG Social · Stats |