Market Data
GET /v1/prices/snapshot.ndjson.gz — Full Price Snapshot
Download the full CSBoard price catalog as a gzipped NDJSON file. One PriceRow per line. Designed for bulk ingestion with ETag-based conditional fetching.
GET
/
prices
/
snapshot.ndjson.gz
Full price-list snapshot (gzipped NDJSON)
curl --request GET \
--url https://csboard.com/v1/prices/snapshot.ndjson.gz \
--header 'Authorization: Bearer <token>'import requests
url = "https://csboard.com/v1/prices/snapshot.ndjson.gz"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://csboard.com/v1/prices/snapshot.ndjson.gz', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://csboard.com/v1/prices/snapshot.ndjson.gz",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://csboard.com/v1/prices/snapshot.ndjson.gz"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://csboard.com/v1/prices/snapshot.ndjson.gz")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://csboard.com/v1/prices/snapshot.ndjson.gz")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body"<string>"{
"code": "missing_api_key",
"detail": "Provide your API key via `Authorization: Bearer csb_pub_…`. Generate one at https://csboard.com/profile?tab=api"
}{
"code": "rate_limit_exceeded",
"detail": "Rate limit of 100 requests/min exceeded."
}The snapshot endpoint serves the complete CSBoard price list as a single gzipped NDJSON file. Every decompressed line is one
Example decompressed output:
A
PriceRow JSON object — the same schema returned by GET /v1/prices. This is the intended path for full-catalog consumers such as comparison sites, arbitrage bots, or data pipelines that need a complete local copy of the price list. For targeted queries against a subset of items, use GET /v1/prices instead.
Authentication required. Send your key as Authorization: Bearer csb_pub_....
Rate limit: 1 request per minute, separate from the general 100 requests/min limit. Plan your polling interval accordingly.
Request headers
string
Pass the
ETag value from a previous snapshot response to make a conditional request. If the snapshot has not changed since that ETag, the server returns 304 Not Modified with no body, saving bandwidth and avoiding a fresh download.Response headers
| Header | Description |
|---|---|
ETag | Opaque version string identifying this snapshot. Store it and send back as If-None-Match on the next request. |
Content-Encoding | gzip — the body is always gzip-compressed. |
Response body
A gzip-compressed stream. After decompression, each newline-delimited line is a valid JSON object conforming to thePriceRow schema:
| Field | Type | Description |
|---|---|---|
market_hash_name | string | Steam market hash name. |
wear | string | null | Wear bucket, or null. |
doppler_phase | string | null | Doppler phase, or null. |
min_price_usd | number | Cheapest current ask in USD. |
qty | integer | Number of listings in this group. |
Example: download and inspect
curl https://csboard.com/v1/prices/snapshot.ndjson.gz \
-H "Authorization: Bearer csb_pub_..." \
--output snapshot.ndjson.gz \
&& gunzip -c snapshot.ndjson.gz | head -5
{"market_hash_name":"AK-47 | Redline (Field-Tested)","wear":"Field-Tested","doppler_phase":null,"min_price_usd":11.92,"qty":73}
{"market_hash_name":"AWP | Asiimov (Field-Tested)","wear":"Field-Tested","doppler_phase":null,"min_price_usd":54.20,"qty":12}
{"market_hash_name":"Karambit | Doppler (Factory New)","wear":"Factory New","doppler_phase":"Ruby","min_price_usd":1240.00,"qty":1}
Example: conditional request with ETag
On the first download you receive anETag header. Pass it back on subsequent requests to avoid re-downloading an unchanged snapshot:
# First request — save ETag from response headers
curl https://csboard.com/v1/prices/snapshot.ndjson.gz \
-H "Authorization: Bearer csb_pub_..." \
--dump-header headers.txt \
--output snapshot.ndjson.gz
# Subsequent request — conditional fetch
curl https://csboard.com/v1/prices/snapshot.ndjson.gz \
-H "Authorization: Bearer csb_pub_..." \
-H "If-None-Match: \"etag-value\"" \
--output snapshot.ndjson.gz
304 Not Modified response means the snapshot is identical to the one you already have — no new download needed.
Error codes
| HTTP status | Code | Meaning |
|---|---|---|
| 304 | (no body) | Snapshot unchanged since the supplied If-None-Match ETag. |
| 401 | missing_api_key, invalid_api_key | Missing or invalid API key. |
| 429 | snapshot_rate_limited | Over the 1 request/min snapshot-specific rate limit. Wait before retrying. |
Always store the
ETag from each successful download and send it back as If-None-Match on the next request. A 304 response costs nothing against your rate limit quota and keeps your local copy up to date without unnecessary re-downloads.This endpoint is designed for full-catalog ingestion. If you only need prices for a specific item or a filtered subset, use
GET /v1/prices — it supports search, category, and wear filters and does not count against the snapshot rate limit.Authorizations
Send your key as a Bearer token on every request: Authorization: Bearer csb_pub_.... Generate keys in your CSBoard profile.
Headers
Conditional request. Pass the ETag from a previous snapshot to receive 304 if unchanged.
Response
Gzipped NDJSON stream. Each decompressed line is one PriceRow JSON object. Sets an ETag header.
The response is of type file.
⌘I
Full price-list snapshot (gzipped NDJSON)
curl --request GET \
--url https://csboard.com/v1/prices/snapshot.ndjson.gz \
--header 'Authorization: Bearer <token>'import requests
url = "https://csboard.com/v1/prices/snapshot.ndjson.gz"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://csboard.com/v1/prices/snapshot.ndjson.gz', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://csboard.com/v1/prices/snapshot.ndjson.gz",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://csboard.com/v1/prices/snapshot.ndjson.gz"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://csboard.com/v1/prices/snapshot.ndjson.gz")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://csboard.com/v1/prices/snapshot.ndjson.gz")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body"<string>"{
"code": "missing_api_key",
"detail": "Provide your API key via `Authorization: Bearer csb_pub_…`. Generate one at https://csboard.com/profile?tab=api"
}{
"code": "rate_limit_exceeded",
"detail": "Rate limit of 100 requests/min exceeded."
}