Developers

Build bots, dashboards and integrations on top of Game Central: read communities, chat, forums, events and game servers with the API, and hear about what happens with webhooks.

Getting a token

Make a personal token in Settings → Developer. The API acts as you, with exactly your access: it sees the communities and channels you can see. Tokens can only read unless you let them post. Send it with every request:

curl https://gamecentral.app/api/v1/me \
  -H "Authorization: Bearer mx_your_token"

Each token can make 120 requests a minute. Over that you get 429 with a Retry-After header. Keep tokens secret: anyone with one can act as you. Delete a token in settings and it stops working at once.

Responses

Everything is JSON. Success is { "data": … }; a problem is { "error": { "code": "…", "message": "…" } } with a matching status: 401 (no or bad token), 403 (not allowed), 404 (not found, or not visible to you), 422 (invalid input) or 429 (too many requests). A message held for moderator review by the community’s automod answers 202 with the code held.

Endpoints

All paths start with https://gamecentral.app/api/v1.

MethodPathWhat it does
GET/meYou, and the communities you’re in.
GET/communities/{slug}A community: name, members, how to join, and your place in it.
GET/communities/{slug}/channelsThe channels you can see.
GET/communities/{slug}/threadsForum threads. ?channel={id} for one forum (with ?sort= and ?page=), otherwise the latest across all of them.
GET/communities/{slug}/eventsUpcoming events, each date of a repeating event separately.
GET/communities/{slug}/serversThe community’s game servers and their live status.
GET/channels/{id}/messagesA chat channel’s messages, oldest first. ?before={id} or ?after={id} to page, ?limit= up to 100.
POST/channels/{id}/messagesPost a message as you: {"content": "…"}. Needs a token that can post.
GET/servers/{id}A listed game server and its live status.

Posting a message:

curl -X POST https://gamecentral.app/api/v1/channels/CHANNEL_ID/messages \
  -H "Authorization: Bearer mx_your_token" \
  -H "Content-Type: application/json" \
  -d '{"content": "Server restarting in 5 minutes"}'

Webhooks

Community managers add webhooks in their community’s settings under Integrations. A Discord webhook URL gets readable messages in that Discord channel; any other https:// address gets a JSON POST for each event it chose. Only content from channels everyone in the community can see is sent. Nobody is pinged by Discord messages.

The events:

  • member.joined
  • member.left
  • message.created
  • thread.created
  • post.created
  • announcement.created
  • event.created
  • application.submitted
  • server.down
  • server.up

A delivery looks like this:

POST /your/endpoint
Content-Type: application/json
X-GameCentral-Event: thread.created
X-GameCentral-Delivery: 0192f1c4-…
X-GameCentral-Timestamp: 1767225600
X-GameCentral-Signature: sha256=5d41402abc4b2a76…

{
  "id": "0192f1c4-…",
  "event": "thread.created",
  "occurredAt": "2026-01-01T00:00:00.000Z",
  "community": { "id": "…", "slug": "my-clan", "name": "My Clan", "url": "…" },
  "data": {
    "channel": { "id": "…", "name": "general" },
    "thread": { "id": "…", "title": "Season 4 plans", "excerpt": "…", "url": "…" },
    "author": { "id": "…", "name": "Alice", "username": "alice", "url": "…" }
  }
}

Answer with any 2xx status within 8 seconds. Network errors, timeouts, 408, 429 and 5xx are tried again up to 5 times, waiting longer each time; redirects aren’t followed. After 20 failed deliveries in a row the webhook switches itself off (switch it back on in settings). The Send test button sends a ping event.

Checking signatures

When you add a JSON webhook you get a signing secret (shown once). Each delivery’s x-gamecentral-signature header is sha256= and the hex HMAC-SHA256, with that secret, of the timestamp header, a dot, and the raw body. Check it, and reject old timestamps, before trusting a delivery:

import { createHmac, timingSafeEqual } from 'node:crypto';

function isFromGameCentral(secret, headers, rawBody) {
  const timestamp = headers['x-gamecentral-timestamp'];
  const expected =
    'sha256=' + createHmac('sha256', secret).update(`${timestamp}.${rawBody}`).digest('hex');
  const given = headers['x-gamecentral-signature'] ?? '';
  const fresh = Math.abs(Date.now() / 1000 - Number(timestamp)) < 300;
  return fresh && given.length === expected.length &&
    timingSafeEqual(Buffer.from(given), Buffer.from(expected));
}

Game Central uses cookies to keep you signed in, check forms aren't sent by bots and remember settings you choose. If you allow it, we'll also remember your time zone so event times show on your clock. No advertising or tracking cookies. Cookie details