API

Buying items

Find listings and buy them in a single atomic call.

Open raw markdownWhole API docs, for pasting into AI assistants

Buying is one call. You name the listings you want and the most you're willing to pay for each, and the order either fills completely or not at all.

There is no cart. v1's CreateCart / AddItems / PurchaseWithWallet dance is replaced by a single request, and what you buy lands in your backpack, ready to sell again or withdraw to Steam.

1. Find something to buy

GET /public/v1/listings returns active listings, newest first, filtered by game:

curl "https://api.cs.deals/public/v1/listings?page=1&limit=500&app_id=730" \
  -H "Authorization: Bearer csd_..."

app_id is 730 for CS2, 252490 for Rust, 570 for Dota 2, 440 for TF2. Each listing carries an id (the listing_id you pass when buying), a price in cents, and an amount, the number of copies available on that listing. Rows also include the full per-game item fields (cs_paint_wear, cs_paint_seed, cs_stickers, cs_inspect_link, and the Rust/Dota/TF2 equivalents; other games' fields are null), so float, pattern, and sticker-craft filtering happens client-side. app_id is the only server-side filter. The WebSocket listing.created event carries the same fields, so a bot can judge a new listing the moment it appears.

To re-check one listing you already know about, rather than paging the whole book, use GET /public/v1/listings/{id}:

curl "https://api.cs.deals/public/v1/listings/123456" \
  -H "Authorization: Bearer csd_..."

It returns the same shape as a row from the list endpoint. Once the listing is sold or delisted it returns 404 LISTING_NOT_FOUND, which is the cheapest way to confirm a listing is gone before you try to buy it.

For a market-wide price snapshot rather than individual listings, use GET /public/v1/prices/all: every priced item in one cached response, which is much cheaper than paging through GET /public/v1/prices or pulling the whole book. Each row carries lowest_listing_price, the cheapest live listing here for that item, next to the Steam-derived market_price.

2. Buy it

POST /public/v1/purchase takes the items directly:

curl -X POST https://api.cs.deals/public/v1/purchase \
  -H "Authorization: Bearer csd_..." \
  -H "Content-Type: application/json" \
  -d '{ "items": [{ "listing_id": 12345, "amount": 1, "max_price": 4250 }] }'

max_price is a ceiling, not an exact price. If the listing dropped to 4000 between your read and your write, the order fills and you are charged 4000. If it rose to 4300, the whole order fails with LISTING_PRICE_CHANGED and nothing is bought. Set it high to opt out of the check entirely.

Up to 50 lines per request, one line per listing. The entire request is a single transaction: if any line fails, no money moves and no items change hands.

3. Read the response

You get back the order, the items you now own, and where they landed:

{
  "order_id": 9001,
  "created_at": "2026-08-06T12:00:00.000Z",
  "items": [
    {
      "order_item_id": 44,
      "app_id": 730,
      "market_hash_name": "AK-47 | Redline (Field-Tested)",
      "steam_asset_id": "39082153990",
      "price": 4000,
      "amount": 1
    }
  ]
}

Purchased items go straight to your on-site backpack. From there you either relist them or withdraw them to Steam.

Errors worth handling

CodeMeaning
LISTING_PRICE_CHANGEDA listing costs more than your max_price. data.listing_ids says which.
LISTING_OUT_OF_STOCKSomeone bought it first. data.listing_ids says which.
LISTING_NOT_ACTIVEThe listing was delisted or archived.
LISTING_NOT_FOUNDNo such listing id.
INSUFFICIENT_BALANCEYour balance won't cover the order. Check GET /public/v1/user.
PURCHASE_OWN_LISTINGYou can't buy your own listing.
PURCHASING_DISABLEDPurchasing is off site-wide. Retry later.

Losing a race is normal, not exceptional. A bot should expect LISTING_OUT_OF_STOCK and LISTING_PRICE_CHANGED at a steady rate, drop those listings, and move on.

Your purchase history

GET /public/v1/orders pages through everything you have bought and sold, newest first, with side: "bought" on your purchases.

For the whole lot in one file, and for accounting, GET /public/v1/orders/export streams it as CSV:

curl "https://api.cs.deals/public/v1/orders/export?side=bought" \
  -H "Authorization: Bearer csd_..." -o purchases.csv

Add format=json for the same columns as JSON, app_id to narrow it to one game, and from/to as ISO dates for a single tax year. Money is in cents, unit_price per copy and total_value for the row.

What about the cart?

The website's checkout runs on separate cart endpoints that are not part of this API. The cart is per-account shared state: if you were to buy through it from a bot, you would also buy whatever is sitting in the cart from a browser session on the same account. Use POST /public/v1/purchase for anything automated.

Staying current

Polling /public/v1/listings finds new listings, but the WebSocket feed is faster and cheaper. It pushes listing.created, listing.price_changed, listing.amount_changed and listing.removed as they happen, each with a global sequence number. See the Overview for the connection and subscription protocol.

Between them those four cover a listing's whole life, so a client can hold a trustworthy local copy of the book: connect, buffer events, fetch GET /public/v1/book for the full active book plus the seq it is valid at, drop buffered events with seq at or below the snapshot's, and apply the rest. One request and one socket, no polling.

seq is an int64, strictly increasing but not contiguous, so gaps are normal. Events for the same listing can arrive slightly out of order, so apply one only when its seq beats the last seq you applied for that listing_id. Every payload is absolute state, which makes that check the whole of the ordering problem.

Rebuild rather than poll: the book is a large response and is rate-limited to six calls a minute. If you only want prices, not individual listings, GET /public/v1/prices/all is the cheap answer. The full protocol is in the Overview.