How to Get Current Skinport Prices for CS2 Items
Updated
The
skinportsource in cs2.sh'sGETorPOST /v1/prices/latestreturns more than a single price. Alongsideaskandask_volumeit carries the distribution of active listings throughmax_ask,mean_ask, andmedian_ask, plus Skinport's own rolling sale statistics over 24 hours, 7 days, 30 days, and 90 days.
Most marketplace sources in the API give you the top of the book and an order count. Skinport gives you the shape of the whole listing set and a recent sales record beside it, which makes it the one source where you can see how far the cheapest listing sits from the typical one without reconstructing it yourself.
What cs2.sh provides for Skinport
| Property | Value |
|---|---|
| Endpoints | GET /v1/prices/latest (all items), POST /v1/prices/latest (up to 100 named items) |
| Order fields | ask, ask_volume |
| Distribution fields | max_ask, mean_ask, median_ask |
| Sale windows | 24h_history, 7d_history, 30d_history, 90d_history |
| Refresh | About every 5 minutes; variants about every 5 minutes |
| Variants | Doppler, Gamma Doppler, and Case Hardened |
| Currency | Always USD |
| Access | Available on all plans |
Skinport publishes no buy orders, so there is no bid or bid_volume on this source. Every figure describes the sell side or completed sales.
Request the item
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)"]}'"skinport": {
"updated_at": "2026-07-26T18:53:09.397Z",
"collected_at": "2026-07-26T18:53:15.672Z",
"ask": 115.95,
"ask_volume": 39,
"max_ask": 575.78,
"mean_ask": 181.61,
"median_ask": 156.61,
"24h_history": {
"price": 113.78,
"max_price": 116.48,
"mean_price": 115.13,
"median_price": 115.13,
"volume": 2
}
}| Field | Type | Description |
|---|---|---|
ask |
number | null |
Lowest active sell listing, USD. |
ask_volume |
integer | null |
Number of active sell listings. |
max_ask |
number | null |
Highest active sell listing. |
mean_ask |
number | null |
Average of active sell listings. |
median_ask |
number | null |
Median active sell listing. |
<window>_history |
object | null |
Rolling sale window. null when Skinport has no recent sales. |
updated_at / collected_at |
string (date-time) |
Skinport's update time and cs2.sh's collection time. |
Each of the four windows is the same object:
| Field | Type | Description |
|---|---|---|
price |
number |
Last sale price in the window, USD. |
max_price |
number |
Highest sale price in the window. |
mean_price |
number |
Average sale price in the window. |
median_price |
number |
Median sale price in the window. |
volume |
integer |
Number of sales in the window. |
Reading the data correctly
Keep the two families apart. ask, max_ask, mean_ask, and median_ask describe listings that have not sold. The _history windows describe sales that have. A gap between median_ask and 24h_history.median_price is the difference between what sellers are asking and what buyers recently paid, and it only means something if you label which is which.
mean_ask is pulled upward by outliers in a way median_ask is not. On an item where max_ask is several times ask, the mean is describing a handful of sticker-heavy or low-float copies rather than the ordinary market. Compare median_ask against ask to judge whether the cheapest listing is a genuine market price or an outlier at the bottom.
The windows overlap and are cumulative, not sequential: 7d_history includes the sales in 24h_history. Subtracting one from another does not give you a clean period, because these are Skinport's own rolling summaries rather than a series you can difference.
A window object is null when Skinport has no recent sales for the item, which is common on illiquid skins. That is a real market state and should propagate as absent rather than zero. volume inside a window that does exist is a genuine count for that period.
Base item source objects are dense, so skinport is present whenever any source has data for the item and unavailable fields are null. Variant source objects are sparse: skinport appears under a variant only when Skinport has data for that exact phase or tier.
When you need history instead
These windows are Skinport's rolling summaries at one moment. They are not a time series and cannot be charted by repeated polling without building your own storage. For a real Skinport series, POST /v1/prices/history with sources: ["skinport"] returns ask OHLC from December 24, 2025 at 5m, 30m, 1h, or 1d. Skinport is ask-only there too, so no bid candles exist.
When items are missing or fail
Item-level failures arrive in errors[] beside successful results in a 200 response: unknown_item for an unresolved name, invalid_format for a malformed value, and not_in_cache for a valid item absent from the current dataset.
Request-level failures carry error, message, and a request_id. Correct 400, 401, 403, and 404 before retrying; retry 429 and temporary 5xx with a bounded delay.
Worked example: is the cheapest listing actually cheap
Read ask, median_ask, and 24h_history.median_price from the same source object. If ask sits well below both, the item has a listing worth examining. If ask is close to median_ask but both sit above 24h_history.median_price, sellers are asking more than recent buyers paid.
Check ask_volume before acting on either reading: with two active listings, median_ask is describing almost nothing. Check 24h_history.volume the same way, and fall back to 7d_history or 30d_history when the day is too thin to carry a conclusion. Record collected_at with whatever you compute.
Full field reference: GET /v1/prices/latest. Skinport window schema: SkinportPriceWindow. Historical coverage: data coverage.