How to Get CS2 Doppler Phase Price Data
Updated
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
variantsobject with a stableversioncode 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:
"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
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.