# Runnable WOK API examples

Browse the [public examples repository](https://github.com/woksteamapi/wok-api-examples)
for these clients, offline fixtures and a CI template. The repository contains examples
only; the included license states their usage terms.

Download [steam-faceit.py](https://woksteamapi.com/api/examples/steam-faceit.py)
and [inventory-stream.mjs](https://woksteamapi.com/api/examples/inventory-stream.mjs).
Both use built-in libraries, a key held in your server environment and the public
WOK endpoints. They stop on errors and never automatically retry a request.

```bash
export WOK_API_KEY='replace-with-your-key'
python3 steam-faceit.py 76561198009000000 --stats
node inventory-stream.mjs --steamids 76561198009000000 --games cs2,dota2 --output ./inventories.ndjson
```

Use Python 3.10+ or Node.js 18+. Keep the key on your server; never put it in a
browser, public URL, source file or bot message. Both clients use
`https://woksteamapi.com`, reject redirects and suppress error response bodies
and transport details in diagnostics. A key needs access to every requested
endpoint. [GET /v1/key](https://woksteamapi.com/docs) reports key limits and
capabilities without consuming quota; technical support does not grant access.

## Steam profile → FACEIT CS2

The Python CLI reads `GET /v1/profile?steam_id=...`, then
`GET /faceit/data/v4/players?game=cs2&game_player_id=...`. With `--stats`, it
uses the returned FACEIT `player_id` for
`GET /faceit/data/v4/players/<player_id>/stats/cs2`. It writes one JSON object
with the Steam profile and the FACEIT profile, plus optional `lifetime`.
Without `--stats`, there are two requests; with it, at most three. Each admitted
request costs one WOK unit, including cached reads.

A FACEIT profile 404 preserves the Steam profile and emits
`"faceit":{"status":"unavailable","profile":null}` with exit status 0.
It skips statistics in that case. Authentication, quota, source and malformed
response failures exit nonzero. A statistics 404 preserves both profiles and
adds `lifetime:null` with `lifetime_status:"unavailable"`. Empty lifetime data
remains `{}` with `lifetime_status:"empty"`; populated lifetime data is marked
`"available"`. Absent
ELO, rank or metrics remain absent. Numeric lifetime metrics remain strings.
Profile and lifetime caches can lag live matches; fetch time is not source
observation time. Treat returned names and URLs as untrusted data in a UI.
Each network request has a 35-second deadline, a 5-second connection timeout
and a 1 MiB response limit. See the [FACEIT guide](https://woksteamapi.com/faceit)
and [Steam profile guide](https://woksteamapi.com/steam-profile-api).

## Persist a progressive inventory batch

The Node CLI first checks `GET /v1/key` for the documented version 1 capability,
then sends exactly one `POST /v1/inventories/stream`. It accepts 1–20 unique
SteamIDs and 1–4 canonical game keys, deduplicating input in first-seen order.
Games are `cs2`, `dota2`, `rust`, `tf2`, `pubg`, `sandbox`, `unturned`, `payday2`.
The server atomically reserves one existing `/v1/inventories` unit per pair
before accepting the batch. Check access and quota separately from capability.
There is no fallback to another route and no automatic replay, including when
the connection fails before an `accepted` record is visible.

Summary mode is the default (`include_items:false`, `top:0`). Add
`--include-items` for complete item arrays. Summary reduces response transfer
and encoding work; Steam inventories are still fetched and materialized fully.
Use complete items when applying several predicates to the same item; a top-N
projection cannot prove whole-inventory matches.

`--output` must name a new file. It is created exclusively with permissions
`0600`, and every verified accepted/inventory line is written and synced before
the next line is consumed. Transport chunks may split JSON or UTF-8 anywhere.
The client checks request IDs, player-major/game-minor indices, inner and outer
pair identities, duplicates and final counts. It accepts exactly one consistent
complete record and writes that record only after EOF. A complete stream may
still contain failed pairs; inspect each result's `ok`, `http_status` and
structured `error.retry_after` / `error.source_scope`. Unknown source scope or
cooldown remains unknown; do not derive it from error text.

Exit status 0 and the JSON summary on stdout confirm full delivery. A truncated,
malformed, oversized or inconsistent stream exits nonzero and leaves verified
lines in the output file. **Keep those lines.** Missing/transient pairs can be
requested deliberately later; those are new charged requests, may repeat work
whose delivery was lost and have no durable replay token or automatic refund.
The example enforces the advertised line cap (at most 4 MiB), at most 82 records,
a bounded pending buffer and 35-second deadlines for preflight and streaming.
Cache age, queue time, transport time and your processing time all consume
remaining snapshot freshness; repricing does not renew it. See the
[stream guide](https://woksteamapi.com/steam-inventory-api) and
[API reference](https://woksteamapi.com/docs).

## Offline fixtures

For a local stub only, append `--local-base http://127.0.0.1:PORT` (or literal
IPv6 `http://[::1]:PORT`) and set a dummy `WOK_API_KEY` starting `local-test-`.
Only loopback IPs with an explicit port are accepted. Real keys are rejected
for local fixtures. Arbitrary hosts and capability-supplied URLs never receive
the credential. Do not point these examples at an untrusted local service.


## Resolve a Steam profile and read public name history

Download [steam-aliases.mjs](https://woksteamapi.com/api/examples/steam-aliases.mjs).
This server-side Node.js 18+ example accepts a SteamID64, public profile URL or
vanity name, resolves `GET /v1/profile`, then passes the returned numeric ID to
`GET /v1/aliases`. The WOK key remains in `WOK_API_KEY`; do not use a Valve key.

```bash
export WOK_STEAM_PROFILE="https://steamcommunity.com/id/your-profile/"
node steam-aliases.mjs
```

The complete flow has a 35-second deadline, a 256 KiB limit per response,
no automatic retries and at most two requests. Each admitted request uses one
WOK unit, including cache hits. Missing aliases do not establish that a player
never changed names. Alias dates are original opaque Steam Community text or
null; do not invent a timezone or recover cleared aliases. Returned names and
URLs need escaping before insertion into a UI. Read the
[name-history workflow](https://woksteamapi.com/steam-profile-name-history#alias-profile-workflow)
for error handling and public-data limits.

## Offline inventory contract exercise

Save both [inventory-contract-check.py](https://woksteamapi.com/api/examples/inventory-contract-check.py)
and [inventory-contract-fixtures.json](https://woksteamapi.com/api/examples/inventory-contract-fixtures.json)
in one directory, then run:

```bash
python3 inventory-contract-check.py
```

This Python 3.10+ teaching exercise uses only the standard library. It reads a
bounded local JSON file; it needs no API key, performs no network calls, writes
no files and spends no quota. All twelve example cases and identities are
fictional. Do not send those identities to an API.

It covers native HTTP 200 private/error states, compatibility arrays and HTTP
errors, observed empty versus unavailable inventories, `count`-weighted
sellable USD totals, null prices, independent inventory/price timestamps and a
partial batch that preserves successful peers. Missing prices keep the full
value unknown even when a known subtotal exists. Market-name quotes do not
include individual float, seed or attachment premiums.

You can pass the path to an edited copy of the synthetic pack to test an
inconsistent interpretation. This is a small declared subset for full grouped
USD rows and batch `include_items:true`, not a complete JSON Schema validator,
benchmark, current price feed or guarantee of another provider's compatibility.
The [migration checks](https://woksteamapi.com/migration#validation) explain the
next step: saved-response tests for your parser, then bounded live comparisons
with identical players, games, price sources and freshness.

## Read bounded CS2 Market listing pages

Download [cs2-market-listings.mjs](https://woksteamapi.com/api/examples/cs2-market-listings.mjs).
Use Node.js 18+ and a server-held WOK key with the Inspect add-on:

```bash
export WOK_MARKET_NAME="AK-47 | Redline (Field-Tested)"
node cs2-market-listings.mjs
```

The complete flow has a 75-second deadline, a 1 MiB limit per response and at
most three authenticated WOK GET requests. It rejects redirects and never
automatically retries. Normal access and quota apply; this request cap does
not promise only three underlying Steam requests. No packages are needed.

The client preserves separate page observations and original partial coverage.
A page limit leaves later offers unread. Empty exact-name results on a page
can still have a continuation; unsupported, inconsistent or nonadvancing
cursors stop before another request. It never invents an offset. A later
error exits unsuccessfully while preserving previously validated pages in
`MarketListingsError.pages` or the CLI's `stopped_because:"error"` output.

Listing and asset IDs stay strings; unavailable floats stay null. Price fields
remain in the returned Steam currency's minor units. No USD conversion,
cross-currency total or individual premium is inferred. Read the
[listing workflow](https://woksteamapi.com/cs2-float-api#bounded-market-client)
for snapshot limitations and the complete field contract.
