# How to get live CS2 skin prices from every marketplace

> Pull live CS2 skin prices from every major marketplace in one call: per-market asks, bids, and aggregate stats in USD cents, with runnable curl and TypeScript.

*Prices & quotes · Beginner · Updated 2026-09-25*

"What is this skin worth right now?" sounds like one question, but every marketplace answers it differently. Each venue has its own listings, its own buy orders, its own fees, and its own refresh cadence. Scraping them one by one means maintaining a dozen integrations, normalizing a dozen currencies, and still not knowing which quotes are current.

SkinPricer does that collection for you and serves the result from one endpoint, [`GET /v1/pricing/:marketHashName`](/api-docs/price). A single call returns every covered venue's representative ask, every standing buy order, an aggregate over the asks, and a best bid and ask summary, all in integer USD cents. This guide covers the single-item read, narrowing it to the venues you trade on, and searching the catalog when you need many items at once.

## What one pricing call returns

| Field | What it tells you |
| --- | --- |
| `markets[]` | One representative ask per venue: `market`, `price`, `fetchedAt` (when SkinPricer last fetched it from the venue), `ingestedAt` (when it reached our price store), `quoteSize` (listings behind the quote), and `isStale`. |
| `buyOrders[]` | Standing buy orders per venue, with `totalQuantity`. Often shorter than `markets[]`: only some venues run a bid book. |
| `aggregate` | Min, max, average, median, and standard deviation over the asks, plus `marketCount`, `freshMarketCount`, and `listingCount`. |
| `bestAsk` / `bestBid` | The cheapest ask and the highest bid across venues, each naming its market. In the default view the bid only counts cash-executable venues. |
| `spreadBps` | The best ask versus best bid gap in basis points. `null` when a side is missing, when the book is crossed, or when the gap would exceed 10000 bps. |

## Step 1: price a single item

Put the exact Steam `market_hash_name` in the path, URL-encoded, and send your key in the `Authorization` header. The endpoint is part of every plan, starting with Developer.

**curl**

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

curl -s "https://pricing.skinpricer.com/v1/pricing/AK-47%20%7C%20Redline%20(Field-Tested)" \
  -H "Authorization: ApiKey $SKINPRICER_API_KEY"
```

**Node (SDK)**

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

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

// The SDK URL-encodes the name for you.
const item = await client.pricing.get("AK-47 | Redline (Field-Tested)");

for (const quote of item.markets) {
  console.log(quote.market.padEnd(16), formatUsd(quote.price), quote.isStale ? "(stale)" : "");
}

const median = item.aggregate?.medianPrice;
if (median != null) console.log("Median ask across venues:", formatUsd(median));
```

**Python**

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

import requests

name = "AK-47 | Redline (Field-Tested)"
res = requests.get(
    f"https://pricing.skinpricer.com/v1/pricing/{quote(name, safe='')}",
    headers={"Authorization": f"ApiKey {os.environ['SKINPRICER_API_KEY']}"},
    timeout=10,
)
res.raise_for_status()
item = res.json()

for q in item["markets"]:
    flag = " (stale)" if q["isStale"] else ""
    print(f"{q['market']:<16} {q['price'] / 100:>9.2f} USD{flag}")
```

*The name goes in the path, so encode it fully (spaces, the pipe, and parentheses). In Python, quote(name, safe='') does that.*

**Response 200** (`GET /v1/pricing/:marketHashName`)

```json
{
  "canonicalItemId": "cmlofca920lka01yozajhixt3",
  "name": "Glock-18 | Water Elemental (Factory New)",
  "aggregate": {
    "minPrice": 6500,
    "maxPrice": 8012,
    "avgPrice": 7102,
    "medianPrice": 7119,
    "stdDev": 439.12,
    "marketCount": 10,
    "freshMarketCount": 9,
    "listingCount": 710,
    "updatedAt": "2026-06-23T21:59:48.717Z"
  },
  "markets": [
    {
      "market": "csfloat",
      "price": 6500,
      "currency": "USD",
      "fetchedAt": "2026-06-23T21:52:27.427Z",
      "ingestedAt": "2026-06-23T21:55:56.923Z",
      "quoteSize": 132,
      "ingestLatencyMs": 209496,
      "isStale": false,
      "sourceUpdatedAt": "2026-06-23T21:01:13.000Z",
      "sourceTimeKind": "last_modified",
      "sourceAgeSeconds": 3074
    }
  ],
  "buyOrders": [
    {
      "market": "buff163",
      "price": 6440,
      "currency": "USD",
      "fetchedAt": "2026-06-23T21:59:48.717Z",
      "ingestedAt": "2026-06-23T21:59:48.000Z",
      "quoteSize": 47,
      "totalQuantity": 47,
      "ingestLatencyMs": 0,
      "isStale": false
    }
  ],
  "bestAsk": {
    "market": "csfloat",
    "price": 6500,
    "updatedAt": "2026-06-23T21:52:27.427Z",
    "isStale": false
  },
  "bestBid": {
    "market": "buff163",
    "price": 6440,
    "updatedAt": "2026-06-23T21:59:48.717Z",
    "isStale": false
  },
  "spreadBps": 93,
  "marketCount": 10,
  "freshMarketCount": 9,
  "calculatedAt": "2026-06-23T22:07:13.752Z"
}
```

*The documented 200 response, trimmed to one venue per list. A real response carries one entry per covered venue.*

## Step 2: narrow it to the venues you trade on

Most integrations only care about a handful of markets: the ones you can deposit on, withdraw from, or hold inventory at. Pass a `markets` list (a comma-separated query parameter, or an array in the SDK) and the response is restricted to those venues. Market ids are the same join keys the [market health](/api-docs/markets) endpoint returns, such as `csfloat`, `buff163`, `skinport`, and `steamcommunity`.

**curl**

```bash
curl -s "https://pricing.skinpricer.com/v1/pricing/AK-47%20%7C%20Redline%20(Field-Tested)?markets=csfloat,buff163,skinport" \
  -H "Authorization: ApiKey $SKINPRICER_API_KEY"
```

**Node (SDK)**

```ts
const venues = await client.pricing.get("AK-47 | Redline (Field-Tested)", {
  markets: ["csfloat", "buff163", "skinport"],
});

if (venues.bestAsk && venues.bestBid) {
  console.log("Cheapest:", venues.bestAsk.market, formatUsd(venues.bestAsk.price));
  console.log("Best bid:", venues.bestBid.market, formatUsd(venues.bestBid.price));
}
```

> **An explicit markets list changes which bids count:** Without `markets`, `bestBid` only considers venues that pay out in cash, so a Steam wallet-credit buy order can never win it. Once you pass a list, every listed venue's bid is taken verbatim. If you include `steamcommunity`, the best bid may be wallet credit. The [Steam vs cash guide](/resources/steam-vs-cash-market-prices) covers how to compare the two.

## Step 3: search the catalog and price many items

When you do not know the exact name, or you want prices for a whole weapon or collection, use [`GET /v1/items`](/api-docs/items). Every result is the same cross-market snapshot as the single-item read, and results are paginated. Search is tokenized: each word is matched as a case-insensitive prefix and every word must match, so `redline ft` narrows on both words rather than looking for that exact phrase. `perPage` goes up to 100.

**curl**

```bash
curl -s "https://pricing.skinpricer.com/v1/items?search=redline&perPage=50&page=1" \
  -H "Authorization: ApiKey $SKINPRICER_API_KEY"
```

**Node (SDK)**

```ts
// searchEach walks every page for you.
for await (const item of client.items.searchEach({ search: "redline", perPage: 100 })) {
  const ask = item.bestAsk;
  console.log(item.name, ask ? formatUsd(ask.price) + " on " + ask.market : "no listings");
}
```

*Each page costs one request against your per-minute budget, so a 100-item page is far cheaper than 100 single-item calls.*

For a full catalog sync there is also [`GET /v1/items/all`](/api-docs/items-all), which returns every tracked item with its latest per-market prices in one unpaginated array (capped at 50,000 rows). It is heavy, so run it on a schedule and cache the result rather than calling it per request.

## Read the numbers correctly

- Every price is an integer number of USD cents. `1550` is $15.50. Divide by 100 only when you display it, so rounding never accumulates.
- `aggregate` describes asks, not trades. The `maxPrice` is often one optimistic listing, and a single outlier can drag `avgPrice`. For a headline number, prefer `minPrice` (what you could buy at) or `medianPrice` (the typical ask).
- Judge freshness by `fetchedAt`, not `ingestedAt`. `isStale` flips when `fetchedAt` is more than 30 minutes old; treat it as a soft signal on thinly traded items where an older quote may be the only one.
- `null` means unknown, not zero. A venue with no listings is simply absent from `markets[]`, and a missing bid side leaves `bestBid` and `spreadBps` as `null`.
- `quoteSize` is how many listings back a venue's quote. A price backed by one listing can disappear the moment someone buys it.

## When to reach for a different endpoint

If you only need the top of the book, one best ask and one best bid with fee-adjusted execution prices, [the NBBO guide](/resources/cs2-best-bid-and-ask) is lighter and more precise. For charts and trend lines, [price history](/resources/cs2-price-history) returns time buckets instead of a snapshot. And if you are building a page that shows every venue side by side, the [comparison site guide](/resources/build-cs2-price-comparison-site) combines search, per-market quotes, and market health into one workflow. The full field reference lives on the [pricing](/api-docs/price) and [item search](/api-docs/items) API reference pages.

## Endpoints used

- [GET /v1/pricing/:marketHashName](/api-docs/price.md)
- [GET /v1/items](/api-docs/items.md)

## Related guides

- [How to find the best bid and ask for a CS2 skin across every market](/resources/cs2-best-bid-and-ask.md)
- [Steam Market vs cash-market prices: how to compare them correctly](/resources/steam-vs-cash-market-prices.md)
- [How to get CS2 skin price history at any interval](/resources/cs2-price-history.md)
- [How to build a CS2 skin price comparison site](/resources/build-cs2-price-comparison-site.md)
