Skip to main content
CSFuse

CSFuse API

Version 1.0 · Base URL: https://csfuse.app/api/v1

Authentication

Most endpoints are public and require no authentication. Authenticated endpoints (/me, /me/matches, /auth/token) require a Bearer token.

Authorization: Bearer cf_<your_api_key>

API keys are issued by CSFuse admins from the admin panel. The raw token is shown only once at issuance — store it safely.

Rate limiting

  • Public endpoints: 60 requests/minute per IP.
  • Authenticated read endpoints: 120 requests/minute per API key.
  • Write endpoints: 30 requests/minute per API key.

Responses include X-RateLimit-Limit, X-RateLimit-Remaining, and Retry-After headers.

Scopes

API keys carry a scope list. The server enforces them at request time — a key lacking the required scope returns 403 insufficient_scope.

Read

  • read:matches
  • read:teams
  • read:stats
  • read:live

Write

  • write:teams
  • write:members
  • write:users
  • write:matches (admin-tier only)

Identity

  • act:discord — enables X-Discord-User-ID

Idempotency

All POST write endpoints accept an Idempotency-Key header. Send the same UUID within 24 hours to safely retry a request: the first response is replayed and the operation is not executed a second time. Reusing a key with a different path or body returns 422 idempotency_key_mismatch.

Idempotency-Key: 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d

Generate a fresh UUID v4 per distinct operation. Reusing a single key across two different operations will result in the second being rejected as a mismatch.

Bot integration (Discord)

To act on behalf of a Discord user, the bot sends its admin API key (with act:discord scope) alongside an X-Discord-User-ID header. The API resolves the header to a CSFuse user via users.discord_id.

Authorization: Bearer cf_<bot_api_key>
X-Discord-User-ID: 123456789012345678
Idempotency-Key: <uuid>

If the Discord ID is not linked to any CSFuse user, the API returns 404 discord_user_not_found with a link_url:

{
  "error": {
    "code": "discord_user_not_found",
    "message": "No CSFuse account is linked to this Discord user.",
    "link_url": "https://csfuse.app/account"
  }
}

Surface this URL in the bot so the user can complete account linking.

Typical flow

  1. User runs /register 76561198067877321. Bot calls POST /api/v1/users/link-steam.
  2. Admin runs /create-team "Alpha Squad" AS. Bot calls POST /api/v1/teams with X-Discord-User-ID = captain.
  3. Admin runs /add-player @user. Bot calls POST /api/v1/teams/3/members with {"discord_id": "..."}.
  4. If the target user hasn't linked a Steam account, the bot can still add them by steam64 — a placeholder account is created and adopted on first login.

Response format

Every response is JSON, wrapped in a consistent envelope.

Single resource

{
  "data": { ... },
  "meta": { }
}

Collection

{
  "data": [ ... ],
  "meta": {
    "total": 142,
    "per_page": 20,
    "current_page": 1,
    "last_page": 8
  },
  "links": { "first": "...", "next": "...", "last": "..." }
}

Error

{
  "error": {
    "code": "not_found",
    "message": "Match not found."
  }
}

Endpoints

GET
/api/v1
API metadata and endpoint index.
GET
/api/v1/matches
Paginated match list. Filters: status, team, map, from, to, format, page, per_page.
GET
/api/v1/matches/{id}
Full match detail including veto, selected maps, map results. Server credentials are never exposed.
GET
/api/v1/teams
Team list.
GET
/api/v1/teams/{id}
Team detail with recent matches.
GET
/api/v1/teams/{id}/stats
Aggregated team statistics (win rate, map records, streaks).
GET
/api/v1/maps
Active map pool.
GET
/api/v1/maps/{id}/stats
Per-map statistics (pick/ban rate, CT/T win rates, team records).
GET
/api/v1/leaderboard
Ranked teams by win rate. Param: min_matches (1–50, default 3).
GET
/api/v1/live
Currently live matches with current scores.
GET
/api/v1/stats
Platform-wide statistics.
GET
/api/v1/head-to-head/{a}/{b}
Head-to-head record between two teams.
GET
/api/v1/me
Authenticated user profile. Requires API key.
GET
/api/v1/me/matches
Authenticated user's team matches. Requires API key.
DELETE
/api/v1/auth/token
Revoke the API key used in this request.
POST
/api/v1/users/link-steam
Link a Steam ID to the Discord user in X-Discord-User-ID. Scopes: write:users, act:discord.
GET
/api/v1/users/by-discord/{discord_id}
Look up a CSFuse user by Discord ID. Scope: act:discord.
POST
/api/v1/teams
Create a team. Optional X-Discord-User-ID assigns the captain. Scope: write:teams.
PATCH
/api/v1/teams/{id}
Update a team (admin key or team leader). Scope: write:teams.
DELETE
/api/v1/teams/{id}
Soft-delete a team. Admin scope only. Scope: write:teams.
POST
/api/v1/teams/{id}/members
Add a member by steam64 or discord_id. Scope: write:members.
DELETE
/api/v1/teams/{id}/members/{steam64}
Remove a team member. Scope: write:members.
PUT
/api/v1/teams/{id}/members/{steam64}/leader
Promote a member to leader. Scope: write:members.
DELETE
/api/v1/teams/{id}/members/{steam64}/leader
Demote a leader. Scope: write:members.
POST
/api/v1/matches
Schedule a match. Admin-tier key only. Scope: write:matches.
PATCH
/api/v1/matches/{id}
Reschedule a match. Admin-tier. Scope: write:matches.
DELETE
/api/v1/matches/{id}
Cancel a match. Admin-tier. Scope: write:matches.

Quick examples

List recent completed matches

curl "https://csfuse.app/api/v1/matches?status=completed&per_page=10"

Team statistics

curl "https://csfuse.app/api/v1/teams/1/stats"

Authenticated

curl -H "Authorization: Bearer cf_xxxxxxxx" "https://csfuse.app/api/v1/me"

Error codes

  • unauthorized — missing or invalid API key (401).
  • insufficient_scope — key lacks the required scope (403).
  • not_admin — endpoint requires an admin-tier key (403).
  • not_authorized — caller is not a leader of this team (403).
  • not_found — resource does not exist (404).
  • discord_user_not_found — Discord ID is not linked to a CSFuse user (404).
  • member_not_found — player is not on the team (404).
  • team_not_found / format_not_found — referenced entity missing or inactive (404).
  • steam_id_already_linked — Steam ID is already linked to a different account (409).
  • already_a_member — user already on this team (409).
  • validation_failed — invalid request parameters or body (422).
  • team_name_taken / team_tag_taken — uniqueness conflict (422).
  • team_at_capacity — team has hit the member cap (422).
  • last_leader_cannot_be_removed / last_leader_cannot_be_demoted — promote another leader first (422).
  • match_not_reschedulable / match_not_cancellable — match status forbids the action (422).
  • idempotency_key_mismatch — same Idempotency-Key used with different path or body (422).
  • too_many_requests — rate limit exceeded (429).

Security

The API never exposes dedicated server credentials — host, port, password, and RCON password are excluded from every response. Match server connection details are web-only and require an authenticated team leader account.