BUFF sale history is now available - POST /v1/archive/buff returns sale prices and daily total supply since September 2024.

How to Get Current Skinport Prices for CS2 Items

Updated

Endpoints used: GET /v1/prices/latest & POST /v1/prices/latest

Related pages: Skinport price API

The skinport source in cs2.sh's GET or POST /v1/prices/latest returns more than a single price. Alongside ask and ask_volume it carries the distribution of active listings through max_ask, mean_ask, and median_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#

bash
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)"]}'
json
"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.