Steam Community Market
Steam Market API for listings, quotes and history
Choose a market observation deliberately: steam_market is the lowest-listing snapshot, while steam and steam_avg are sale median observations when available. Every quote keeps source and updated_at so your application can show its freshness.
GET /v1/items?source=steam_marketBearer authenticationUpdated
curl --fail-with-body \
-H "Authorization: Bearer $WOK_API_KEY" \
--get "https://woksteamapi.com/v1/items" \
--data-urlencode "game=cs2" \
--data-urlencode "q=AK-47 | Redline (Field-Tested)" \
--data-urlencode "source=steam_market"Which Steam Market price does your application need?
Start with a game key and the exact market_hash_name from an item. The catalog request above searches saved observations; it does not contact Steam during that request.
| Saved source | What it describes | Safe use |
|---|---|---|
steam_market | Observed lowest listing from a bounded Community Market sweep. | Compare an asking price; check updated_at and stock context before displaying it. |
steam or steam_avg | Saved sale-median observations when available. | Compare with the listing source; availability varies by item and game. |
steam_buy | Separate saved buy-order observation when available. | Treat it as a different side of the market. It is excluded from automatic inventory valuation. |
Use GET /v1/items?game=cs2&source=steam_market to filter catalog rows by that exact saved source. A search in q is a substring, so match items[].market_hash_name exactly in your client and follow next_cursor. For one exact name, GET /v1/price accepts price_source=steam&strict=1; POST /v1/prices accepts the same selection in JSON. This selects the Steam family in order: steam_avg, steam, then steam_market. It does not pin the lowest-listing feed. Use the catalog request when you require steam_market specifically. Both quote endpoints also accept price_stat. The single quote exposes updated_at; the batch omits a quote-level updated_at. Inspect each returned source_statistics entry's nullable updated_at when present. Missing or null times remain unknown; returned times do not guarantee fresh or complete source coverage. Check quote availability and source age before displaying a value.
Python: find one exact saved listing and check its age
The quickstart above returns a search page. This Python example keeps the same filters while following next_cursor as needed, accepts only the exact market name and steam_market source, then applies an example 24-hour client policy to updated_at. Choose an age limit for your own workflow. The timestamp describes the saved source observation, not when this request ran; a catalog read does not refresh Steam or guarantee a newer price. Each catalog page uses one WOK request unit.
import os
import time
import requests
market_name = "AK-47 | Redline (Field-Tested)" # Use an exact market_hash_name.
params = {"game": "cs2", "source": "steam_market",
"q": market_name, "limit": 200}
headers = {"Authorization": f"Bearer {os.environ['WOK_API_KEY']}"}
quote = None
with requests.Session() as session:
while True:
response = session.get(
"https://woksteamapi.com/v1/items",
headers=headers, params=params, timeout=15,
)
response.raise_for_status()
page = response.json()
for item in page["items"]:
if item["market_hash_name"] != market_name:
continue # q is a substring search, not an exact lookup.
quote = next((price for price in item["prices"]
if price["source"] == "steam_market"), None)
break
if quote is not None or not page["has_more"]:
break
params["cursor"] = page["next_cursor"] # Keep all filters unchanged.
if quote is None:
print("No saved Steam Market listing for this exact item")
else:
age_hours = max(0, time.time() - quote["updated_at"]) / 3600
max_age_hours = 24 # Example application policy, not a WOK freshness SLA.
if age_hours > max_age_hours:
print(f"Saved listing is {age_hours:.1f} hours old; hide its value")
else:
print({"price_usd": quote["price_usd"],
"observed_at": quote["updated_at"],
"age_hours": round(age_hours, 1)})Read only observed price history
curl --fail-with-body -H "Authorization: Bearer $WOK_API_KEY" --get "https://woksteamapi.com/v1/price-history" --data-urlencode "game=cs2" --data-urlencode "name=AK-47 | Redline (Field-Tested)" --data-urlencode "source=steam_market" --data-urlencode "days=30"The history guide explains OHLC fields and gaps. A 30-day request can return fewer than 30 daily points: WOK records observations only after an item enters its tracked set, and no missing day is fabricated. Prices are USD estimates, not guaranteed proceeds after fees.
Need the float of an individual current CS2 offer? The CS2 Market float API guide covers the separate live, paginated listing route. Its prices use Steam's returned native currency rather than this saved USD catalog.
Current CS2 listing floatsOne quote or a 200-name batchApply prices to owned itemsSeparate BUFF163 CS2 observationsDota 2 inventory exampleTF2 backpack example
Quickstart
Use WOK from a trusted server. Keep the API key outside browser bundles and public repositories.
curl --fail-with-body \
-H "Authorization: Bearer $WOK_API_KEY" \
--get "https://woksteamapi.com/v1/items" \
--data-urlencode "game=cs2" \
--data-urlencode "q=AK-47 | Redline (Field-Tested)" \
--data-urlencode "source=steam_market"// Node.js: keep the API key on your server.
const url = new URL("https://woksteamapi.com/v1/items");
url.search = new URLSearchParams({
game: "cs2",
q: "AK-47 | Redline (Field-Tested)",
source: "steam_market"
});
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();import os
import requests
response = requests.get(
"https://woksteamapi.com/v1/items",
headers={"Authorization": f"Bearer {os.environ['WOK_API_KEY']}"},
params={
"game": "cs2",
"q": "AK-47 | Redline (Field-Tested)",
"source": "steam_market",
},
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. This example uses a historical observation timestamp. The saved lowest-listing row still has its provider min, but it is too old for recent floor-quote statistics: price_statistics.source_count is 0 and coverage is unavailable. Check actual source timestamps before displaying a current price.
JSON
application/json{
"game": "cs2",
"query": "AK-47 | Redline (Field-Tested)",
"source": "steam_market",
"currency": "USD",
"items": [
{
"game": "cs2",
"market_hash_name": "AK-47 | Redline (Field-Tested)",
"icon_url": null,
"icon_url_large": null,
"image": null,
"image_url": null,
"image_url_large": null,
"image_source": null,
"image_observed_at": null,
"source_count": 1,
"prices": [
{
"source": "steam_market",
"price_usd": 12.1,
"currency": "USD",
"volume": 3,
"updated_at": 1787572800.0,
"statistics": {
"basis": "lowest_listing_only",
"currency": "USD",
"min": 12.1,
"max": null,
"avg": null,
"median": null
}
}
],
"price_statistics": {
"basis": "one_lowest_ask_per_marketplace",
"currency": "USD",
"source_count": 0,
"sources": [],
"min": null,
"max": null,
"avg": null,
"median": null,
"min_source": null,
"max_source": null,
"coverage": "unavailable"
}
}
],
"next_cursor": null,
"has_more": false
}
Response schema
Stable fields for typed clients, storage and error handling.
| Field | Type | Meaning |
|---|---|---|
game | string | Requested named game key. |
currency | string | USD for price_usd fields; native TM RUB quotes use price_rub. |
query | string | Search text; q is a substring search, not an exact-name assertion. |
source | string|null | Exact saved source filter; buff selects BUFF163 for CS2. |
items[].market_hash_name | string | Exact market hash name to match before using a quote. |
items[].icon_url | string|null | Observed Steam icon token, or null if unknown. |
items[].image_url | string|null | Renderable HTTPS Steam image URL, or null; no image fetch occurs on this call. |
items[].image_source | string|null | Steam inventory or market sweep provenance of the icon. |
items[].image_observed_at | number|null | Unix time when WOK observed the icon. |
items[].source_count | integer | Number of returned source rows for this item. |
items[].price_statistics | object | Recent floor-quote statistics across the returned sources; source_count counts eligible recent observations, not every saved row. |
items[].price_statistics.coverage | string | multiple_marketplaces, single_marketplace or unavailable; old rows can remain visible without fresh statistic coverage. |
items[].prices[].source | string | Source of this observation. |
items[].prices[].price_usd | number | Saved source observation in USD. |
items[].prices[].price_rub | number | Native TM RUB quote when available; not a converted USD amount. |
items[].prices[].volume | integer | Source activity/count metadata, never a player's item count. |
items[].prices[].updated_at | number | Source observation timestamp, not the time of this API request. |
items[].prices[].statistics | object | Provider-reported measures and basis; lowest_listing_only supplies min, while unsupported max/avg/median stay null. |
next_cursor | string|null | Opaque cursor for the next page with the same filters. |
has_more | boolean | Whether another page is available. |
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.
A lowest listing is an observation, not a guaranteed executable price. Fees, currency conversion, availability and liquidity must be handled by the client.
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.
Is this the Steam Store game price API?
No. This page covers Community Market item observations such as listings and sale medians, not the regional price of a game or DLC in the Steam Store.
What does steam_market mean?
It is WOK's lowest-listing observation from a bounded Community Market sweep. It is useful for comparison, but it is not a guaranteed executable sale price.
Does a catalog request fetch a live Steam Market listing?
No. GET /v1/items reads WOK's saved catalog. Check each observation's updated_at and source; a missing item or date is unavailable data, not a zero market price.
Can I request history?
Yes. GET /v1/price-history returns observed daily OHLC points for one market hash name, source and period up to 365 days. It does not backfill dates before WOK observed the item.