# CSBoard API

> Market data + programmatic buying over the CSBoard CS2 marketplace — live listings, floats, stickers, minAsk prices, FX rates, and (opt-in) buying skins straight from your balance. Free to read, key-gated, built for automation and AI agents. Fetch this single file and you have the entire public API.

Base URL: `https://csboard.com/v1`

Human docs: https://csboard.com/docs

## Authentication

Send your key as a Bearer token on every request:

```
Authorization: Bearer csb_pub_...
```

- Keys are generated in your profile: https://csboard.com/en/profile?tab=api
- `GET /v1/health` needs no key. Every other endpoint requires one.

Example:

```bash
curl https://csboard.com/v1/listings \
  -H "Authorization: Bearer csb_pub_..."
```

## Rate limits

- Pointed endpoints (`/v1/listings`, `/v1/prices`, `/v1/currency`): 30 requests/minute per key.
- Bulk snapshot (`/v1/prices/snapshot.ndjson.gz`): 1 request/minute per key.
- Buying (`POST /v1/orders`): 30 requests/minute per key (one order carries up to 10 items).
- Exceeding a limit returns HTTP 429 with body `{ "code": "rate_limit_exceeded" }` and a `Retry-After` header.
- More than 30 bad keys/minute from one IP triggers a 5-minute ban.
- Need a higher limit? Email support@csboard.com to raise your key's limit.

## Endpoints

### GET /v1/health

Liveness + freshness probe. No auth required.

Response:

```json
{
  "status": "ok",
  "version": "v1",
  "groups": 31821,
  "price_list_age_seconds": 38,
  "server_now": "2026-06-02T18:37:42Z"
}
```

- `groups` — count of priced item groups.
- `price_list_age_seconds` — age of the materialized price list (freshness).

```bash
curl https://csboard.com/v1/health
```

### GET /v1/listings

Live buyable listings across the marketplace. Auth required.

Query parameters:

- `search` (string) — full-text match on market hash name.
- `category` (string) — e.g. Rifle, Knife, Gloves.
- `wear` (enum) — Factory New | Minimal Wear | Field-Tested | Well-Worn | Battle-Scarred.
- `rarity` (string) — e.g. Classified, Covert.
- `min_price` (number, USD) / `max_price` (number, USD).
- `min_float` (number) / `max_float` (number).
- `stat_trak` (only | exclude).
- `souvenir` (only | exclude).
- `sort` (id | newest | price_asc | price_desc) — default `id`.
- `cursor` (string) — keyset cursor from `next_cursor`.
- `limit` (number) — 1–200, default 50.

Response shape: `{ items: Listing[], next_cursor: string | null }`

A `Listing` is:

```
{
  id, market_hash_name, wear, doppler_phase, float_value, paint_seed,
  stickers: [{ name, image, slot, wear }],
  price_usd, category, rarity, image, inspect_link,
  tradable, tradable_at,
  delivery   // "instant" | "hold"
}
```

Example:

```bash
curl "https://csboard.com/v1/listings?category=Rifle&wear=Minimal%20Wear&stat_trak=only&limit=1" \
  -H "Authorization: Bearer csb_pub_..."
```

```json
{
  "items": [
    {
      "id": "000012e8-1f4a-4c2b-9d3e-7a1b2c3d4e5f",
      "market_hash_name": "StatTrak™ AK-47 | The Oligarch (Minimal Wear)",
      "wear": "Minimal Wear",
      "doppler_phase": null,
      "float_value": 0.1427,
      "paint_seed": 671,
      "stickers": [],
      "price_usd": 267.66,
      "category": "Rifle",
      "rarity": "Classified",
      "image": "https://cdn.cs2c.app/...",
      "inspect_link": "steam://...",
      "tradable": true,
      "tradable_at": null,
      "delivery": "instant"
    }
  ],
  "next_cursor": "eyJpZCI6IjAwMDAxMmU4In0"
}
```

### GET /v1/prices

The minAsk price list — one row per market hash name (+ wear + Doppler phase). Auth required.

Query parameters:

- `search` (string) — full-text match on market hash name.
- `category` (string) — e.g. Rifle, Knife, Gloves.
- `wear` (enum) — Factory New … Battle-Scarred.
- `rarity` (string) — e.g. Classified, Covert.
- `min_price` (number, USD) / `max_price` (number, USD).
- `cursor` (string) — keyset cursor from `next_cursor`.
- `limit` (number) — 1–500, default 100.

Response shape: `{ items: [{ market_hash_name, wear, doppler_phase, min_price_usd, qty }], next_cursor: string | null }`

Example:

```bash
curl "https://csboard.com/v1/prices?search=AK-47%20Redline&limit=1" \
  -H "Authorization: Bearer csb_pub_..."
```

```json
{
  "items": [
    {
      "market_hash_name": "AK-47 | Redline (Battle-Scarred)",
      "wear": "Battle-Scarred",
      "doppler_phase": null,
      "min_price_usd": 25.99,
      "qty": 636
    }
  ],
  "next_cursor": null
}
```

### GET /v1/prices/snapshot.ndjson.gz

Full gzipped NDJSON dump of the price list — one price row JSON per line. Auth required. Rate limited to 1 request/minute. Use this for full-catalog ingestion (e.g. comparison sites), not pagination.

Supports `ETag` / `If-None-Match`: an unchanged snapshot returns `304 Not Modified`, so you only download when the catalog actually moved.

Each line is a price row: `{ market_hash_name, wear, doppler_phase, min_price_usd, qty }`.

Example:

```bash
curl --compressed \
  -H "Authorization: Bearer csb_pub_..." \
  https://csboard.com/v1/prices/snapshot.ndjson.gz
```

```
{"market_hash_name":"AK-47 | Redline (Battle-Scarred)","wear":"Battle-Scarred","doppler_phase":null,"min_price_usd":25.99,"qty":636}
{"market_hash_name":"AWP | Asiimov (Field-Tested)","wear":"Field-Tested","doppler_phase":null,"min_price_usd":74.10,"qty":211}
```

### GET /v1/currency

FX rates with USD as the base. Auth required. All API prices are USD — use this to convert to a local currency. Backed by the same rate table the site and payment flows use (cached ~1h).

Response shape: `{ base: "USD", rates: { USD: 1, RUB: 81.4, EUR: 0.92, ... }, updated_at, rub_source, base_source }`

```bash
curl https://csboard.com/v1/currency \
  -H "Authorization: Bearer csb_pub_..."
```

```json
{
  "base": "USD",
  "rates": { "USD": 1, "RUB": 81.4, "EUR": 0.92, "CNY": 7.2 },
  "updated_at": "2026-06-03T12:00:00Z",
  "rub_source": "antilopay",
  "base_source": "cs2cap"
}
```

## Buying (orders)

Buy skins straight from your CSBoard balance. This is opt-in and intentionally locked down:

- **Enable trading first.** A normal key only reads. Turn on buying for your key at https://csboard.com/en/profile?tab=api (one toggle). A read key cannot spend — `POST /v1/orders` returns 403 `trading_not_enabled` until you enable it.
- **Balance only.** Buys debit your existing CSBoard balance. Top up on the site; there is no card/crypto over the API.
- **Steam linked.** Your account needs a linked Steam ID + trade URL (set on the site).
- **One price source, no surprises.** The price you are charged is the LIVE price at execution. `price_usd` in `GET /v1/listings` is authoritative (it equals what the buy charges). `GET /v1/prices` is an indicative grouped snapshot and can lag slightly. ALWAYS send `max_price_usd` — a ceiling enforced atomically inside the locked debit. If the live price moved above it, the order is rejected with `price_moved` (and the current total) instead of overcharging you. Re-read the listing and retry.
- **Idempotent.** Send an `Idempotency-Key` header (or `idempotency_key` in the body). A retried request replays the original order instead of buying twice.

### POST /v1/orders

Body:

```
{
  item_ids: string[],        // 1–10 ids from GET /v1/listings (unique). Don't mix external-market items with platform items.
  max_price_usd?: number,    // total ceiling (USD). Strongly recommended — your overcharge protection.
  idempotency_key?: string   // optional; or send the Idempotency-Key header.
}
```

Returns `201` with the created order:

```
{
  order_id, status, currency: "USD", charged_total_usd, item_count,
  items: [{ market_hash_name, price_usd, status }],
  delivery,            // "instant" | "pending" | null
  expected_minutes, created_at, updated_at
}
```

```bash
curl -X POST https://csboard.com/v1/orders \
  -H "Authorization: Bearer csb_pub_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f9c2b10-1a2b-4c3d-9e8f-0a1b2c3d4e5f" \
  -d '{ "item_ids": ["000012e8-1f4a-4c2b-9d3e-7a1b2c3d4e5f"], "max_price_usd": 268.00 }'
```

Recommended flow: read the item from `GET /v1/listings` → take its `price_usd` → POST with `max_price_usd` set to that (optionally + a small tolerance). If you get `409 price_moved`, re-read and retry with the new price.

### GET /v1/orders/:id

Status of one of your orders. Returns the same order shape as above. `404 order_not_found` if it isn't on your account.

```bash
curl https://csboard.com/v1/orders/clx123abc... \
  -H "Authorization: Bearer csb_pub_..."
```

### GET /v1/balance

Your CSBoard balance. Check it before buying.

Response: `{ currency: "USD", balance_usd, trading_enabled }`

```bash
curl https://csboard.com/v1/balance \
  -H "Authorization: Bearer csb_pub_..."
```

## Pagination

List endpoints return a `next_cursor`. Pass it back as `?cursor=` to fetch the next page. A `null` cursor means the end. Keyset cursors — stable at any depth, no offset drift.

```bash
curl "https://csboard.com/v1/listings?cursor=eyJpZCI6IjAwMDAxMmU4In0" \
  -H "Authorization: Bearer csb_pub_..."
```

## Errors

Every error returns JSON of the shape `{ "code": "...", "detail": "..." }`.

- 401 `missing_api_key` — no Authorization header sent.
- 401 `invalid_api_key` — key not found, revoked, or malformed.
- 429 `rate_limit_exceeded` — per-key request limit hit (see `Retry-After`).
- 429 `snapshot_rate_limited` — snapshot limited to 1/min per key.
- 429 `too_many_failed_auth` — >30 bad keys/min from your IP (5-min ban).

Buying (`POST /v1/orders`) adds:

- 400 `invalid_request` / `unsupported_item` / `steam_account_required` / `cannot_mix_sources` / `one_external_per_order`.
- 402 `insufficient_balance` (with `required_usd` / `current_usd`) — top up first.
- 402 `kyc_required` (with `kyc_url`) — verify identity on the site, then retry.
- 403 `trading_not_enabled` — enable buying for your key in your profile.
- 403 `account_restricted` — contact support.
- 409 `price_moved` (with `quoted_max_usd` / `current_total_usd`) — live price passed your ceiling; re-read and retry.
- 409 `item_unavailable` — one or more items sold out.
- 409 `idempotency_in_progress` — same Idempotency-Key still processing; retry shortly.
- 501 `not_implemented` — endpoint off by design (e.g. withdraw).

## MCP server

Use CSBoard from Claude Desktop / Cursor. Run `npx @csboard/mcp` with your `CSBOARD_API_KEY`. Tools: `search_listings`, `get_prices`, `list_cheapest`, `health`.

```json
{
  "mcpServers": {
    "csboard": {
      "command": "npx",
      "args": ["-y", "@csboard/mcp"],
      "env": { "CSBOARD_API_KEY": "csb_pub_..." }
    }
  }
}
```

## Not available via API

- POST /v1/withdraw — returns 501 by design. Withdrawals/payouts are managed on the site only (https://csboard.com/profile).
