Skip to content
API

Steam 429 handling

Steam inventory 429 handling for production clients

WOK separates client-plan rate limits from Steam upstream availability. A cache hit avoids duplicate Steam work but still consumes the API operation/rate quota; native upstream capacity can be reported as status=limited while the HTTP response is 200.

GET /v1/inventoryBearer authentication

Updated

curl
curl --fail-with-body --max-time 35 \
  -H "Authorization: Bearer $WOK_API_KEY" \
  "https://woksteamapi.com/v1/inventory?steam_id=76561198090744629&game=cs2"
Cache firstreuse a fresh snapshot
Singleflightcoalesce concurrent misses
Bounded retrycap attempts and total time
Status awareseparate WOK 429 from Steam limited

Decide from both HTTP status and inventory outcome

The examples below make one request and never retry silently. JavaScript and Python accept only status=ok or status=empty as a successful inventory. curl prints the body for inspection: --fail-with-body detects HTTP errors, not an unavailable inventory inside HTTP 200.

ResponseWhat it meansNext action
HTTP 200, ok or emptyA successful inventory observation.Use the result with its cache age and unpriced coverage. An observed empty inventory is different from a failed lookup.
HTTP 200, private or notfoundInventory data is unavailable for this request.Show the explicit outcome. Do not retry in a tight loop or replace an earlier value with zero.
HTTP 200, limited or errorTemporary upstream capacity or a failed inventory read.Keep any last successful observation visibly dated. Schedule a later read only within your application's attempt and elapsed-time budget.
HTTP 429 from this native routeWOK key minute-window admission was refused.Wait at least Retry-After when supplied; WOK sends delta seconds here. Inspect X-RateLimit-Reset and reduce request concurrency. A compatibility route's upstream 429 is a separate case.
HTTP 400 / 401 / 402 / 403 / 404 / 422Invalid input, authentication, exhausted quota, access or route availability.Correct the request or access issue. Use GET /v1/key for effective quota and reset times; repeating an unchanged request does not repair it.
HTTP 502 / 503An upstream or local dependency failed or was unavailable.Inspect the documented error. The HTTP code alone does not prove that Steam returned the same code. Avoid an immediate retry burst.
Invalid JSON or an unknown inventory outcomeThe client cannot validate the response.Stop and report unavailable data. Do not invent an empty inventory or a successful zero-value result.

If your application adds retries, cap both attempts and total elapsed time, use jitter across concurrent clients and honor any supplied Retry-After as a minimum. If that wait exceeds the remaining budget, stop and return control to your scheduler; do not shorten it. A later normal inventory read can use another WOK quota unit and trigger source work on a cache miss, so a retry is not a free recovery operation.

Endpoint error referenceCache-first polling and price-only refreshSDKs without automatic retriesNative inventory outcome map

Quickstart

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

Set WOK_API_KEY on your server. Use Node.js 18+ for the JavaScript example, or install requests for Python. These examples send one request with redirects disabled. The Python connect/read timeouts are per-operation limits, not a whole-flow deadline. Read the retry decision table before adding a scheduler or reusing a failed result.

curl
curl --fail-with-body --max-time 35 \
  -H "Authorization: Bearer $WOK_API_KEY" \
  "https://woksteamapi.com/v1/inventory?steam_id=76561198090744629&game=cs2"
JavaScript (Node.js)
// Node.js 18+: one request; let your scheduler decide when to try again.
const key = process.env.WOK_API_KEY;
if (!key) throw new Error("Set WOK_API_KEY on your server");
const url = "https://woksteamapi.com/v1/inventory?steam_id=76561198090744629&game=cs2";
const response = await fetch(url, {
  headers: {Authorization: `Bearer ${key}`},
  redirect: "error",
  signal: AbortSignal.timeout(35_000)
});
if (!response.ok) {
  await response.body?.cancel();
  throw new Error(`WOK HTTP ${response.status}; no automatic retry`);
}
let inventory;
try { inventory = await response.json(); }
catch { throw new Error("Invalid inventory JSON"); }
const outcomes = ["ok", "empty", "private", "notfound", "limited", "error"];
if (!inventory || Array.isArray(inventory) ||
    !outcomes.includes(inventory.status) || !Array.isArray(inventory.items)) {
  throw new Error("Invalid inventory response");
}
if (!["ok", "empty"].includes(inventory.status)) {
  throw new Error(`Inventory unavailable: ${inventory.status}; no automatic retry`);
}
console.log(inventory);
Python
import json
import os
import requests

url = "https://woksteamapi.com/v1/inventory"
with requests.get(
    url, headers={"Authorization": f"Bearer {os.environ['WOK_API_KEY']}"},
    params={"steam_id": "76561198090744629", "game": "cs2"},
    timeout=(5, 30), allow_redirects=False,
) as response:
    if not 200 <= response.status_code < 300:
        raise RuntimeError(f"WOK HTTP {response.status_code}; no automatic retry")
    try:
        inventory = response.json()
    except ValueError:
        raise RuntimeError("Invalid inventory JSON") from None
    outcomes = ("ok", "empty", "private", "notfound", "limited", "error")
    if (not isinstance(inventory, dict) or inventory.get("status") not in outcomes
            or not isinstance(inventory.get("items"), list)):
        raise RuntimeError("Invalid inventory response")
    if inventory["status"] not in ("ok", "empty"):
        raise RuntimeError(
            f"Inventory unavailable: {inventory['status']}; no automatic retry")
print(json.dumps(inventory))

Response example

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

JSON

application/json
HTTP 429 (WOK key rate limit)
Content-Type: application/json
Cache-Control: no-store
Retry-After: 17
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1787252400

{"error":"rate limit exceeded","status":429}

HTTP 200 (native Steam capacity outcome)
Cache-Control: private, no-store

{"status":"limited","meta":{"cache_ttl":0}}

Response schema

Stable fields for typed clients, storage and error handling.

Steam inventory 429 handling for production clients response schema
FieldTypeMeaning
HTTP statusintegerFor this native route, 429 means WOK key minute-window admission was refused; exhausted daily or period quota is 402. Upstream capacity is HTTP 200 with status=limited.
statusstringNative inventory outcome; limited means temporary upstream capacity.
Retry-AfterheaderMinimum wait when supplied. A WOK minute-limit response supplies delta seconds; do not shorten that delay to fit a local retry budget.
errorstring/objectAdmission error text or a structured endpoint error. Use HTTP status and documented fields, not matching translated prose.
X-Wok-Cache-AgeheaderAge when the corresponding inventory result path supplies it.
X-Wok-Cache-TTLheaderFreshness window when the corresponding inventory result path supplies it.

Limits and error behavior

Rules clients should handle explicitly in production.

No service can guarantee that Steam will never rate-limit an inventory request. WOK can reduce duplicate upstream work, not change Steam's external availability.

A 429 from your WOK plan requires backoff. Native temporary upstream capacity is returned as HTTP 200 status=limited and also requires backoff; treat Retry-After as the minimum wait when the response includes it.

Retry only idempotent reads, cap the attempt count and add jitter in high-concurrency systems. Do not retry 400, 401, 402, 403 or 404.

no_cache=1 deliberately bypasses a reusable snapshot and can increase upstream work; reserve it for explicit refresh actions.

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.

Cache-Control is private, no-store, so shared intermediaries must not reuse user-specific inventory bodies. WOK's server-side cache is described by the X-Wok headers instead.

A cache hit still counts as a WOK API operation and rate-limit unit even though it avoids another Steam request.

Frequently asked questions

Direct answers about access, freshness and result semantics.

Can any API guarantee no Steam 429 responses?

No. Caching, singleflight and bounded retries reduce duplicate upstream work, but they cannot change Steam's external availability.

Should clients retry every error?

No. Retry temporary 429 or limited outcomes with a cap and jitter. Do not retry validation, authentication, payment or not-found responses as a burst.