Skip to main content

New features

Buy Dota 2 and Rust with delivery to any trade URLPOST /v1/market/buy now takes appId in the body, like POST /v1/orders: 570 for Dota 2, 252490 for Rust. Leave it out and the endpoint buys CS2, as before.
  • Payment and delivery work as they do for CS2: settled balance only, and the skins go to the trade URL built from partner + token.
  • A Dota 2 or Rust order takes up to 10 ids. More answers 400 too_many_items.
  • Dota 2 and Rust orders are queued, so every skin answers pending first. Follow the order with GET /v1/orders/info or the order.updated webhook.

New features

Instant Sell for Dota 2 and Rust, and sales across several offers
  • POST /v1/sell/quotes and POST /v1/sell/orders take app_id: 730 CS2 (the default), 570 Dota 2, 252490 Rust. A game your key cannot sell answers 422 unsupported_game with supported_app_ids. Quote items and orders carry app_id.
  • New split flag. Leave it false and the sale ships as one trade offer, to the market that leaves the seller the most value. Set it true and every item goes to the market that pays the most for it, which can mean several offers. Quote items carry offer_group (a, b, and so on) so you know how many offers to expect.
  • Orders now carry trade_offer_ids, an offer_group on each offer and a status on each item. The sell.updated webhook sends the same object.
  • Credit timing per game: CS2 about 7 days after the seller accepts, Dota 2 7 days after the seller accepts, Rust as soon as the market confirms. See when the money arrives.
  • min_total_usd is now checked against the total the order actually books, after the items are grouped into offers. Below it, the order is refused with 409 price_drift.
  • The Instant Sell endpoints have their own pages in the API reference, including GET /v1/sell/orders with list mode and pagination.
Webhooks for sales, withdrawals and depositsThe webhooks guide now documents sell.updated, withdrawal.updated and deposit.updated with their payloads.

New features

Dota 2 and Rust over the same API — choose the game with appIdCSBoard now sells Dota 2 and Rust items as well as CS2, and the API reaches them through one new parameter. Pass Steam’s appId — 570 for Dota 2, 252490 for Rust — and the endpoint answers for that game. Leave it out and you get CS2, byte for byte as before.
  • appId works on GET /v1/listings, GET /v1/prices and GET /v1/listings/availability as a query parameter, and on POST /v1/orders as a body field.
  • Dota 2 and Rust rows have the same keys as CS2 rows. The CS2-only fields are null and stickers is [], so one parser reads all three games.
  • CS2-only filters (wear, min_float, max_float, stat_trak, souvenir, available_after, sort=newest) sent with another game answer 400 invalid_param instead of being silently ignored.
  • An appId your key cannot use answers 400 unsupported_game with supported_app_ids. New endpoint GET /v1/games lists the games your key can read and whether it can buy there.
  • Dota 2 and Rust orders answer delivery: "pending" and expected_minutes: null.
The SSE stream, the bulk snapshot and POST /v1/market/buy stay CS2 only.A keyless price feed: GET /v1/public/pricesGET /v1/public/prices returns one cheapest ask per market_hash_name for CS2, Dota 2 or Rust. It needs no API key and no balance. CS2 Doppler phases are merged into Steam’s base name, so every key matches a real Steam name. The feed is rebuilt once a minute and limited to 1 request per minute per IP.List your own skins on the P2P market from the API — freeFive new endpoints let a key put its owner’s CS2 items up for sale on the CSBoard P2P market. No balance requirement and no trading permission — any valid key works.The website’s seller rules apply unchanged, and a sold item still has to be sent through Steam and confirmed with Steam Guard before the payout reaches your balance. One deliberate difference: a price under half of our market price is refused with 422 price_below_market. Over a key it cannot be confirmed past, so a leaked key cannot dump your inventory. Writes are limited to 30 per minute per key. The P2P listing guide walks through the whole flow.

Fixes

Purchases that time out now answer 504, 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 poll GET /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 emits gone events as well as new ones. 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 standard Last-Event-ID header, including across our deploys.
  • New query parameter available_after on GET /v1/listings — turns a poll into a delta read. The usual response is an empty page. Overlap your watermark by ~60 seconds and dedupe by id; the parameter docs explain why that overlap is not optional.
  • New field listed_at on every Listing — when the item entered the catalogue, which is what sort=newest now orders by. Re-listings surface alongside genuinely new inventory.
Nothing existing changes shape: 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, and POST /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 ends cancelled 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} and GET /v1/orders/info — now carries a refund object: amount_usd, refunded_at, and partial (true when only one leg of a multi-item order came back). It is null when 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 same order_id, so an end-of-day reconciliation is one pass over this feed.
Both are additive — the 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 optional min_total_usd price-drift protection and external_id idempotency.
  • Track lifecycle (pending → offer_sent → received → completed) and settled amounts with GET /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_id so you can render anti-impersonation checks to sellers.
  • Access is granted per-account — call GET /v1/sell/status to check, and contact support to request access.
See the Instant Sell guide for the full walkthrough.

Fixes

Precise 402 error codes on POST /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.
Both responses now include 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.