Skip to content
API

Steam item prices

Steam price API for item quotes, batches and history

Look up an exact Steam market hash name and receive the selected USD quote, source-level prices and update time. Use separate endpoints for a 200-name batch, catalog search and daily OHLC data.

GET /v1/priceBearer authentication

Updated

curl
curl --fail-with-body \
  -H "Authorization: Bearer $WOK_API_KEY" \
  --get "https://woksteamapi.com/v1/price" \
  --data-urlencode "game=cs2" \
  --data-urlencode "name=AK-47 | Redline (Field-Tested)"
1 quoteexact market hash name lookup
200 namesmaximum price batch
USDselected and source-level values
365 daysobserved daily OHLC history

Select a price source and statistic

Single quotes and price batches accept price_source, strict and price_stat. Catalog search uses source to filter saved rows.

GET /v1/price?game=cs2&name=... returns the selected quote, available sources and the selected source's updated_at. Use price_source=skinport&strict=1 to require that provider. If source is empty, no usable selected quote exists.

POST /v1/prices accepts {"game":"cs2","names":["AK-47 | Redline (Field-Tested)"],"price_source":"skinport","strict":true,"price_stat":"min"} and returns a name-keyed map with price, source, sources and statistic coverage. Unknown names are omitted. The quote has no updated_at field of its own; read each source's known updated_at within source_statistics. Missing or null source times remain unknown. Quota is charged per unique requested name, not just once for the HTTP envelope.

price_stat=min|max|avg|median chooses a statistic. Without price_source, it compares one fresh lowest ask per marketplace. With an explicit price_source, it selects the provider's reported field; unsupported values are null. Read price_statistics.source_count and source_statistics before treating a result as a range of lots. For player-owned items, compare inventory listing floors and medians. A catalog quote does not prove that a player owns an item.

Before displaying a value, require price_status="available". When the lookup has no retained price observation for the exact game and name, a single quote returns HTTP 404 and a batch omits that name. This can include observations excluded by source-age rules; it does not establish that the item is absent from Steam or WOK's catalog. A retained name without a usable selected quote can return price=0 with an empty source; an unsupported statistic returns null. Keep those states distinct from a free item. For a strict quote, verify the returned source; steam selects a Steam family rather than one exact feed. Check an exact quote against your display-age policy.

Compare WOK with SteamWebAPICheck endpoint compatibility before migrating

Why is an item price missing or too old?

Check the exact item, selected source and observation time before displaying a price. A successful HTTP response alone does not establish a usable current quote.

Export WOK_API_KEY and WOK_MARKET_HASH_NAME as environment variables on your server before running these examples. Copy the full CS2 name from items[].markethashname in an actual inventory or market_hash_name in a catalog result, including exterior and StatTrak or Souvenir variant. This example requests only Skinport's saved CS2 listing floor; it does not assume that source covers every game or item.

Capture one exact CS2 quote (curl)
umask 077
curl --disable --fail-with-body --max-time 30 --max-filesize 262144 \
  -H "Authorization: Bearer $WOK_API_KEY" \
  --get "https://woksteamapi.com/v1/price" \
  --data-urlencode "game=cs2" \
  --data-urlencode "name=$WOK_MARKET_HASH_NAME" \
  --data-urlencode "price_source=skinport" \
  --data-urlencode "price_stat=min" \
  --data-urlencode "strict=1" \
  --output quote.json --write-out '\nHTTP %{http_code}\n'

The command makes one bounded request and saves its body as quote.json. It prints the HTTP status. Run the Python check below only after curl succeeds with HTTP 200; a failed capture can leave an incomplete file. The request consumes one WOK quota unit when admitted, including an unavailable quote. It makes no Steam inventory scan or on-demand marketplace refresh. The first curl option, --disable, ignores the default curl configuration file; redirects and retries are not enabled.

Observed resultWhat to do
HTTP 404No retained lookup quote for this exact game and name. Check spelling, game and variant. A saved observation may also have been excluded by an age rule; do not label the item worthless or absent from Steam.
HTTP 200, price_status=unavailableA name was found, but the requested selection or statistic is unavailable. Preserve null or zero as an unavailable quote; do not present a free item or silently switch providers.
Available price, unknown or old updated_atKeep the source time with the value. Apply your own maximum age and show a dated value or unavailable state when it fails. A recent response time does not replace the source time.
HTTP 401, 402, 429 or another failureHandle the access, quota or temporary error before inspecting a price. Follow Retry-After when supplied and use a bounded retry policy; do not repeatedly replay a missing quote.

Check the saved quote without another API call

Save the following as quote_check.py, then run python3 quote_check.py in the directory containing the successful response. The one-hour limit is an illustrative application setting. Choose the age your workflow accepts; WOK does not guarantee that every source updates within it. The checker requires this exact game, name, USD, statistic and provider, rejects unknown or future times, and never substitutes another price.

Validate the saved quote (Python)
# Save as quote_check.py. Python 3.10+, standard library only.
import json
import math
import os
import time

MAX_AGE_SECONDS = 3600  # Example application policy, not a WOK freshness promise.


def positive_number(value):
    try:
        return (isinstance(value, (int, float)) and not isinstance(value, bool)
                and math.isfinite(value) and value > 0)
    except OverflowError:
        return False


def check_quote(quote, expected_name, now):
    if not isinstance(quote, dict):
        raise ValueError("Unexpected quote response")
    if (quote.get("game") != "cs2" or quote.get("name") != expected_name
            or quote.get("currency") != "USD" or quote.get("price_stat") != "min"):
        raise ValueError("Unexpected game, exact name, currency or statistic")
    price = quote.get("price")
    if quote.get("price_status") != "available" or not positive_number(price):
        raise ValueError("No usable selected price; keep the value unavailable")
    if quote.get("source") != "skinport":
        raise ValueError("The quote is not from the required source")
    observed_at = quote.get("updated_at")
    if not positive_number(observed_at) or observed_at > now:
        raise ValueError("Unknown or future source time; do not label it fresh")
    age = now - observed_at
    if age > MAX_AGE_SECONDS:
        raise ValueError("Source quote is older than this application's age policy")
    return price, age


if __name__ == "__main__":
    with open("quote.json", "rb") as saved:
        raw = saved.read(262145)
    if len(raw) > 262144:
        raise SystemExit("Quote file exceeds the example's size limit")
    try:
        quote = json.loads(raw)
        price, age = check_quote(quote, os.environ["WOK_MARKET_HASH_NAME"], time.time())
    except (ValueError, KeyError) as error:
        raise SystemExit(str(error))
    print(f"{price:.2f} USD; Skinport listing floor; source age {age:.0f}s")

To investigate broader gaps, request GET /v1/prices/coverage?game=cs2&source=skinport with Bearer authentication. This is a separate quota-bearing request. Its quote_age_p50_seconds, quote_age_p95_seconds and missing-name counts summarize saved source rows and can be cached for five minutes. They do not prove that this exact item meets your age policy or that all Steam items are covered. A repeated quote read, source change or inventory refresh_prices=1 reads local observations; none forces a new provider observation.

A positive listing-floor quote remains a name-level observation. It does not establish current ownership, live stock, the value of an individual float or sticker craft, or sale proceeds after fees. For inventory values, retain null item prices, unpriced, quantities and sellable-state rules instead of treating missing coverage as zero.

Revalue an active inventory snapshotAudit inventory quantities and unpriced valueHandle access and API errorsSaved coverage and freshness reference

Choose the price endpoint for the job

The quote, batch, catalog and history methods share the same item naming contract but return different shapes.

EndpointUse it forResult
GET /v1/priceOne exact market hash nameSelected USD price, source values and update time
POST /v1/prices1 to 200 names for one gameMap of matched names to price quotes
GET /v1/itemsSearching or paging through the catalogPer-source price rows and a cursor
GET /v1/prices/coverageChecking saved catalog coverage and quote agePer-game and per-source priced counts, missing counts and observation age
GET /v1/cs2/itemsFiltering saved CS2 names by base item, exterior, variant or priceCursor page with name-derived metadata and explicit unknown rarity/collection
GET /v1/cs2/market-listingsInspecting actual matching Steam Market lotsPage-level float, seed, native price and observed lot statistics
GET /v1/price-historyObserved daily history for 1 to 365 daysOHLC, volume, samples and observation times
POST /v1/portfolio-historyViewing observed daily value for 1 to 20 supplied exact namesPer-name gaps and a total only on days with every source observation

Read observed daily price historyPrice a public Steam inventoryRead inventory items and totalsSee every request parameterDownload OpenAPI

CS2 skin price API: which marketplaces are available?

WOK records separate USD observations for each actual source. A source name is only returned when a usable item price was observed; the number of marketplaces in a list does not guarantee coverage for your item.

SourceWhat it representsHow to inspect it
Steam MarketCommunity listing floor, saved median observations and buy orders are different values.source=steam_market for saved listing rows; read timestamps and volume.
SkinportLowest active listings for supported named games, including CS2.source=skinport in the catalog.
Market.CSGO and TMSeparate third-party catalog snapshots for named games.source=tm in the catalog.
BUFF163CS2 lowest sell listings from WOK's authorized shared Pricempire feed.source=buff or inventory price_source=buff&strict=1.
Skins.comCS2 lowest sell listings from the same shared feed, kept distinct from BUFF.source=skins or inventory price_source=skins&strict=1.
WaxpeerLowest active listing from a public USD feed for CS2, Dota 2, Rust and TF2 where stock exists.source=waxpeer or inventory price_source=waxpeer&strict=1.
49SkinsCurrent CS2 listing floor converted from EUR cents to USD, excluding checkout fees.source=49skins or inventory price_source=49skins&strict=1.
CS.DEALSCS2 lowest in-stock listing from the authenticated full-price snapshot, when configured.source=csdeals or inventory price_source=csdeals&strict=1.
HaloSkinsCS2 lowest in-stock P2P or bot listing from the authenticated full-market snapshot, when configured.source=haloskins or inventory price_source=haloskins&strict=1.

CSFloat pricesYouPin898 pricesSkinport pricesWaxpeer pricesMarket.CSGO prices

GET /v1/price accepts price_source, strict=1 and price_stat for one exact market hash name, while its sources map shows available saved quotes. Use GET /v1/items?game=cs2&source=waxpeer to page exact-source catalog rows. Explicit price_source=auto overrides a key's saved source. Omit price_source to preserve the key's saved selection; when none is set, the server default applies. mix can use fresh opt-in marketplace observations after a coarse outlier check. A selectable mode does not prove fresh coverage for a particular item. Compare each source's timestamp before treating quotes as simultaneous.

price_stat=selected|min|max|avg|median works across price, catalog and inventory endpoints. Without price_source, the statistics compare one recent lowest selling ask per marketplace; they do not summarize all seller lots. With price_source, WOK uses that provider's reported measure and returns null when the provider has no real maximum, average or median. price_statistics.basis, source_count and coverage make the scope explicit. To calculate min, max, average or median over actual CS2 Steam Market lots, use /v1/cs2/market-listings, follow its pages and keep native currencies separate. Its statistics cover observed matching lots on each returned page and include Steam fees.

GET /v1/cs2/market-prices provides a separate short-lived CS2 comparison snapshot where its upstream source has a fresh quote, including observed CSFloat and Youpin entries when available. It does not guarantee either market for every item. WOK does not currently promise DMarket coverage. Market-name quotes also cannot appraise an individual float, pattern, sticker combination, fees or actual sale proceeds.

Quickstart

Use WOK from a trusted server. Keep the API key outside browser bundles and public repositories.

curl
curl --fail-with-body \
  -H "Authorization: Bearer $WOK_API_KEY" \
  --get "https://woksteamapi.com/v1/price" \
  --data-urlencode "game=cs2" \
  --data-urlencode "name=AK-47 | Redline (Field-Tested)"
JavaScript (Node.js)
// Node.js: keep the API key on your server.
const url = new URL("https://woksteamapi.com/v1/price");
url.search = new URLSearchParams({
  game: "cs2",
  name: "AK-47 | Redline (Field-Tested)"
});
const response = await fetch(url, {
  headers: { Authorization: `Bearer ${process.env.WOK_API_KEY}` }
});
if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);
const quote = await response.json();
Python
import os
import requests

response = requests.get(
    "https://woksteamapi.com/v1/price",
    headers={"Authorization": f"Bearer {os.environ['WOK_API_KEY']}"},
    params={
        "game": "cs2",
        "name": "AK-47 | Redline (Field-Tested)",
    },
    timeout=10,
)
response.raise_for_status()
quote = response.json()

Response example

The values below illustrate the response shape. Field names and types match the public contract.

JSON

application/json
{
  "game": "cs2",
  "name": "AK-47 | Redline (Field-Tested)",
  "price": 12.34,
  "price_stat": "selected",
  "price_basis": "selected_source",
  "price_status": "available",
  "currency": "USD",
  "native_prices": {},
  "source": "steam_avg",
  "sources": {
    "steam_avg": 12.34,
    "steam": 12.79,
    "steam_market": 12.1,
    "skinport": 11.92,
    "tm": 11.75
  },
  "updated_at": 1787572800.0
}

Response schema

Stable fields for typed clients, storage and error handling.

Steam price API for item quotes, batches and history response schema
FieldTypeMeaning
gamestringDocumented key: cs2, rust, tf2, dota2, pubg, sandbox, unturned or payday2.
namestringExact Steam market hash name requested by the client.
pricenumber|nullUSD value for price_stat; check price_status before displaying a value.
price_statstringRequested statistic: selected, min, max, avg or median.
price_basisstring|nullSelected source, cross-market floor quotes or the provider's reported measure.
price_statusstringavailable or unavailable; unavailable is not a zero-value item.
price_statisticsobjectRecent marketplace floor-quote statistics, with source_count and coverage.
source_statisticsobjectProvider-reported statistics by source; unsupported measures are null.
currencystringUSD for price and sources.
native_pricesobjectSelected source's separate native quote, e.g. RUB for TM.
sourcestringSource for price; market_quotes for a cross-market statistic, or empty if unavailable.
sourcesobjectKnown USD prices keyed by catalog source.
updated_atnumberSelected source time, or latest contributing time for cross-market statistics; not the request time.

Limits and error behavior

Rules clients should handle explicitly in production.

GET /v1/price requires an exact market hash name. A valid item with no catalog match returns HTTP 404. If rows exist but no price passes selection, price_stat=selected returns price=0, source='' and updated_at=0. An unsupported min/max/avg/median returns price=null. Check price_status: unavailable does not mean a zero-value item.

POST /v1/prices accepts 1 through 200 names. Unknown names are omitted from its result, so compare response keys with the requested list.

Prices are USD observations, not guaranteed sale proceeds. Fees, liquidity and item-specific attributes can change the realizable value.

steam_market is WOK's lowest-listing observation from the bounded Steam Market sweep; steam/steam_avg are sale-median observations when present.

Use a market hash name, not a localized display label. The catalog can only match names observed for the selected game.

Cache and freshness semantics

How to tell whether data was reused, shared or refreshed.

For price_stat=selected, GET /v1/price updated_at belongs to the selected source, not an unrelated market. An explicit price_source overrides the key's saved source; otherwise the key or server default applies. Source selection reads saved observations, not a live refresh.

sources keeps the available source-level observations. A missing key means that source has no saved catalog match for the item. A saved observation is not a promise of a real-time executable quote.

GET /v1/items exposes per-source updated_at values and cursor pagination when an integration needs to inspect the catalog directly.

Catalog rows include image_url and Steam icon tokens when WOK has observed an exact game/name match in a public inventory or existing Market sweep. Unknown images are null; this read does not fetch icons.

GET /v1/price-history returns observed daily OHLC points for 1 through 365 days; it does not synthesize days with no observations.

GET /v1/price and POST /v1/prices accept price_source, strict and price_stat=selected|min|max|avg|median. Use query parameters for GET and JSON fields (including a boolean strict) for POST. Strict prevents fallback outside the requested source mode; steam remains a family.

Without an explicit price_source, non-selected statistics compare one recent lowest ask per marketplace; updated_at is the latest contributing observation, not a promise that every quote is that fresh. With price_source, only a provider-reported measure is used. Unsupported measures remain null. Inspect price_basis and price_statistics.coverage.

Each POST /v1/prices quote omits a quote-level updated_at. Known saved source times are in source_statistics[source].updated_at; missing or null times stay unknown. GET /v1/items also exposes prices[].updated_at when inspecting exact market_hash_name matches.

Frequently asked questions

Direct answers about access, freshness and result semantics.

What is the difference between the price and inventory price APIs?

The Steam price API quotes catalog items by market hash name. The inventory price API reads a public player's items and calculates an estimated inventory total.

Can I request more than one item price?

Yes. POST /v1/prices accepts 1 through 200 market hash names for one game. Unknown names are omitted from the response.

Does the API return historical prices?

Yes. GET /v1/price-history returns observed daily OHLC points for a requested item, source and period from 1 through 365 days.

Can I choose BUFF163 or another exact source for a quote?

Yes. GET /v1/price accepts price_source=buff&strict=1 for a BUFF-only CS2 selected quote; POST /v1/prices accepts the same fields in JSON with strict:true. Other documented source modes are supported. Check price_status and source: a missing selected quote is unavailable, not a zero-value item. GET /v1/items uses source=buff instead for exact-source catalog rows.

How do min, max, average and median differ from the selected price?

price_stat=selected uses the selected source quote. min, max, avg and median without an explicit price_source compare one recent lowest ask per marketplace, not all seller lots. With price_source they use that provider's reported measure; unsupported measures return null. Check price_basis, price_statistics and source_statistics.