Selling items
List backpack items on the market, reprice them, and take them down.
There are two ways to sell, depending on where the item is right now:
- Still in Steam:
POST /public/v1/sell. We send you a trade offer, and the item goes on the market when you accept. - Already in your backpack on site:
POST /public/v1/list. No trade offer, it is listed immediately.
Both end at the same place, and the same edit, delist and reporting calls work on whatever they produce.
Selling from Steam
GET /public/v1/steam-inventory?app_id=730
reads your live Steam inventory. Every row carries a token, a signed handle
for that item that expires after 30 minutes:
curl "https://api.cs.deals/public/v1/steam-inventory?app_id=730" \
-H "Authorization: Bearer csd_..."Hand those tokens straight to the sell call with a price per copy in cents:
curl -X POST "https://api.cs.deals/public/v1/sell" \
-H "Authorization: Bearer csd_..." \
-H "Content-Type: application/json" \
-d '{ "listings": [{ "items": [{ "token": "eyJ...", "amount": 1 }], "price": 4250 }] }'You get back deposit_ids. Each one appears as deposit_id on a
GET /public/v1/trades row, which is where
you watch for the offer, its steam_offer_id, and whether it was accepted.
Nothing is listed until you accept the offer in Steam.
Selling from your backpack
Anything already in your backpack can be listed without a trade offer: items you bought here, and items you deposited earlier. These calls all work on the same backpack item id you would withdraw with.
1. Find what you can sell
GET /public/v1/backpack returns what you
own:
curl "https://api.cs.deals/public/v1/backpack?page=1&limit=50" \
-H "Authorization: Bearer csd_..."The id on each row is the backpack item id. It is not the listing id and not
the Steam asset id. An item with trade_locked_until set can still be listed;
it just cannot leave the platform until the hold expires.
For a price to ask, GET /public/v1/prices/all
gives market_price and recommended_price for every item in one cached
response.
2. List it
POST /public/v1/list takes groups of items,
each with one price in cents:
curl -X POST "https://api.cs.deals/public/v1/list" \
-H "Authorization: Bearer csd_..." \
-H "Content-Type: application/json" \
-d '{ "listings": [{ "items": [{ "id": 8891, "amount": 1 }], "price": 4250 }] }'{
"listings": [
{
"id": 55120,
"app_id": 730,
"market_hash_name": "AK-47 | Redline (Field-Tested)",
"price": 4250,
"amount": 1,
"commodity": false,
"created_at": "2026-08-09T16:20:00.000Z"
}
]
}Each group becomes one listing, so a single call can put fifty different items
up at fifty different prices. Identical commodity items grouped together sell
as one stack of amount.
A commodity backpack row is a quantity, not a single copy, so the same id can
appear in as many groups as you like — that is how you get separate listings,
each with its own listing_id, for copies of the same item at the same price:
# three Cloth, three listings, all at 10c
curl -X POST "https://api.cs.deals/public/v1/list" \
-H "Authorization: Bearer csd_..." \
-H "Content-Type: application/json" \
-d '{ "listings": [
{ "items": [{ "id": 8891, "amount": 1 }], "price": 10 },
{ "items": [{ "id": 8891, "amount": 1 }], "price": 10 },
{ "items": [{ "id": 8891, "amount": 1 }], "price": 10 }
] }'The groups draw from one pool, so asking for more than the row's amount in
total fails with INSUFFICIENT_ITEMS and nothing is listed.
Keep the returned id. That is the listing_id every later call uses, and the
id buyers see in the public book.
3. Reprice or resize
PATCH /public/v1/list changes a
listing. Send price, amount, or both:
curl -X PATCH "https://api.cs.deals/public/v1/list" \
-H "Authorization: Bearer csd_..." \
-H "Content-Type: application/json" \
-d '{ "listing_id": 55120, "price": 3990 }'Raising amount takes more of the same item from your backpack. Lowering it
returns the surplus to your backpack — unless you send price in the same
call, which is treated as a partial reprice:
# 10 Cloth listed at 10c; move one of them to 9c
curl -X PATCH "https://api.cs.deals/public/v1/list" \
-H "Authorization: Bearer csd_..." \
-H "Content-Type: application/json" \
-d '{ "listing_id": 55120, "amount": 1, "price": 9 }'That leaves listing 55120 holding 1 at 9c and puts the other 9 in a new
listing, still at 10c. Nothing goes back to your backpack, so repricing part of
a stack never takes the rest off sale. The response is the listing you edited;
pick up the new one from
GET /public/v1/my-listings.
Auto-decaying prices are website-only, so a bot that wants a decay curve reprices on its own schedule.
Repricing in bulk
Send a listings array instead of a single body to edit up to 50 at once. The
per-listing rules are identical, including the partial reprice above:
curl -X PATCH "https://api.cs.deals/public/v1/list" \
-H "Authorization: Bearer csd_..." \
-H "Content-Type: application/json" \
-d '{ "listings": [
{ "listing_id": 55120, "price": 3990 },
{ "listing_id": 55121, "price": 4250 }
] }'Each listing is applied on its own, so one bad listing_id does not stop the
rest. You get a row per listing, in the order you sent them, carrying the same
error code the single-listing form would have returned:
{
"results": [
{ "listing_id": 55120, "ok": true, "error": null, "listing": { "id": 55120, "price": 3990 } },
{ "listing_id": 55121, "ok": false, "error": "LISTING_NOT_FOUND", "listing": null }
]
}The rate limit counts calls, not listings, so a batch of 50 lifts the ceiling from 30 edits a minute to 1,500.
4. Take it down
POST /public/v1/delist removes a listing and
returns its items to your backpack:
curl -X POST "https://api.cs.deals/public/v1/delist" \
-H "Authorization: Bearer csd_..." \
-H "Content-Type: application/json" \
-d '{ "listing_id": 55120 }'Send listing_ids instead to remove up to 50 at once. As with bulk editing,
each is removed on its own and comes back in results with its own ok and
error:
curl -X POST "https://api.cs.deals/public/v1/delist" \
-H "Authorization: Bearer csd_..." \
-H "Content-Type: application/json" \
-d '{ "listing_ids": [55120, 55121, 55122] }'Keeping track
GET /public/v1/my-listings lists your
own listings, filterable by status:
ACTIVEis on the market nowFILLEDsold outDISABLEDwas taken down
available_amount on each row is how many more copies of that commodity you
still hold in the backpack, which is what you can add to the listing.
Accounts have a ceiling on how much they can have listed at once. Past it,
listing fails with LISTING_LIMIT_REACHED. If you are running into it, talk
to support.
GET /public/v1/my-listings/value
answers "what am I currently asking for, in total" in one call:
{ "listing_count": 214, "item_count": 388, "total_value": 1049900 }When something sells
A sale is not pushed to you as a private event. Two ways to see it:
GET /public/v1/ordersshows rows withside: "sold".GET /public/v1/transactionsshows the money arriving, actionSALE, with your running balance.
The public WebSocket feed also carries listing.amount_changed and
listing.removed for your listings, but those are public events about the book,
not a private notification: new_amount: 0 means the listing sold out.
For books and tax season,
GET /public/v1/orders/export hands
back your whole history in one file, CSV by default:
curl "https://api.cs.deals/public/v1/orders/export?side=sold" \
-H "Authorization: Bearer csd_..." -o sales.csvEach row carries the commission in fee and what you actually kept in net.