How to Get Current CS2 Item Prices
Updated
cs2.sh's
GET /v1/prices/latestreturns the current price of every tracked CS2 item across BUFF, Youpin, CSFloat, Skinport, Steam, and C5Game in one response.POST /v1/prices/latestreturns the same shape for up to 100 named items. Both are available on all plans.
Most CS2 price problems are not really price problems. They are identity and freshness problems: the same skin is listed under different identifiers on six marketplaces, each updates on its own schedule, and a number without a timestamp cannot be compared with anything. This endpoint resolves all six under one market_hash_name and stamps every source with its own collection time.
What cs2.sh provides for current prices
| Property | Value |
|---|---|
| Endpoints | GET /v1/prices/latest (all items), POST /v1/prices/latest (up to 100 named items) |
| Marketplaces | BUFF, Youpin, CSFloat, Skinport, Steam, C5Game |
| Refresh | Most prices about every 5 minutes, depending on the marketplace |
| Variants | Doppler, Gamma Doppler, and Case Hardened, under variants |
| Currency | Always USD |
| Access | Available on all plans |
Two field names carry most of the meaning. ask is the current lowest sell listing. bid is the current highest generic buy order. ask_volume and bid_volume are the number of active listings or buy orders behind them.
Not every marketplace publishes all four:
| Source | Fields |
|---|---|
buff |
ask, bid, ask_volume, bid_volume |
youpin |
ask, bid, ask_volume, bid_volume |
csfloat |
ask, bid, ask_volume |
skinport |
ask, ask_volume, max_ask, mean_ask, median_ask, 24h_history, 7d_history, 30d_history, 90d_history |
steam |
ask, bid, ask_volume, bid_volume |
c5game |
ask, bid, ask_volume |
CSFloat and C5Game report no bid_volume, so a top buy order on those two arrives without depth behind it. Skinport is ask-only for orders but adds distribution fields the others do not have: max_ask, mean_ask, and median_ask describe the spread of active listings, and the rolling 24h_history through 90d_history windows carry Skinport's own sale statistics.
Request specific items
curl -X POST https://api.cs2.sh/v1/prices/latest \
-H "Authorization: Bearer <<YOUR_API_KEY>>" \
-H "Accept-Encoding: gzip" --compressed \
-H "Content-Type: application/json" \
-d '{
"items": [
"USP-S | Printstream (Factory New)"
]
}'| Field | Type | Required | Description |
|---|---|---|---|
items |
string[] |
Yes | market_hash_name values, max 100. |
GET /v1/prices/latest takes no body and returns every tracked item. Use it to build or refresh a full local price table; use the POST form when you already know which items you need.
The response shape
{
"response_time": "2026-07-26T18:54:04.041256216Z",
"currency": "USD",
"items": {
"USP-S | Printstream (Factory New)": {
"market_hash_name": "USP-S | Printstream (Factory New)",
"buff": {
"updated_at": "2026-07-26T18:50:53Z",
"collected_at": "2026-07-26T18:53:10.67Z",
"ask": 109.72,
"ask_volume": 463,
"bid": 106.17,
"bid_volume": 41
},
"csfloat": {
"updated_at": "2026-07-26T18:53:05.094Z",
"collected_at": "2026-07-26T18:53:05.134Z",
"ask": 107.99,
"ask_volume": 227,
"bid": 105
}
}
}
}| Field | Type | Description |
|---|---|---|
items.<name>.<source> |
object |
Prices and order counts on that marketplace. |
<source>.updated_at |
string (date-time) |
When the marketplace last updated the price. |
<source>.collected_at |
string (date-time) |
When cs2.sh collected it. |
items.<name>.variants |
object |
The same per-source shape, per variant. |
Reading the data correctly
updated_at and collected_at answer different questions and both matter. updated_at is the marketplace's own timestamp; collected_at is when cs2.sh read it. A price can be freshly collected and still stale at source, which is what a wide gap between the two indicates. Reject on whichever bound your use case cares about, and keep the timestamp beside any number you display.
Base item source objects are dense: once any source has data for the item, all six keys are present and unavailable fields are null. Variant source objects are sparse: they appear only where that source actually has variant data. Code that iterates variants must handle a missing source key, while code that iterates base items must handle a null value. Treating those two cases identically is the most common integration bug against this endpoint.
Comparing across marketplaces means comparing like with like. An ask on one marketplace against a bid on another is not a spread, it is two different questions. Steam values settle to Steam Wallet funds rather than cash, so a Steam number placed beside BUFF or CSFloat needs an explicit conversion assumption recorded separately from the raw value. And because each source refreshes on its own schedule, two prices in the same response were not necessarily observed at the same moment.
When items are missing or fail
POST endpoints validate each requested item independently, so a 200 response can carry both items and an errors[] array. An entry in errors applies only to that item and does not invalidate the rest.
| Code | Meaning |
|---|---|
unknown_item |
The name does not match a known item. |
invalid_format |
The submitted item value is not valid. |
not_in_cache |
The item is valid but unavailable in the current dataset. |
Request-level failures use a shared object carrying error, message, and a request_id to quote when contacting support. Correct 400, 401, 403, 404, and 405 before retrying; retry 429 and temporary 5xx with a bounded delay.
Variants and the base item
An item with Doppler, Gamma Doppler, or Case Hardened prices carries a variants object. Phase 1 through Phase 4, Ruby, Sapphire, and Black Pearl are separate markets that trade at materially different levels. A base Doppler price is not a substitute for a missing phase.
Steam supports no variants at all, because the Steam Community Market does not distinguish a phase from its base item. BUFF, Youpin, CSFloat, Skinport, and C5Game support current Doppler and Gamma Doppler prices; Case Hardened is supported on BUFF, Skinport, and C5Game.
Worked example: the best price to buy at right now
Request the item, then read ask from each source object where it is not null, discarding any whose collected_at is older than your tolerance. The lowest remaining ask is the cheapest active sell listing across covered marketplaces.
Keep the source name and collected_at attached to that figure. Fees, regional availability, and transfer restrictions live outside the API, so the lowest ask is a candidate rather than a settled decision. Pair it with ask_volume to see whether the price represents one listing or a deep book.
Full request, response, and field reference: GET /v1/prices/latest. Refresh rates for every endpoint: data coverage. Getting started: quickstart.