# How to get CS2 Doppler phase prices, from Phase 1 to Emerald

> Price CS2 Doppler and Gamma Doppler by phase: Phase 1 to 4, Ruby, Sapphire, Black Pearl, and Emerald, with live buckets and history. Runnable code.

*Floats & attributes · Intermediate · Updated 2026-09-25*

Doppler and Gamma Doppler knives are the clearest case where one Steam market name hides several very different items. A `★ Karambit | Doppler (Factory New)` can be any of four phases or one of three gems, and those trade at very different prices, yet the market hash name is identical for all of them. A price quoted for the plain name is a blend, and it is wrong for every specific knife you might hold.

SkinPricer prices each phase and gem as its own item, so you can ask for exactly the variant you care about. This guide shows how to list an item's phases, get a cross-market price for each, break a phase down by float band, and pull a band's history.

## How phases are identified

Every phase and gem is a separate catalog item whose name is the base name plus a suffix. The plain base name still exists and represents the blended market; use it only when you really mean "any phase".

| Finish | Variant item names |
| --- | --- |
| Doppler | `<base> - Phase 1` to `<base> - Phase 4`, plus the gems `<base> - Ruby`, `<base> - Sapphire`, and `<base> - Black Pearl` |
| Gamma Doppler | `<base> - Phase 1` to `<base> - Phase 4`, plus the gem `<base> - Emerald` |

For example, `★ Karambit | Doppler (Factory New) - Phase 2` and `★ Karambit | Gamma Doppler (Factory New) - Emerald`. Not every knife and wear has every gem, so do not build the names by hand; list them from the catalog as shown next.

## Step 1: list the phases of an item

Look up the base item in the item schema. Its record carries a `variants` array with one entry per phase or gem: the variant's exact `marketHashName`, its `family` (`doppler` or `gamma_doppler`), its display `name`, and a numeric `phase` for Phase 1 to 4. The schema lookup is available from the Developer plan up. It is not wrapped by the published SDK yet, so the TypeScript sample calls it with `fetch`.

**curl**

```bash
export SKINPRICER_API_KEY="sp_live_•••"   # from your account's API keys page

curl -s "https://pricing.skinpricer.com/v1/schema/items/%E2%98%85%20Karambit%20%7C%20Doppler%20(Factory%20New)" \
  -H "Authorization: ApiKey $SKINPRICER_API_KEY"
```

**Node (fetch)**

```ts
interface SchemaVariant {
  marketHashName: string;
  family: "doppler" | "gamma_doppler";
  name: string;
  phase?: number;
}

const base = "★ Karambit | Doppler (Factory New)";
const res = await fetch(
  `https://pricing.skinpricer.com/v1/schema/items/${encodeURIComponent(base)}`,
  { headers: { Authorization: `ApiKey ${process.env.SKINPRICER_API_KEY}` } },
);
if (!res.ok) throw new Error(`schema lookup failed: ${res.status}`);

const { item } = (await res.json()) as { item: { variants?: SchemaVariant[] } };
const variants = item.variants ?? [];
console.log(variants.map((v) => v.name).join(", "));
```

**Python**

```python
import os
from urllib.parse import quote

import requests

base = "★ Karambit | Doppler (Factory New)"
res = requests.get(
    f"https://pricing.skinpricer.com/v1/schema/items/{quote(base, safe='')}",
    headers={"Authorization": f"ApiKey {os.environ['SKINPRICER_API_KEY']}"},
    timeout=10,
)
res.raise_for_status()
variants = res.json()["item"].get("variants") or []
print([v["name"] for v in variants])
```

**Response 200** (`GET /v1/schema/items/:idOrName`)

```json
{
  "schemaVersion": 1783069455007,
  "item": {
    "id": "cmlofcu700pem01yop1965ua2",
    "marketHashName": "★ Karambit | Doppler (Factory New)",
    "slug": "karambit-doppler-factory-new",
    "category": "skin",
    "baseName": "★ Karambit | Doppler",
    "weapon": "Karambit",
    "finish": "Doppler",
    "rarity": "covert",
    "wear": "Factory New",
    "wears": ["Factory New", "Minimal Wear"],
    "stattrak": false,
    "souvenir": false,
    "hasStattrak": true,
    "hasSouvenir": false,
    "variants": [
      {
        "marketHashName": "★ Karambit | Doppler (Factory New) - Phase 1",
        "family": "doppler",
        "name": "Phase 1",
        "phase": 1,
        "image": "https://community.akamai.steamstatic.com/economy/image/..."
      },
      {
        "marketHashName": "★ Karambit | Doppler (Factory New) - Phase 2",
        "family": "doppler",
        "name": "Phase 2",
        "phase": 2,
        "image": "https://community.akamai.steamstatic.com/economy/image/..."
      },
      {
        "marketHashName": "★ Karambit | Doppler (Factory New) - Phase 3",
        "family": "doppler",
        "name": "Phase 3",
        "phase": 3,
        "image": "https://community.akamai.steamstatic.com/economy/image/..."
      },
      {
        "marketHashName": "★ Karambit | Doppler (Factory New) - Phase 4",
        "family": "doppler",
        "name": "Phase 4",
        "phase": 4,
        "image": "https://community.akamai.steamstatic.com/economy/image/..."
      },
      {
        "marketHashName": "★ Karambit | Doppler (Factory New) - Black Pearl",
        "family": "doppler",
        "name": "Black Pearl",
        "image": "https://community.akamai.steamstatic.com/economy/image/..."
      },
      {
        "marketHashName": "★ Karambit | Doppler (Factory New) - Ruby",
        "family": "doppler",
        "name": "Ruby",
        "image": "https://community.akamai.steamstatic.com/economy/image/..."
      },
      {
        "marketHashName": "★ Karambit | Doppler (Factory New) - Sapphire",
        "family": "doppler",
        "name": "Sapphire",
        "image": "https://community.akamai.steamstatic.com/economy/image/..."
      }
    ],
    "image": "https://community.akamai.steamstatic.com/economy/image/...",
    "ids": { "buff163": "42998", "marketcsgo": "★ Karambit | Doppler (Factory New)" }
  },
  "registries": {
    "rarities": [{ "key": "covert", "name": "Covert", "tier": 6, "color": "#eb4b4b" }],
    "collections": {},
    "containers": {}
  }
}
```

*The documented schema record for the Factory New Doppler Karambit: four phases and three gems, each with its own market hash name.*

## Step 2: get a cross-market price for every phase

Each variant name works anywhere the API takes a market hash name. The [NBBO](/api-docs/nbbo) for a phase returns the best ask and best bid across every venue that lists that phase separately, with the usual freshness and confidence signals. Venues that only list the blended item simply do not contribute a quote.

```ts
// npm i @skinpricer/sdk
import { SkinpricerClient, formatUsd } from "@skinpricer/sdk";

const client = new SkinpricerClient({
  apiKey: process.env.SKINPRICER_API_KEY!,
  authScheme: "ApiKey",
});

for (const variant of variants) {
  const q = await client.nbbo.get({ marketHashName: variant.marketHashName });
  const ask = q.bestAsk ? `${formatUsd(q.bestAsk.price)} on ${q.bestAsk.market}` : "no asks";
  console.log(variant.name.padEnd(12), ask, `(${q.freshMarketCount} fresh venues)`);
}
```

*One NBBO call per variant. Seven variants cost seven requests, so cache the results for your polling interval.*

## Step 3: break a phase down by float

Within one phase, float still moves the price, and the lowest bands usually carry a premium. The [attribute price endpoint](/api-docs/floats) returns BUFF163's phase buckets for a variant: a phase-wide bucket that covers every float, and one bucket per float band within the phase. Both are tagged with the phase in `dimensions.variant`. Request `attributes=float,tag`; the phase-wide bucket is a pure tag bucket and is omitted by the default float-only filter.

**curl**

```bash
curl -s "https://pricing.skinpricer.com/v1/attribute-prices/latest?marketHashName=%E2%98%85%20Karambit%20%7C%20Doppler%20(Factory%20New)%20-%20Phase%202&attributes=float,tag" \
  -H "Authorization: ApiKey $SKINPRICER_API_KEY"
```

**Node (SDK)**

```ts
const phase = await client.attributePrices.latest({
  marketHashName: "★ Karambit | Doppler (Factory New) - Phase 2",
  attributes: ["float", "tag"],
});

for (const item of phase.items) {
  for (const bucket of item.buckets) {
    const band = bucket.dimensions.float;
    const label = band ? `float ${band.min} to ${band.max}` : "all floats";
    const ask = bucket.askCents === null ? "no asks" : formatUsd(bucket.askCents);
    console.log(item.market, bucket.dimensions.variant, label, ask);
  }
}
```

**Response 200** (`GET /v1/attribute-prices/latest`)

```json
{
  "bucketSchemaVersion": 1,
  "markets": ["buff163", "steamcommunity", "marketcsgo", "csfloat", "dmarket"],
  "currency": "USD",
  "asOf": "2026-06-23T09:18:45.864Z",
  "items": [
    {
      "canonicalItemId": "cmlofa7dh08ww01yo9lrpej3e",
      "marketHashName": "★ Karambit | Doppler (Factory New) - Phase 2",
      "market": "buff163",
      "buckets": [
        {
          "bucketId": "buff163:cmlofa7dh08ww01yo9lrpej3e:tag:446954:float:0-0.01",
          "bucketKey": "tag:446954:float:0-0.01",
          "bucketType": "attribute",
          "attributeType": "tag",
          "attributeTypes": ["tag", "float"],
          "dimensions": {
            "variant": "Phase2",
            "float": { "min": 0, "max": 0.01, "minInclusive": true, "maxInclusive": false },
            "fade": null,
            "pattern": null,
            "paintSeed": null
          },
          "sourceItemId": "44102",
          "sourceBucketId": "buff163:44102:tag446954:f0-0.01",
          "askCents": 197795,
          "avgAskCents": 201340,
          "medianAskCents": 199500,
          "bidCents": 179787,
          "askListingCount": 82,
          "bidOrderCount": null,
          "sourceUpdatedAt": "2026-06-23T09:10:00.000Z",
          "collectedAt": "2026-06-23T09:11:35.446Z"
        },
        {
          "bucketId": "buff163:cmlofa7dh08ww01yo9lrpej3e:tag:446954:float:0.01-0.02",
          "bucketKey": "tag:446954:float:0.01-0.02",
          "bucketType": "attribute",
          "attributeType": "tag",
          "attributeTypes": ["tag", "float"],
          "dimensions": {
            "variant": "Phase2",
            "float": { "min": 0.01, "max": 0.02, "minInclusive": true, "maxInclusive": false },
            "fade": null,
            "pattern": null,
            "paintSeed": null
          },
          "sourceItemId": "44102",
          "sourceBucketId": "buff163:44102:tag446954:f0.01-0.02",
          "askCents": 189676,
          "avgAskCents": 191220,
          "medianAskCents": 190100,
          "bidCents": 179344,
          "askListingCount": 66,
          "bidOrderCount": null,
          "sourceUpdatedAt": "2026-06-23T09:10:00.000Z",
          "collectedAt": "2026-06-23T09:11:35.446Z"
        }
      ]
    }
  ],
  "nextCursor": null,
  "sourceGaps": []
}
```

*Two float bands of the Phase 2 Karambit on BUFF163. `attributeTypes` shows each bucket bands on both the phase tag and a float range.*

## Step 4: track a phase band over time

Every bucket has a stable `bucketId`. Pass it to [attribute price history](/api-docs/attribute-history) to get that band's open, high, low, and close asks per interval, plus the closing bid. History requires the Pro plan. Daily spacing over a quarter is a good default for charts; switch to `1h` or `10m` for recent, fast-moving windows.

```ts
const history = await client.attributePrices.history({
  bucketId: "buff163:cmlofa7dh08ww01yo9lrpej3e:tag:446954:float:0-0.01",
  granularity: "1d",
  from: new Date(Date.now() - 90 * 24 * 60 * 60 * 1000),
});

for (const point of history.items[0]?.buckets[0]?.points ?? []) {
  console.log(point.bucketStart.slice(0, 10), point.closeAskCents, point.closeBidCents);
}
```

## Pitfalls that cost money

- Never value a specific knife from the plain base name. The blended price mixes cheap and expensive phases and fits none of them.
- `dimensions.variant` uses the source market's own label (for example `Phase2` or `Emerald`). Treat the variant item name from Step 1 as the authoritative label and the bucket tag as confirmation.
- Gems are thin. A Ruby or Emerald may have only a handful of listings across all venues, so check `isStale`, `freshMarketCount`, and `askListingCount` before trusting a single quote.
- `null` bids are common on gem bands. No buy order is not the same as a zero bid.
- On knives, a listing's `paintIndex` identifies the phase when the market exposes it: Doppler Ruby is 415, Sapphire 416, Black Pearl 417, and Phases 1 to 4 are 418 to 421; Gamma Doppler Emerald is 568 and Phases 1 to 4 are 569 to 572.

> **Phase buckets come from BUFF163:** Phase-by-float buckets are currently published from BUFF163's segmentation. Cross-market phase pricing (Step 2) draws on every venue that lists phases separately, so use the NBBO for "where is it cheapest" and the buckets for "what does float do to the price".

## When to reach for a different endpoint

To price ordinary skins by float, without a phase, follow the [float range guide](/resources/cs2-float-range-prices). To inspect the individual listings behind a phase price, including exact floats and paint indexes, use the [listing data guide](/resources/cs2-listing-float-paint-seed-stickers). And for BUFF's full bucket set and history in one place, see [BUFF163 prices and history](/resources/buff163-prices-and-history).

## Endpoints used

- [GET /v1/schema/items/:idOrName](/api-docs/schema-item.md)
- [GET /v1/nbbo](/api-docs/nbbo.md)
- [GET /v1/attribute-prices/latest](/api-docs/floats.md)
- [GET /v1/attribute-prices/history](/api-docs/attribute-history.md)
- [How attribute & float buckets are built](/api-docs/attribute-buckets.md)

## Related guides

- [How to price a CS2 skin by its float range](/resources/cs2-float-range-prices.md)
- [How to get BUFF163 prices, float buckets, and history in USD](/resources/buff163-prices-and-history.md)
- [How to get float, paint seed, and sticker data for live CS2 listings](/resources/cs2-listing-float-paint-seed-stickers.md)
- [How to find the best bid and ask for a CS2 skin across every market](/resources/cs2-best-bid-and-ask.md)
