How to Get CSFloat Listing Price History
Updated
cs2.sh's
POST /v1/prices/historywithsources: ["csfloat"]returns OHLC candles for CSFloat's lowest sell listing and highest buy order, from December 24, 2025, at5m,30m,1h, or1dintervals.
This is listing history, not sale history. It tracks how the visible order book moved, which is the right series for charts, spread analysis, and reprice detection. For what items actually sold for, POST /v1/archive/csfloat returns daily average sale prices back to 2022.
What cs2.sh provides for CSFloat history
| Property | Value |
|---|---|
| Endpoint | POST /v1/prices/history with sources: ["csfloat"] |
| Coverage | From December 24, 2025 |
| Intervals | 5m, 30m, 1h, 1d |
| Fields | ask and bid OHLC, ask_volume, sample_count |
| Not published | bid_volume |
| Items per request | 100 |
| Variants | Doppler, Gamma Doppler, and Case Hardened |
| Access | Requires a Scale or Enterprise API key |
Request the series
curl -X POST https://api.cs2.sh/v1/prices/history \
-H "Authorization: Bearer <<YOUR_API_KEY>>" \
-H "Accept-Encoding: gzip" --compressed \
-H "Content-Type: application/json" \
-d '{
"items": ["USP-S | Printstream (Factory New)"],
"start": "2026-07-20",
"end": "2026-07-23",
"sources": ["csfloat"],
"interval": "1h"
}'| Field | Type | Required | Description |
|---|---|---|---|
items |
string[] |
Yes | market_hash_name values, max 100. |
start |
string |
Yes | YYYY-MM-DD or RFC3339. |
end |
string |
No | Defaults to now. |
sources |
string[] |
No | Defaults to all sources. |
interval |
string |
No | Defaults to 5m. One of 5m, 30m, 1h, 1d. |
Each interval has a maximum range per request:
| Interval | Maximum request range |
|---|---|
5m |
14 days |
30m |
90 days |
1h |
365 days |
1d |
Unlimited |
These are per-request limits, not account limits. Six months of 30m candles is two requests joined together rather than an error.
The response shape
{
"start": "2026-07-20T00:00:00Z",
"end": "2026-07-23T00:00:00Z",
"interval": "1h",
"items": {
"USP-S | Printstream (Factory New)": {
"count": 72,
"data": [
{
"bucket": "2026-07-20T00:00:00Z",
"csfloat": {
"open_ask": 109.85,
"high_ask": 110.4,
"low_ask": 109.85,
"close_ask": 110.2,
"ask_volume": 227,
"open_bid": 105.0,
"close_bid": 105.5,
"sample_count": 11,
"open_time": "2026-07-20T00:04:12Z",
"close_time": "2026-07-20T00:57:40Z"
}
}
]
}
}
}| Field | Type | Description |
|---|---|---|
items.<name>.count |
integer |
Number of buckets with data. |
data[].bucket |
string (date-time) |
UTC-aligned interval boundary. |
open_ask / high_ask / low_ask / close_ask |
number |
Sell-listing OHLC for the bucket. |
open_bid / high_bid / low_bid / close_bid |
number |
Buy-order OHLC for the bucket. |
ask_volume |
integer |
Active sell listing count. |
sample_count |
integer |
Observations behind the candle. |
open_time / close_time |
string (date-time) |
First and last actual observations inside the bucket. |
Reading the data correctly
bucket and open_time are not the same thing. bucket is the aligned interval boundary; open_time and close_time are when observations actually happened inside it. On a thin item those can sit far from the boundary, which explains candles that look mistimed but are simply sparse.
sample_count is the evidence behind the candle. A bucket built from one observation has identical open, high, low, and close, and that is not a flat market, it is a single reading. Filter or annotate on sample_count before treating small moves as signal.
CSFloat has no bid_volume here, exactly as in current prices. Bid candles show where the highest buy order moved without showing how much stood behind it.
Per-source objects appear only when that source had data in the bucket, so a missing csfloat key is a gap rather than a zero. Valid items with no buckets in the requested range are omitted from items entirely, which is why you should read count rather than assuming every requested item comes back.
start is floored to the interval boundary and end is ceiled and exclusive, so the effective range in the response can be slightly wider than the one you asked for. Use the returned start and end when labelling a chart.
When items and variants fail
A 200 response can carry both items and errors[]. unknown_item and invalid_format cover naming, unsupported_variant covers a phase CSFloat does not carry, and unsupported_source covers an item with no CSFloat identity.
Request-level failures carry error, message, and a request_id. A 403 means history is not in your plan, a 400 covers malformed requests and more than 100 items, and 429 means the per-second limit was exceeded and should be retried with a bounded delay.
Worked example: the gap between listings and sales
Request 1d CSFloat history over a window that overlaps your CSFloat sale archive data. For each day, take close_ask from the candle and price from the archive row with the matching date.
The ratio close_ask / price - 1 is how far the cheapest listing sat above realised sales that day. Keep sample_count from the candle and volume from the archive row beside it, because a day with two sales and three observations cannot support the same conclusion as one with forty of each.
Full request and response reference: POST /v1/prices/history. Sale history: POST /v1/archive/csfloat. History endpoints need a Scale or Enterprise key.