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

How to Get CS2 Doppler Phase Price Data

Doppler phases are separate markets. A Ruby Karambit can trade at several times its base item, and the base price is never a substitute for a missing phase. cs2.sh returns each phase under a variants object with a stable version code you can key on.

A Factory New Karambit Doppler is not one product. Phase 1 through Phase 4 are different patterns at different prices, and Ruby, Sapphire, and Black Pearl are different again. Most CS2 price sources flatten all of that into a single number, which is why phase-level pricing is one of the harder things to get right.

What cs2.sh provides for Doppler variants#

Property Value
Identity GET /v1/schema, available on all plans
Current prices GET / POST /v1/prices/latest, all plans
Price history POST /v1/prices/history, from December 24, 2025, Scale or Enterprise
Completed sales POST /v1/archive/csfloat, from 2022, Scale or Enterprise
Current price support BUFF, Youpin, CSFloat, Skinport, C5Game
Not supported Steam, on any endpoint
Refresh BUFF ~3-5 min, Skinport and C5Game ~5 min, Youpin ~5-15 min, CSFloat ~10-15 min

Steam supports no variants anywhere, because the Steam Community Market does not distinguish a phase from its base item.

Use the stable version code#

Every variant object carries four identity fields:

json
"variants": {
  "Ruby": {
    "market_hash_name": "★ Karambit | Doppler (Factory New)",
    "name": "★ Karambit | Doppler (Factory New) | Ruby",
    "display_name": "Ruby",
    "version": "ruby",
    "buff": { "ask": 7671.41, "bid": 7287.47 },
    "csfloat": { "ask": 7590, "bid": 7220 }
  }
}
Field Meaning
market_hash_name The base item's market hash name.
name The full cs2.sh variant name.
display_name Human-readable label.
version Stable variant code.

Key your code on version, not on display_name. Display labels are for people; the codes are the contract:

Version code Family Label
p1 to p4 Doppler / Gamma Doppler Phase 1 to Phase 4
ruby Doppler Ruby
sapphire Doppler Sapphire
blackpearl Doppler Black Pearl
emerald Gamma Doppler Emerald

Note that p1 through p4 are shared between Doppler and Gamma Doppler. The family comes from the base item, not the code, so version alone does not tell you which one you are holding.

Request a phase price#

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": ["★ Karambit | Doppler (Factory New)"]}'

Request the base item. Phases arrive nested under variants on that item rather than as separate top-level names.

For history, the same nesting applies to POST /v1/prices/history, where each variant carries the full bucketed OHLC shape, to POST /v1/archive/csfloat, where each variant carries its own daily average sale price and sale count, and to POST /v1/archive/buff, where each phase carries its own sale samples and supply.

Reading the data correctly#

Variant source objects are sparse. Unlike base items, where all six sources are present with null in unsupported fields, a variant only carries the sources that actually have data for that exact phase. Code that iterates variants must handle a missing source key rather than a null value, and that difference is the most common integration bug against phase-level data.

Never fall back to the base item. A missing Phase 3 price is missing. Substituting the base Doppler price understates a Ruby by an order of magnitude and overstates a Phase 4 in the other direction.

Sell listings and buy orders are not completed sales. ask and bid describe offers; POST /v1/archive/csfloat describes transactions. On thin phases the difference is large, because a phase can go days without a sale while listings sit unchanged.

Phase prices do not include individual float values, paint seeds, or stickers. Those attributes explain much of the variation inside one phase and are not in the price response, which is why a daily average on a low-volume phase can look erratic.

When variants are missing or fail#

A variant absent from variants has no data on any source, while a source key absent inside a variant means that one marketplace has no data for that phase. Neither is an error and neither should fall back to the base item.

Item-level failures arrive in errors[] beside successful results. unsupported_variant means the requested phase is not supported by that dataset, which is always the case for Steam. unsupported_source means the item has no identity on the requested marketplace.

Compare two phases correctly#

To measure a phase premium, divide one variant's price by another's on the same date and from the same source, then show both sale counts beside the ratio. A one-sale Ruby average and a forty-sale Phase 1 average do not carry equal weight, and a ratio that hides that is a number without evidence.

Align asks with asks and bids with bids across marketplaces. For history, use identical intervals and keep the real open_time and close_time rather than assuming the bucket boundary.

Worked example: current phase spread across marketplaces#

Request the base item, then for each entry in variants, read ask from every source key present. You now have the cheapest active listing per phase per marketplace, without ever having guessed a name.

Take the lowest ask per phase and compare it against the same phase's most recent CSFloat archive price to see whether listings sit above or below realised sales. Keep collected_at from each source object: CSFloat variants refresh about every 10-15 minutes while BUFF variants refresh about every 3-5, so two numbers in one response can be ten minutes apart.

Full references: variants and version codes, GET /v1/prices/latest, POST /v1/prices/history, POST /v1/archive/csfloat. Variant coverage per marketplace: data coverage.