API
API changes

6 October 2026

Listings no longer stack. Every listing holds one copy.

Open raw markdownFor pasting into AI assistants

Listings no longer stack. Every copy of an item for sale is its own listing, with its own listing_id, and amount on a listing is always 1. A commodity with 40 copies for sale appears as 40 listings.

Why: a stacked listing mixed copies that could differ, for example in trade lock, and could not be bought, repriced or tracked one at a time. With one copy per listing, every purchase, edit and WebSocket event refers to exactly one copy, so there are no partial fills, stack splits or amount edits to reconcile.

The release runs under maintenance mode: authenticated REST calls return 503 MAINTENANCE_MODE until it ends, while the WebSocket stays up. During maintenance every existing stacked listing is split into single-copy listings and the WebSocket feed announces it: listing.amount_changed with new_amount: 1 for each original listing, and listing.created for each new copy. The new copies keep the original listing's created_at, so these listing.created events can carry old timestamps. Private listings are split without events. Once maintenance ends, resync your local book from GET /public/v1/book to be safe.

What you need to do

  1. Resync after maintenance. Rebuild your local book from GET /public/v1/book, and refetch your own listings from GET /public/v1/my-listings.
  2. Keep every listing_id. Listing and selling create one listing per copy, and POST /public/v1/list returns all of them. Store every id, not just the first.
  3. Stop sending amount on edits. PATCH /public/v1/list no longer accepts amount and fails with BAD_REQUEST if you send it. To sell more copies list them; to sell fewer, delist them.
  4. Buy several copies with several lines. On POST /public/v1/purchase every line's amount must be 1; send one line per listing. amount above 1 is rejected, normally with LISTING_OUT_OF_STOCK.
  5. Expect LISTING_NOT_FOUND when you lose a race. A sold copy's listing is gone, so buying, repricing or delisting it returns LISTING_NOT_FOUND.
  6. Use the bulk forms for many copies. Send listing_ids to reprice up to 500 listings at one price, or to delist up to 500 at once.
  7. Check your bulk error handling. A bulk delist or reprice is all or nothing, and the error does not say which id failed. If a copy sold since you read your listings, refetch them and retry with the ids still there.
  8. Handle LISTING_DISABLED. Listing can now be switched off site-wide. While it is off, listing, repricing and delisting fail with 503 LISTING_DISABLED; retry later.

Changed

AreaBeforeNow
Listing amountNumber of copies in the stackAlways 1
POST /public/v1/listOne listing per groupOne listing per copy; the response lists every listing created
POST /public/v1/sellOne listing per group once the trade is acceptedOne listing per copy
PATCH /public/v1/listEdits price and amount; lowering amount with a new price split the stackEdits the price only, with price or price_decay as before
POST /public/v1/delist bulkUp to 50 ids, each removed on its own with a per-id ok / errorUp to 500 ids in one transaction: if any id is missing (LISTING_NOT_FOUND) or not yours (FORBIDDEN), the call fails and nothing is removed, without saying which id. On success every id comes back with ok: true
POST /public/v1/purchaseA line could buy several copies of a stackEvery line buys one listing; amount must be 1
POST /public/v1/purchase losing a raceUsually LISTING_OUT_OF_STOCK, while the stack still had copies leftLISTING_NOT_FOUND: a sold copy's listing is removed. LISTING_OUT_OF_STOCK now only means a line asked for more than 1
GET /public/v1/my-listingsOne row per stackOne row per copy. On commodities, available_amount is how many more copies you could list from your backpack; otherwise 0
GET /public/v1/my-listings/valuelisting_count up to item_countlisting_count equals item_count
GET /public/v1/book and GET /public/v1/listingsOne row per stackOne row per copy, so payloads are larger for commodity-heavy games
GET /public/v1/prices/alllisting_count up to stocklisting_count equals stock
WebSocket listing.amount_changedAny stock changeSent when a listing sells (new_amount: 0), and once with new_amount: 1 per split listing during this release
WebSocket listing.createdNot sent for listings created from a Steam sellSent for every public listing, including those created when a Steam sell trade is accepted
WebSocket listing.price_changedNot sent when an auto-decaying price droppedSent for every price change, including each auto-decay step

Event volume rises with the number of copies. Listing and selling send one listing.created per copy; buying sends one listing.amount_changed and one listing.sold per copy; delisting sends one listing.removed per copy; a bulk reprice sends one listing.price_changed per listing whose price changed.

Added

AreaWhat
PATCH /public/v1/listA listing_ids form: up to 500 listings, each id once, set to one price or price_decay in one transaction. Fails as a whole if any id is missing, not yours, not active or below the item's minimum price. Returns { listings }
LISTING_DISABLED error503 from POST /public/v1/list, PATCH /public/v1/list and POST /public/v1/delist while listing is switched off site-wide. The bulk listings form of PATCH /public/v1/list reports it per row in results instead

Removed

AreaWhat
PATCH /public/v1/listThe amount field, and with it the partial reprice that split a stack