Skip to main content
GET/v2/prices/latestENTERPRISE

Bulk Latest Prices

Latest prices for every catalog item of one game in a single call: each item's per-market asks and bids plus its best ask and best bid, in the same shape and with the same values as /v2/pricing/:marketHashName in its default all-markets view. Rebuilt every 10 minutes and served gzip-compressed. Enterprise plans only. The bulk alternative to /v1/items/all. Prices are integer USD cents.

One request returns every item of the game that has a servable quote: items[], ordered by canonicalItemId, with itemCount closing the envelope. Each item carries the same markets[] (asks), buyOrders[] (bids), bestAsk and bestBid as /v2/pricing/:marketHashName in its default all-markets view, so a snapshot row matches what the per-item route returned when the snapshot was built. As there, bestBid only considers cash-executable venues. Both bestAsk and bestBid are nullable and a missing bestBid is common, so null-check both. Items the per-item route would answer with 404 (no servable quote) are left out rather than listed empty.

The snapshot is rebuilt every 10 minutes. generatedAt is when the build started, and every quote in it was read at or after that time. Each quote's isStale is evaluated when the snapshot is built.

Efficient polling: send Accept-Encoding: gzip. The body is served compressed and is roughly 10 times smaller that way (about 7 MB instead of 75 MB for CS2 today), and gzip downloads are never limited; uncompressed downloads are limited to a few at a time and can answer 503. Keep the ETag from each 200 and send it back as If-None-Match: you get a 304 with no body until the next snapshot, which is rebuilt every 10 minutes. Responses carry Cache-Control: private, max-age=60, Vary: Accept-Encoding, and Last-Modified (the snapshot's generatedAt). Poll every 1 to 10 minutes with gzip and If-None-Match; a new snapshot lands every 10 minutes. Quota: every request that passes the plan check counts toward your per-minute limit (and the monthly limit where your plan has one), 304s and 503s included; a 401 or a plan 403 does not.

Games: pass game=cs2. The route also accepts game=rust, which answers 503 until Rust is enabled on it. See Games: CS2 & Rust.

Parameters

gamestringrequired
Query. cs2 or rust; missing or any other value returns 400. rust answers 503 until Rust is enabled on this route.
Accept-Encodingstringoptional
Header. Send gzip. The body is served compressed, roughly 10 times smaller (about 7 MB instead of 75 MB for CS2 today), and compressed downloads are never limited. Uncompressed downloads are limited to a few at a time and can answer 503.
If-None-Matchstringoptional
Header. The ETag from your last download; returns 304 with no body until the next snapshot (rebuilt every 10 minutes).

Response fields

LatestPricesResponseEvery item of one game that has a servable quote, in one snapshot.
generatedAtstring (date-time)
When the snapshot build started. Every quote in it was read at or after this time. Also sent as Last-Modified.
gamestring
cs2 or rust, as requested.
currencystring
Always USD: the currency of every price field.
Every catalog item with at least one servable quote, ordered by canonicalItemId.
itemCountinteger
Number of entries in items.

Nested and shared shapes link to the API Objects reference.

Errors

400game missing or not cs2 / rust.
401Missing Authorization header, unsupported scheme, or a key that is unknown, inactive, expired, or revoked.
403Valid key, but the plan does not include bulk prices (Enterprise only), or the subscription is inactive or expired.
429Rate limit exceeded; see Retry-After + X-RateLimit-* headers. Pooled per account across all keys.
503No fresh snapshot (none built yet, or the newest is more than 25 minutes old), Rust not enabled yet, or too many uncompressed downloads in progress. Comes with Retry-After: 60: retry then, ideally with Accept-Encoding: gzip.
export SKINPRICER_API_KEY="sp_live_•••"

# --compressed asks for gzip and unpacks it. etag.txt keeps the last ETag:
# until the next snapshot (every 10 minutes) the API answers 304 and
# prices-cs2.json stays as it is. Needs curl 7.68 or newer.
curl -G "https://pricing.skinpricer.com/v2/prices/latest" \
  --data-urlencode "game=cs2" \
  -H "Authorization: ApiKey $SKINPRICER_API_KEY" \
  --compressed \
  --etag-compare etag.txt \
  --etag-save etag.txt \
  -o prices-cs2.json
// No SDK helper for this endpoint yet, so call it directly.
// Poll every 1 to 10 minutes; a new snapshot lands every 10.
let etag: string | null = null;

async function pollLatestPrices() {
  const url = new URL("https://pricing.skinpricer.com/v2/prices/latest");
  url.searchParams.set("game", "cs2");
  const res = await fetch(url, {
    headers: {
      Authorization: `ApiKey ${process.env.SKINPRICER_API_KEY}`,
      "Accept-Encoding": "gzip", // fetch unpacks the body for you
      ...(etag ? { "If-None-Match": etag } : {}),
    },
  });
  if (res.status === 304) return null; // no new snapshot since the last poll
  if (!res.ok) throw new Error(`HTTP ${res.status}`); // 503: retry after Retry-After
  etag = res.headers.get("etag");
  return res.json();
}

const snapshot = await pollLatestPrices();
if (snapshot) console.log(snapshot.itemCount, "items, built at", snapshot.generatedAt);
import os
import requests

etag = None  # keep the last ETag between polls (every 1 to 10 minutes)


def poll_latest_prices():
    global etag
    headers = {
        "Authorization": f"ApiKey {os.environ['SKINPRICER_API_KEY']}",
        "Accept-Encoding": "gzip",  # requests unpacks the body for you
    }
    if etag:
        headers["If-None-Match"] = etag
    res = requests.get(
        "https://pricing.skinpricer.com/v2/prices/latest",
        params={"game": "cs2"},
        headers=headers,
        timeout=60,
    )
    if res.status_code == 304:
        return None  # no new snapshot since the last poll
    res.raise_for_status()  # 503: retry after the Retry-After header
    etag = res.headers.get("ETag")
    return res.json()


snapshot = poll_latest_prices()
if snapshot:
    print(snapshot["itemCount"], "items, built at", snapshot["generatedAt"])

Authenticated endpoint: call it with your API key from your own client (see the code sample).

Response 200
{
  "generatedAt": "2026-09-28T12:00:00.000Z",
  "game": "cs2",
  "currency": "USD",
  "items": [
    {
      "name": "AK-47 | Redline (Field-Tested)",
      "canonicalItemId": "cmlofczf90qj401vsd80dskd1",
      "bestAsk": {
        "market": "buff163",
        "price": 1450,
        "updatedAt": "2026-09-28T11:58:12.000Z",
        "isStale": false
      },
      "bestBid": {
        "market": "buff163",
        "price": 1400,
        "updatedAt": "2026-09-28T11:57:40.000Z",
        "isStale": false
      },
      "markets": [
        {
          "market": "buff163",
          "price": 1450,
          "fetchedAt": "2026-09-28T11:58:12.000Z",
          "isStale": false,
          "quoteSize": 20,
          "originalPriceCents": 10150,
          "originalCurrency": "CNY"
        },
        {
          "market": "csfloat",
          "price": 1512,
          "fetchedAt": "2026-09-28T11:55:03.000Z",
          "isStale": false,
          "quoteSize": 7,
          "originalPriceCents": 1512,
          "originalCurrency": "USD"
        }
      ],
      "buyOrders": [
        {
          "market": "buff163",
          "price": 1400,
          "fetchedAt": "2026-09-28T11:57:40.000Z",
          "isStale": false,
          "quoteSize": 5,
          "totalQuantity": 44
        },
        {
          "market": "youpin",
          "price": 1385,
          "fetchedAt": "2026-09-28T11:56:20.000Z",
          "isStale": false,
          "quoteSize": 3,
          "originalPriceCents": 9695,
          "originalCurrency": "CNY",
          "totalQuantity": 31,
          "totalOrdersCount": 12,
          "orderBookComplete": true
        }
      ]
    }
  ],
  "itemCount": 1
}
Response headers
X-RateLimit-Limit: <per-minute, set by your plan>
X-RateLimit-Remaining: <remaining this minute>
X-RateLimit-Reset: <seconds to reset>
X-RateLimit-Remaining-Month: <left this month, capped plans>
X-Request-ID: req_xxxxxxxxxxxxxxxx

Usage & licensing

Access to the API and its data is governed by our Terms of Service. You may not resell or redistribute the data, use it to build a competing service, or exceed your plan’s rate limits, and you must attribute SkinPricer as the source wherever the Terms permit you to display it. Abuse may be throttled or suspended.