Fixes
Purchases that time out now answer504, not 500. When a marketplace stops responding mid-purchase the outcome is genuinely unknown — the buy may still have completed. POST /market/buy and POST /orders now return 504 upstream_timeout for that case and say so explicitly.Crucially, the idempotency claim is held instead of released. Re-sending the identical custom_id / Idempotency-Key replays the original outcome rather than buying a second time; a retry sent while the original is still unresolved returns 409 idempotency_in_progress. Poll the order list before treating a 504 as a failure. Deterministic errors (price moved, insufficient balance, item unavailable) are unchanged.Lost concurrency races answer 409 concurrent_update. When two orders touch the same items at the same instant the loser’s transaction is rolled back whole — nothing charged, nothing reserved. That used to surface as 500; it is now a 409 with Retry-After, because retrying is exactly the right move.New features
Stop polling for new listings — subscribe to themUntil today the only way to notice new inventory was to pollGET /v1/listings harder, and that cost does not divide across clients: ten integrators at 300 requests/minute is ten separate deep scans of the same table returning almost identical rows. Worse, the thing everyone was polling could not answer the question — sort=newest ordered by when the row was created, so items returning to the catalogue from cancelled orders, expired trade offers and released holds never surfaced at the top, no matter how fast anyone polled.Three additions, all backward compatible:- New endpoint
GET /v1/listings/stream— Server-Sent Events. One connection replaces any polling loop, and it emitsgoneevents as well asnewones. That second half is what polling cannot express: a poller only discovers an item sold by trying to buy it and failing. Reconnects are gap-free via the standardLast-Event-IDheader, including across our deploys. - New query parameter
available_afteronGET /v1/listings— turns a poll into a delta read. The usual response is an empty page. Overlap your watermark by ~60 seconds and dedupe byid; the parameter docs explain why that overlap is not optional. - New field
listed_aton everyListing— when the item entered the catalogue, which is whatsort=newestnow orders by. Re-listings surface alongside genuinely new inventory.
sort=newest keeps its name and its ordering direction, it simply stopped hiding re-listings.Fixes
Corrected rate limits in the docsThe published limits were wrong in the direction that costs you throughput: pointed reads are 100 requests/minute, not 30, andPOST /v1/orders is 250/minute, not 30. If you sized your client against the old numbers, you have more headroom than you thought — and if you were about to ask for a raise, try available_after or the stream first.New features
Refunds are now explicit — no more guessingAn order that endscancelled or failed has always been refunded in full, usually within seconds. The API just never said so, which left clients rendering “refund pending” against orders that were already settled. Two additions fix that:- Every order — in
GET /v1/orders,GET /v1/orders/{id}andGET /v1/orders/info— now carries arefundobject:amount_usd,refunded_at, andpartial(true when only one leg of a multi-item order came back). It isnullwhen nothing was refunded. - New endpoint
GET /v1/transactions— your full balance ledger, keyset paginated:purchase,refund,sale,deposit,withdrawal,bonus,fee,adjustment. A purchase and the refund that reversed it share the sameorder_id, so an end-of-day reconciliation is one pass over this feed.
status vocabulary is unchanged, so existing integrations keep working untouched.New features
Instant Sell API (invite-only)Sell CS2 skins programmatically through the CSBoard bot network. Quote a Steam inventory, create a sell order, and funds settle to your CSBoard balance once Steam’s trade-protection hold clears (~8 days).- Quote any Steam inventory with
POST /v1/sell/quotes— every eligible item comes back with the exact USD amount you’ll be credited. - Create orders with
POST /v1/sell/orders, with optionalmin_total_usdprice-drift protection andexternal_ididempotency. - Track lifecycle (
pending→offer_sent→received→completed) and settled amounts withGET /v1/sell/orders/:id. Large baskets can split across up to 3 bots. - Every offer exposes the sending bot’s Steam profile and
trade_offer_idso you can render anti-impersonation checks to sellers. - Access is granted per-account — call
GET /v1/sell/statusto check, and contact support to request access.
Fixes
Precise 402 error codes onPOST /v1/market/buyThe endpoint now distinguishes the two out-of-funds cases instead of always returning insufficient_settled_balance:insufficient_balance— the account balance is simply lower than the order total. Top up and retry.insufficient_settled_balance— the balance covers the total, but part of it is still inside the reversal window and cannot fund external delivery yet.
balance_usd alongside required_usd and settled_usd, so a bot can tell the cases apart programmatically. If your integration matched on the insufficient_settled_balance code for generic low-funds handling, match on HTTP 402 instead.Held orders also gained a small post-unlock grace before claimable flips to true — claiming at the exact unlock instant previously failed on the marketplace side.New features
Claim held orders over the APIOrders that land under a marketplace hold (status: "hold" with a hold_until timestamp) can now be released programmatically. Once hold_until passes, call POST /v1/orders/:id/claim to release the order. After a successful claim the marketplace sends a Steam trade offer your bot must accept within ~15 minutes. Some held orders deliver automatically, in which case the call is a harmless no-op.autoclaim account settingSet autoclaim: true on POST /v1/orders or POST /v1/market/buy and every held order is released automatically the moment its hold clears — no per-order call required. The flag is sticky at the account level.Exact name filter on listings and pricesPass a name query parameter to GET /v1/listings or GET /v1/prices to fetch a single item by its exact market_hash_name (case-insensitive). Unlike search, which does fuzzy word matching and can collide on overlapping titles (for example, Spectrum Case vs Spectrum 2 Case), name returns only the item you asked for. When both parameters are supplied, name takes precedence — no more post-filtering the response.See Market Data for usage examples.