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.

Sign in to CSFuse

Pick how you'd like to sign in.

Continue with Steam Continue with Discord

Discord users are asked for their Steam ID once after sign-in.

What does Steam sign-in share with CSFuse?
  • You enter your password on steamcommunity.com, never on CSFuse.
  • We only receive your public SteamID.
  • We can't see your friends, inventory, trades, or market history.
  • We can't trade, gift, or change anything on your account.