Steam inventories,
minus the sharp edges.
ItemData exposes fresh, normalized Steam inventory data through one cursor-paginated HTTP endpoint with a stable response model.
/v1HTTPSNormal public requests can reuse a durable page snapshot. Use no_cache=true to force a coordinated refresh; requests carrying a Steam session bypass shared-cache reads and writes.
Base cost: 1 credit per successful inventory page or confirmed private result. no_cache=true, try_first_seven_days_blocked_items=true, steam_login_secure, or trade_url add +1 credit for a billable result. Fresh-fetch additions never stack, so the maximum price is 2 credits per request. Failed requests and non-authoritative success=false results cost 0; confirmed Steam HTTP 403 results use normal pricing.
Make your first request
Create a key in the dashboard, keep it in an environment variable, then send it as a Bearer token. A successful call returns one Steam page with assets and descriptions; continue with its cursor.
curl "/v1/inventory?steam_id=76561198000000000&game=cs2" \
-H "Authorization: Bearer $ITEMDATA_API_KEY"Keep the key server-side
Send your key in the Authorization header. Query-string keys are supported for compatibility, but Bearer authentication avoids leaking credentials into logs and browser history.
Authorization: Bearer isk_…Call ItemData from your backend, not public browser code.
/inventory
Fetch one inventory using a SteamID64, SteamID3, SteamID2, vanity name, or Steam Community profile URL.
Do not send last_assetid after a response with more_items=false: that response is terminal and has no next page.
API authentication is required through Authorization: Bearer or the legacy key query parameter. steam_id is required only when neither a Steam login cookie nor a trade URL supplies the target. Every other inventory query parameter is optional; defaults are documented below.
Each accepted query parameter may appear only once. Unknown parameters are rejected with HTTP 400 before credit reservation or any Steam request.
steam_idstringConditionally required. Accepts a SteamID64, SteamID3, SteamID2, vanity name, or Steam Community profile URL. Omit it when a Steam login cookie or trade URL supplies the target; it is ignored when either credential supplies it.gameenumOptional. One of cs2, rust, dota2, tf2, or pubg. dota is accepted as an alias for dota2. Defaults to cs2.languagestringOptional. Language requested from Steam for descriptions. Defaults to english.start_assetidstringOptional. Omit for the first page. For a later page, use the exact last_assetid cursor from the preceding response only when more_items is true.include_non_tradablebooleanOptional; defaults to false. Include assets that cannot currently be traded.no_cachebooleanBypasses the default 3-day shared cache and fetches fresh inventory data directly from Steam. Adds +1 credit to a billable request. Default: 0.try_first_seven_days_blocked_itemsbooleanCS2 only. Tries the trade inventory first to include 7–10 day trade-locked items, then falls back to the normal inventory when the partner path cannot return a usable first page. This may increase response time and failure rate. Adds +1 credit to a billable request. Default: 0.steam_login_securestringOptional. Preferred header: X-Steam-Login-Secure. A structurally valid cookie must contain its owner SteamID64. It is supported for every game; for CS2, it fetches that authorized owner's inventory without the normal 10-day visibility delay. It bypasses shared cache state. Additional cost: +1 credit for a billable result, including a confirmed Steam HTTP 403.trade_urlstringOptional. Preferred header: X-Steam-Trade-URL. CS2 only. Accepts a canonical HTTPS steamcommunity.com/tradeoffer/new/ URL with partner and token, derives the target from partner, includes 7–10 day trade-locked items, and bypasses shared cache state. Additional cost: +1 credit after success. It cannot be combined with try_first_seven_days_blocked_items.with_no_tradablealiasbooleanOptional; defaults to false. Equivalent switches for including non-tradable assets; if both are supplied, their values must match.formatenumOptional; defaults to json. Accepted values are json, prettyjson, or pretty. All variants return JSON.prettyaliasbooleanOptional; defaults to false. Set to true or 1 for indented JSON output; alias for a pretty format.X-ItemData-More-Itemsmore_itemsX-ItemData-Next-Cursorlast_assetidX-ItemData-CacheHIT, MISS, STALE, or BYPASS for the public page or account-wide private state returned.X-ItemData-Inventory-Sourcepublic for the normal endpoint, partner when the internal session pool succeeded, or public-fallback when the first partner page fell back to a fresh public request.AgeWhole seconds since the public page or confirmed private state was observed at Steam.X-ItemData-Billing-Statusconfirmed after durable accounting. A rare pending value means the successful payload is returned while an ambiguous database COMMIT is handled with at-most-once billing; charged-credit headers are then omitted.X-ItemData-Credits-ChargedActual total charged for a billable result: 1 base credit plus at most 1 fresh-fetch credit, with a maximum of 2. Present only for confirmed billing.X-ItemData-Credit-Pricing-VersionVersion of the server-side credit rules used for this request.Examples for every parameter
These examples cover every accepted inventory query parameter without combining incompatible modes. In Python, the GET query is passed as params=payload; it is not a JSON request body. Query payloads are serialized into the URL, so keep live secrets in environment variables and prefer the documented credential headers in production.
Public inventory with explicit options
cURL · public pageFetch a fresh Dota 2 page, include non-tradable items, choose the Steam response language, and request indented JSON.
keysteam_idgamelanguageinclude_non_tradableno_cacheformat
curl --fail-with-body --include --get \
-H "Authorization: Bearer $ITEMDATA_API_KEY" \
--data-urlencode "steam_id=76561198000000000" \
--data-urlencode "game=dota2" \
--data-urlencode "language=english" \
--data-urlencode "include_non_tradable=true" \
--data-urlencode "no_cache=true" \
--data-urlencode "format=prettyjson" \
"/v1/inventory"import os
import requests
payload = {
"key": os.environ["ITEMDATA_API_KEY"],
"steam_id": "76561198000000000",
"game": "dota2",
"language": "english",
"include_non_tradable": True,
"no_cache": True,
"format": "prettyjson",
}
response = requests.get(
"/v1/inventory",
params=payload,
timeout=30,
)
response.raise_for_status()
print(response.json())no_cache=true bypasses shared cache state. Additional cost: +1 credit for a billable result, including a confirmed Steam HTTP 403.
Next public page with compatibility aliases
cURL · next pageContinue the same Dota 2 inventory using the exact cursor returned by the previous response. Preserve every option that defines the page.
keysteam_idgamelanguagestart_assetidwith_no_tradablepretty
curl --fail-with-body --include --get \
-H "Authorization: Bearer $ITEMDATA_API_KEY" \
--data-urlencode "steam_id=76561198000000000" \
--data-urlencode "game=dota" \
--data-urlencode "language=english" \
--data-urlencode "start_assetid=$NEXT_CURSOR" \
--data-urlencode "with_no_tradable=true" \
--data-urlencode "pretty=true" \
"/v1/inventory"import os
import requests
payload = {
"key": os.environ["ITEMDATA_API_KEY"],
"steam_id": "76561198000000000",
"game": "dota",
"language": "english",
"start_assetid": os.environ["NEXT_CURSOR"],
"with_no_tradable": True,
"pretty": True,
}
response = requests.get(
"/v1/inventory",
params=payload,
timeout=30,
)
response.raise_for_status()
print(response.json())dota is an alias for dota2. with_no_tradable aliases include_non_tradable, and pretty=true aliases indented JSON output.
Try recently trade-blocked CS2 items first
cURL · blocked-item modeTry the internal Steam-session pool before a fresh public fallback. The mode automatically includes non-tradable items.
keysteam_idgamelanguagetry_first_seven_days_blocked_items
curl --fail-with-body --include --get \
-H "Authorization: Bearer $ITEMDATA_API_KEY" \
--data-urlencode "steam_id=76561198000000000" \
--data-urlencode "game=cs2" \
--data-urlencode "language=english" \
--data-urlencode "try_first_seven_days_blocked_items=true" \
"/v1/inventory"import os
import requests
payload = {
"key": os.environ["ITEMDATA_API_KEY"],
"steam_id": "76561198000000000",
"game": "cs2",
"language": "english",
"try_first_seven_days_blocked_items": True,
}
response = requests.get(
"/v1/inventory",
params=payload,
timeout=30,
)
response.raise_for_status()
print(response.json())Additional cost: +1 credit for a billable result, including a confirmed Steam HTTP 403 from public fallback. For the next cursor, retain this flag only after X-ItemData-Inventory-Source: partner; omit it after public-fallback.
Inventory authorized by steamLoginSecure
cURL · caller Steam sessionFetch the cookie owner's inventory. The owner SteamID64 is read from the cookie, so steam_id is not required and would be ignored.
keysteam_login_securegamelanguageformatX-Steam-Login-Secure
curl --fail-with-body --include --get \
-H "Authorization: Bearer $ITEMDATA_API_KEY" \
-H "X-Steam-Login-Secure: $STEAM_LOGIN_SECURE" \
--data-urlencode "game=rust" \
--data-urlencode "language=english" \
--data-urlencode "format=json" \
"/v1/inventory"import os
import requests
payload = {
"key": os.environ["ITEMDATA_API_KEY"],
"steam_login_secure": os.environ["STEAM_LOGIN_SECURE"],
"game": "rust",
"language": "english",
"format": "json",
}
response = requests.get(
"/v1/inventory",
params=payload,
timeout=30,
)
response.raise_for_status()
print(response.json())Repeat X-Steam-Login-Secure on every cursor request. This fresh BYPASS mode supports every listed game. Additional cost: +1 credit for a billable result, including a confirmed Steam HTTP 403.
CS2 inventory authorized by a Trade URL
cURL · Trade URLFetch the partner inventory through the authenticated trade path. The target SteamID64 is derived from partner, so steam_id is not required and would be ignored.
keytrade_urlgamelanguageformatX-Steam-Trade-URL
curl --fail-with-body --include --get \
-H "Authorization: Bearer $ITEMDATA_API_KEY" \
-H "X-Steam-Trade-URL: $STEAM_TRADE_URL" \
--data-urlencode "game=cs2" \
--data-urlencode "language=english" \
--data-urlencode "format=json" \
"/v1/inventory"import os
import requests
payload = {
"key": os.environ["ITEMDATA_API_KEY"],
"trade_url": os.environ["STEAM_TRADE_URL"],
"game": "cs2",
"language": "english",
"format": "json",
}
response = requests.get(
"/v1/inventory",
params=payload,
timeout=30,
)
response.raise_for_status()
print(response.json())Repeat X-Steam-Trade-URL on every cursor request. This mode is CS2-only and never falls back to the public endpoint. Additional cost: +1 credit after success.
Legacy credential query forms
Reference only · do not executeSyntax reference only. These aliases remain compatible, but credentials in URLs can leak through history and access logs.
keysteam_login_securetrade_url
GET /v1/inventory?key=REDACTED_NON_WORKING_KEY&steam_login_secure=REDACTED_NON_WORKING_COOKIE
GET /v1/inventory?key=REDACTED_NON_WORKING_KEY&trade_url=REDACTED_NON_WORKING_URLimport requests
# Syntax reference only: replace these values through your secret manager.
payload = {
"key": "REDACTED_NON_WORKING_KEY",
"steam_login_secure": "REDACTED_NON_WORKING_COOKIE",
"game": "cs2",
}
response = requests.get(
"/v1/inventory",
params=payload,
timeout=30,
)
print(response.status_code)Use Authorization: Bearer, X-Steam-Login-Secure, and X-Steam-Trade-URL in production. Never place live credentials in a URL.
Try the endpoint
Enter your own key to send a real request. The key stays in this page's memory and is never saved by the explorer.
{
"success": true,
"steam_id": "76561198000000000",
"game": "cs2",
"appid": 730,
"total_inventory_count": 184,
"items": [
{
"assetid": "34589211402",
"market_hash_name": "AK-47 | Slate (Field-Tested)",
"tradable": true
}
],
"last_assetid": "34589211402",
"more_items": true
}Compatible where semantics stay honest
ItemData accepts SteamWebAPI-style parameters when their semantics match, including no_cache=true for a forced public refresh. It rejects or omits only unsupported enrichment and global operations.
Open the SteamWebAPI inventory referenceSupported compatibility
start_assetidLive Steam cursor from last_assetid, valid only while more_items is true.include_non_tradable / with_no_tradableEquivalent switches for including non-tradable assets; if both are supplied, their values must match.pretty=1Returns indented JSON; the response format remains JSON.game=dotaAccepted as an alias for dota2.steam_login_secure / X-Steam-Login-SecureOptional. Preferred header: X-Steam-Login-Secure. A structurally valid cookie must contain its owner SteamID64. It is supported for every game; for CS2, it fetches that authorized owner's inventory without the normal 10-day visibility delay. It bypasses shared cache state. Additional cost: +1 credit for a billable result, including a confirmed Steam HTTP 403.trade_url / X-Steam-Trade-URLOptional. Preferred header: X-Steam-Trade-URL. CS2 only. Accepts a canonical HTTPS steamcommunity.com/tradeoffer/new/ URL with partner and token, derives the target from partner, includes 7–10 day trade-locked items, and bypasses shared cache state. Additional cost: +1 credit after success. It cannot be combined with try_first_seven_days_blocked_items.no_cacheSupported for public inventories. true forces a fresh upstream fetch. Additional cost: +1 credit for a billable result, including a confirmed Steam HTTP 403.try_first_seven_days_blocked_itemsSupported for CS2. On a partner response, continue with the flag and returned cursor. After public-fallback, continue with the public cursor without this flag.Not supported
stateItemData does not expose an alternate inventory-state selector.parse, raw, mode, currency, markets, with_prices, phase, sort-by-priceItemData does not perform price, float, or market enrichment.offset, search, group, selectThese would require global semantics across multiple live cursor pages, so ItemData does not promise them.other blocked modesUse trade_url for an authorized CS2 trade partner, steam_login_secure for the cookie owner, or the explicit try_first_seven_days_blocked_items mode. Other blocked-inventory selectors are rejected.Responses are JSON only; XML and other output formats are not supported.
Filtering, grouping, selecting, or offsetting one live page would produce misleading results for the full inventory. Fetch pages by cursor and apply global operations only after collecting them.
Supported economies
cs2Counter-Strike 2730 / 2dota2Dota 2570 / 2rustRust252490 / 2tf2Team Fortress 2440 / 2pubgPUBG: BATTLEGROUNDS578080 / 2Errors you can act on
Every error uses the same envelope with a stable machine-readable code and a human-readable message.
invalid_request / invalid_steam_idA query parameter or Steam identifier is missing, unsupported, or malformed.missing_api_key / invalid_api_keyThe API key is missing or invalid.insufficient_creditsThe account does not have enough credits.inactive_api_key / plan_expiredThe key has been revoked or disabled, or its assigned plan has expired.rate_limit_exceededThe Steam account's shared fixed-window minute, UTC-day, or UTC-month request limit has been exceeded. All replicas and rotated keys share these counters; honor Retry-After.invalid_upstream_response / upstream_error / pagination_limitSteam returned an invalid or unexpected response, or the response exceeded a safety limit.cache_unavailable / refresh_in_progress / upstream_unavailable / rate_limiter_unavailableA refresh is already in progress or a dependency is temporarily unavailable; honor Retry-After before retrying.upstream_timeoutThe upstream request exceeded its deadline.