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

How to Get Steam Community Market Sale History

Updated

Endpoints used: POST /v1/archive/steam & POST /v1/prices/history

Related pages: Steam price API & CS2 price history API

cs2.sh's POST /v1/archive/steam returns the same sale data that Steam draws in the price graph on a Community Market item page: a median sale price and a purchase count per bucket, daily from April 26, 2013 and hourly from May 9, 2026.

Steam publishes a sale graph on every Community Market item page, but it gives you no way to query it. There is no documented endpoint, the page-embedded series is throttled aggressively, and it arrives as a rendered graph payload rather than a stable schema. cs2.sh collects that native series for every tracked regular CS2 item and serves it as JSON.

What cs2.sh provides for Steam sales#

Property Value
Endpoint POST /v1/archive/steam
Coverage Daily (1d) from April 26, 2013; hourly (1h) from May 9, 2026
Intervals 1h, 1d (no maximum request range on either)
Refresh About 1-4x per day
Items per request 100
Variants Not supported
Currency Always USD
Access Requires a Scale or Enterprise API key

Two fields come back per bucket. price is Steam's median sale price for that bucket, and volume is the number of purchases in it. This is Steam's own statistic, not a cs2.sh calculation, which is what makes the series comparable with what a person sees on the item page.

Variants are unsupported here because the Steam Community Market does not distinguish a Doppler phase from its base item. A request naming ★ Karambit | Doppler (Factory New) - Phase 2 returns unsupported_variant rather than silently falling back to the base item.

Request the series#

bash
curl -X POST https://api.cs2.sh/v1/archive/steam \
  -H "Authorization: Bearer <<YOUR_API_KEY>>" \
  -H "Accept-Encoding: gzip" --compressed \
  -H "Content-Type: application/json" \
  -d '{
  "items": [
    "USP-S | Printstream (Factory New)"
  ],
  "start": "2025-01-01",
  "end": "2025-02-01",
  "interval": "1d"
}'
Field Type Required Description
items string[] Yes Regular market_hash_name values, max 100. Variants are not supported.
start string Yes YYYY-MM-DD or RFC3339, inclusive.
end string No YYYY-MM-DD or RFC3339, exclusive. Defaults to now.
interval string Yes 1h or 1d. The native Steam bucket interval.

Because neither interval has a maximum request range, a single request can pull an item's entire history back to 2013. Accept-Encoding: gzip matters on those ranges: thirteen years of daily buckets across 100 items is a large response.

The response shape#

json
{
  "response_time": "2026-07-26T18:54:20.110090345Z",
  "currency": "USD",
  "start": "2025-01-01T00:00:00Z",
  "end": "2025-02-01T00:00:00Z",
  "interval": "1d",
  "items": {
    "USP-S | Printstream (Factory New)": {
      "market_hash_name": "USP-S | Printstream (Factory New)",
      "count": 31,
      "data": [
        {
          "bucket": "2025-01-01T00:00:00Z",
          "price": 150.23,
          "volume": 7
        }
      ]
    }
  }
}
Field Type Description
items.<name>.count integer Number of buckets with data.
items.<name>.data[] array Buckets, sorted ascending by bucket.
data[].bucket string (date-time) Native Steam bucket start.
data[].price number | null Steam median sale price, USD.
data[].volume integer | null Steam purchase count.
start / end string (date-time) Normalized UTC range actually queried.
errors ItemError[] Per-item failures returned alongside successful results.

bucket is present on every bucket, but price and volume are independently nullable: Steam's native bucket sometimes omits one. Check each field rather than assuming a returned bucket is complete.

Reading the data correctly#

The price field is a median, and that has consequences. A median is not the price of any particular sale, so multiplying price by volume gives an approximation of traded value rather than exact gross value. It is also not comparable like-for-like with POST /v1/archive/csfloat, where price is the arithmetic average of that day's sales. Label the statistic wherever both appear.

Steam prices settle to Steam Wallet funds rather than cash. If a chart puts Steam beside a cash marketplace such as BUFF or CSFloat, keep the raw Steam value and store any conversion assumption separately.

Sale history and listing history answer different questions. This endpoint reports what items sold for. POST /v1/prices/history with sources: ["steam"] reports how the active ask (the lowest sell listing) and bid (the highest buy order) moved. Joining the two on bucket gives a seller premium (ask close against median sale price) or buyer pressure (bid close against the same median), and sample_count alongside volume tells you how much evidence sits behind each side.

A missing bucket is a gap, not a zero-purchase bucket. Forward-filling one before summing volume inflates activity in exactly the quiet periods where the error matters most.

When items are missing or fail#

Requests return partial results rather than failing wholesale. A 200 response can carry both items and an errors[] array.

Code Meaning
not_in_archive A valid item has no Steam archive rows.
unsupported_variant A variant name was requested; Steam does not support variants.
unknown_item The market_hash_name does not resolve.
404 not_found None of the requested valid items have any Steam archive rows.

Treat not_in_archive as a coverage fact about that item, not a request error. Retrying it produces the same result.

Worked example: a thirteen-year price chart#

To chart one item's full Steam history, request interval: "1d" with start at 2013-04-26 and no end. Read count to size the series, then iterate data[], skipping buckets where price is null and recording gaps rather than interpolating them. For a volume panel beneath the price line, sum volume only across returned buckets inside each period you label.

To narrow to an event, switch to interval: "1h" for any window after May 9, 2026 and request the hours around it. Requesting 1h for an earlier date does not create intraday detail that Steam never published.

Full request, response, and error reference: POST /v1/archive/steam. Coverage and refresh rates for every endpoint: data coverage. Archive endpoints need a Scale or Enterprise key.