Introduction
Getting started

Counter-Strike Boost API

A public, keyless HTTP API for game panels and tools: browse and install CS 1.6 plugins, addon packs, and assemble a complete ready-to-run server.

No key required Read-only https://api.counter-strike-boost.com

Introduction #

Everything under /v1 is public and read-only. There is no signup, no OAuth dance and no key to wait for — a bare curl against any endpoint works right now:

BASH
curl "https://api.counter-strike-boost.com/v1/plugins?per_page=20"

An API key exists, but it is purely a limits upgrade — see API keys. The three surfaces are:

The three APIs #

Base URL and versioning #

All endpoints live under one host. The main website domain does not serve the API — use the api. subdomain.

Base URLhttps://api.counter-strike-boost.com
Versionv1, carried in the path. A breaking change ships as v2; v1 only ever gains fields.
TransportHTTPS only, HTTP/2. Plain HTTP is redirected.
MethodsGET everywhere. There is no write surface on /v1.
Content typeapplication/json; charset=utf-8, except file downloads.
CORSAccess-Control-Allow-Origin: * without credentials — call it straight from a browser frontend.

Add fields defensively: we add response fields without notice, so parse leniently and never assume a fixed key set.

Authentication #

Two tiers. Which one you get is decided by a single thing: whether you sent an Authorization header at all.

TierTriggerIdentified byScopes
Anonymous no Authorization header client IP plugins:read, addons:read, server:read
Key Authorization: Bearer csbk_… the key whatever the key was issued with
A broken key is a hard 401 — never a silent downgrade

The anonymous path is taken only when the header is absent. A header that is present but malformed, unknown, disabled or expired returns 401. Falling back to anonymous would let a rotting key go unnoticed until it hit the much lower keyless ceiling and produced a confusing 429 instead of the real problem.

API keys #

Running a panel that installs at scale? Ask for a key and send it as a bearer token. Same endpoints, much higher limits, and no per-IP compile or build cap. Keys look like csbk_….

BASH
curl -H "Authorization: Bearer csbk_your_key_here" \
     "https://api.counter-strike-boost.com/v1/plugins"

Keys are scoped — plugins:read, addons:read, server:read — and carry their own per-minute and per-day quota. A request needing a scope the key lacks returns 403 insufficient_scope with the required scopes listed. Request a key

Rate limits #

Fixed-window counters. Call /v1/meta at any time to read the exact numbers that apply to you — the defaults below are operator-tunable and the live values always win.

BucketWindowApplies toDefault
Requests1 minuteanonymous, per IPsee rate_limits.per_minute
Requests1 dayanonymous, per IPsee rate_limits.per_day
Compiles
(kind=amxx, kind=zip)
1 houranonymous, per IP60
Server builds
(server-builder/download)
1 houranonymous, per IP10
Compiler flood brake1 minuteeveryone, site-wide40
Key quota1 min / 1 dayper keyissued per key

The compile and build buckets exist because those two calls are the only genuinely expensive ones: a .amxx download runs a native compiler, and a server build reads hundreds of files. Plain JSON reads and kind=sma only face the general limits.

Exceeding a bucket returns 429 rate_limited with a Retry-After header. Back off for that many seconds — retrying immediately just burns the next window.

Errors #

Every error is JSON with the same envelope: status is false and error is a stable machine-readable code. Branch on error, never on the human wording. Some codes add context fields — those are listed with the endpoint that raises them.

JSON
{
  "allowed": ["amxx", "sma", "zip"],
  "error": "invalid_kind",
  "status": false
}

Codes you can hit on any endpoint:

StatuserrorMeaning
401unauthorizedBearer token missing the csbk_ prefix, or unknown. Also returned to keyless callers if an operator has switched keyless access off.
401key_disabledThe key exists but was disabled.
401key_expiredThe key is past its expiry date.
403insufficient_scopeKey lacks the scope. Body carries required: [...].
404not_foundNo such slug/version, or it is not published.
429rate_limitedBucket exhausted. Body carries retry_after (seconds); same value in the Retry-After header.
500query_failedOur database hiccuped. Safe to retry.
503api_disabledThe whole API is switched off by an operator. Rare and brief.
Only published content is visible

Drafts and unpublished versions are invisible to the API — they return 404 exactly like a slug that never existed. There is no way to distinguish the two, by design.

Service metadata #

GET /v1/meta plugins:read addons:read auth optional

Everything a client needs to configure itself at startup: the plugin categories that actually have content, the AMX Mod X toolchains you may pin, the full endpoint map, and — most usefully — the exact rate limits applied to the caller making this request. Call it once on boot rather than hardcoding limits.

Parameters

None. This endpoint takes no parameters.

Response fields

FieldTypeNotes
auth string "anonymous" or "key" — which tier served this request.
authenticated bool Handy sanity check: send a key, get true. Still false? Your header never arrived.
scopes string[] What the caller may do. Anonymous callers get all three read scopes.
amxx_toolchains string[] Valid values for the amxx query parameter on plugin downloads.
plugin_categories object[] Categories with at least one published plugin, plus their counts. Empty categories are omitted, so this is safe to render as a filter list.
rate_limits object The live per-minute and per-day limits for this caller.

A key that is disabled or expired fails here too, which makes /v1/meta the cheapest possible health check for an integration.

Request
cURL
curl "https://api.counter-strike-boost.com/v1/meta"
JavaScript
const res  = await fetch(
  "https://api.counter-strike-boost.com/v1/meta"
);
const data = await res.json();

if (!data.status) {
  throw new Error(data.error);   // stable machine-readable code
}
PHP
<?php
$body = file_get_contents(
    "https://api.counter-strike-boost.com/v1/meta"
);
$data = json_decode($body, true);

if (empty($data['status'])) {
    throw new RuntimeException($data['error'] ?? 'request_failed');
}
Python
import requests

r = requests.get(
    "https://api.counter-strike-boost.com/v1/meta",
    timeout=30,
)
r.raise_for_status()
data = r.json()
Response 200 OK
200 OK
{
  "amxx_toolchains": ["1.8.2", "1.9", "1.10"],
  "api_version": "v1",
  "auth": "anonymous",
  "authenticated": false,
  "docs": "https://counter-strike-boost.com/developers",
  "endpoints": {
    "addon_detail": "/v1/addons/{slug}",
    "addons": "/v1/addons",
    "meta": "/v1/meta",
    "plugin_detail": "/v1/plugins/{slug}",
    "plugin_download": "/v1/plugins/{slug}/download/{version}?kind=amxx|sma|zip",
    "plugins": "/v1/plugins",
    "server_builder_component": "/v1/server-builder/components/{slug}",
    "server_builder_download": "/v1/server-builder/download?components=…&optimized=1",
    "server_builder_file": "/v1/server-builder/file?path=…&components=…&optimized=1",
    "server_builder_meta": "/v1/server-builder/meta",
    "server_builder_resolve": "/v1/server-builder/resolve?components=…&optimized=1"
  },
  "plugin_categories": [
    { "category": "gameplay", "count": 39 },
    { "category": "admin",    "count": 35 },
    { "category": "fun",      "count": 30 },
    { "category": "hud-info", "count": 26 }
  ],
  "rate_limits": { "per_day": 1500, "per_minute": 15 },
  "scopes": ["plugins:read", "addons:read", "server:read"],
  "status": true
}

Conventions #

EnvelopeSuccessful JSON responses always carry "status": true; errors carry "status": false and an error code.
Key orderObject keys come back alphabetically sorted. Do not rely on it — parse by name.
TimestampsStrings in YYYY-MM-DD HH:MM:SS, UTC. An unset timestamp is "", not null.
Empty vs nullLists that are empty come back as [] on list endpoints. A few nested fields (e.g. component rules, build notes) are null when empty — handle both.
Paginationpage_n (1-based, max 100000) and per_page (1–100, default 24). Out-of-range values are clamped, not rejected. Responses echo page, per_page, total, total_pages.
OrderingList endpoints sort by download count, descending. Not configurable.
SlugsLowercase, hyphenated, stable. Use them as your foreign key — names and versions change, slugs do not.
Ready-made URLsResponses embed detail_url, page_url, install_url and download_url. Follow them rather than string-building paths yourself.
DownloadsBinary responses set Content-Disposition: attachment with the correct filename. With curl, -OJ honours it.
Something wrong or missing?

These pages are generated from the live API contract and verified against production on 2026-07-31. If a response here does not match what you got, tell us — that is a bug on our side.