Dota 2 inventory
Dota 2 inventory API with cosmetic values
Request game=dota2 for Dota 2 cosmetics using the same typed inventory response as CS2, Rust and TF2. Missing prices remain explicit instead of removing the item.
GET /v1/inventory?game=dota2Bearer authenticationUpdated
WOK APIcurl --fail-with-body \
-H "Authorization: Bearer $WOK_API_KEY" \
"https://woksteamapi.com/v1/inventory?steam_id=76561198090744629&game=dota2&top=10"Your first Dota 2 inventory request
Dota 2 uses Steam AppID 570 and inventory context 2. WOK selects them with game=dota2.
Create a WOK account and API key, set WOK_API_KEY on your server, and use the curl example with a public SteamID64.
Check status before showing the value. A private inventory is not an empty inventory. Show unpriced alongside total; gems and autographs are not separately appraised.
Show meta.cache_age and meta.cache_ttl separately from each item's priceupdatedat. To change only the valuation, use batch price-only refresh with games:["dota2"]; it preserves the inventory age.
Quote a cosmetic without reading the backpack again
The example quotes Manifold Paradox. Replace that value with one exact items[].markethashname from an inventory response. The returned source and updated_at describe that saved quote, not the player's current ownership. A missing catalog row returns 404; keep the item in your inventory display as unpriced.
WOK APIcurl --fail-with-body -H "Authorization: Bearer $WOK_API_KEY" --get "https://woksteamapi.com/v1/price" --data-urlencode "game=dota2" --data-urlencode "name=Manifold Paradox"Complete Dota 2 API mapMarket source and timestamp meaningsSelective observed historyMigrate an existing SteamWebAPI integrationCheck request quotas before production
Quickstart
Use WOK from a trusted server. Keep the API key outside browser bundles and public repositories.
WOK APIcurl --fail-with-body \
-H "Authorization: Bearer $WOK_API_KEY" \
"https://woksteamapi.com/v1/inventory?steam_id=76561198090744629&game=dota2&top=10"WOK API// Node.js: keep the API key on your server.
const url = new URL("https://woksteamapi.com/v1/inventory");
url.search = new URLSearchParams({
steam_id: "76561198090744629",
game: "dota2",
top: "10"
});
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 inventory = await response.json();WOK APIimport os
import requests
response = requests.get(
"https://woksteamapi.com/v1/inventory",
headers={"Authorization": f"Bearer {os.environ['WOK_API_KEY']}"},
params={
"steam_id": "76561198090744629",
"game": "dota2",
"top": 10,
},
timeout=30,
)
response.raise_for_status()
inventory = response.json()Response example
The values below illustrate the response shape. Field names and types match the public contract.
JSON
application/json{
"steamid": "76561198090744629",
"game": "dota2",
"status": "ok",
"total": 24.68,
"items_total": 2,
"sellable": 2,
"untradable": 0,
"untradable_value": 0.0,
"tradelocked": 0,
"tradelocked_value": 0.0,
"unpriced": 0,
"items": [
{
"markethashname": "Example market item",
"count": 2,
"game": "dota2",
"tradable": 1,
"marketable": 1,
"pricemedian": 12.34,
"prices": {
"steam": 12.34
},
"pricesource": "steam",
"priceupdatedat": 1787572800.0
}
],
"meta": {
"cached": true,
"shared": false,
"lane": "cache",
"saved": false,
"ms": 0,
"bytes": 0,
"paid_bytes": 0,
"upstream_attempts": 0,
"detail": "",
"cache_age": 42,
"cache_ttl": 1800,
"price_source": "steam"
}
}
Response schema
Stable fields for typed clients, storage and error handling.
| Field | Type | Meaning |
|---|---|---|
steamid | string | Canonical 17-digit SteamID64. |
game | string | Documented key: cs2, rust, tf2, dota2, pubg, sandbox, unturned or payday2. Numeric Steam appids are also accepted and returned as app<appid> without catalog pricing. |
status | string | ok, empty, private, notfound, limited or error. |
total | number | Priced sellable inventory total in USD. |
items_total | integer | Number of item instances before top truncation. |
sellable | integer | Tradable and marketable item instances, including unpriced ones; total sums matched values. |
untradable | integer | Item instances excluded from sellable value. |
untradable_value | number | Value of excluded untradable items in USD. |
tradelocked | integer | Item instances currently trade locked. |
tradelocked_value | number | Value of trade-locked items in USD. |
unpriced | integer | Instances without a usable price. |
items[] | array | Items with market names, count, trade state, prices and optional inspect links. |
items[].markethashname | string | Canonical price-catalog market hash name. |
items[].marketname | string | Steam market display name when supplied. |
items[].type | string | Steam-supplied item type text; not a WOK-normalized category. |
items[].count | integer | Grouped item instance count. |
items[].tradable | integer | Steam tradability flag, 0 or 1. |
items[].marketable | integer | Steam marketability flag, 0 or 1. |
items[].tradelocked | boolean | Whether the grouped item is trade locked. |
items[].tradelockuntil | number|null | Unix expiry when a trade lock is known. |
items[].pricemedian | number|null | Selected source median price in USD. |
items[].pricesource | string | Selected catalog source; empty when the item is unpriced. |
items[].priceupdatedat | number|null | Selected source observation time, separate from inventory cache age. |
items[].prices | object | Per-source USD prices. |
items[].inspect_links | array | Optional CS2 inspect actions. |
meta | object | Cache age/TTL, cached/shared flags, timing, bytes, lane and upstream-attempt metadata. |
meta.cached | boolean | Whether the inventory snapshot was reused. |
meta.shared | boolean | Whether this request joined an in-flight singleflight fetch. |
meta.cache_age | integer | Snapshot age in seconds. |
meta.cache_ttl | integer | Applied freshness window in seconds. |
Limits and error behavior
Rules clients should handle explicitly in production.
The Steam inventory must be public. Private, missing and empty inventories are distinct statuses, not successful empty data.
top accepts 0 through 100. top=0 returns every item row; items_total still describes the complete inventory when a top limit is used.
Prices are USD. An item can be valid while pricemedian is null; use unpriced instead of treating missing prices as zero-value evidence.
A partial or malformed Steam inventory is not saved as a successful snapshot. On GET /v1/inventory, validation/auth failures use HTTP 400/401/402/404/422/429; Steam outcomes private, notfound, limited and error are returned with HTTP 200 in response.status. The compatibility GET /steam/api/inventory maps them to 403/404/429/502 (empty to 410).
Socketed gems, autographs and unusual modifiers can require instance-specific valuation beyond a market hash name price.
Cache and freshness semantics
How to tell whether data was reused, shared or refreshed.
Successful inventory snapshots use a 1,800-second default TTL. Negative defaults are 21,600 seconds for empty, 3,600 seconds for private and 600 seconds for not found.
For authenticated inventory responses that reach validation/result handling, read X-Wok-Cache-Age and X-Wok-Cache-TTL when present; authentication and quota errors may omit them.
Identical concurrent misses are coalesced. A waiter receives X-Wok-Singleflight: 1 and does not start another Steam inventory fetch.
Use refresh_prices=1 or POST /v1/inventory/refresh-prices only with an active compatible OK/EMPTY snapshot. Repricing never fetches Steam or resets inventory age/TTL; 404 inventory_cache_miss means run a normal inventory scan. refresh_prices=1 cannot be combined with no_cache=1; prices_updated_at identifies the repricing operation.
Frequently asked questions
Direct answers about access, freshness and result semantics.
Which game value selects Dota 2?
Use game=dota2 with GET /v1/inventory.
Does this Dota 2 API include match or hero statistics?
No. The documented game=dota2 endpoint returns public inventory cosmetics, trade state and matched catalog prices, not match history or hero performance.
How are missing Dota 2 prices represented?
The cosmetic remains in the response with a missing price and contributes to the unpriced count.