Skip to content
LogoLogo

Mutations and purchasing

Market mutations are form POSTs against steamcommunity.com, authenticated by the cookies of a signed-in session. They are not a JSON API, and they are not tolerant of a bare HTTP client.

Two ways to buy

OperationBehaviour
POST /market/buylisting/{listingid}Buys one specific listing outright, at its asking price, from the Steam Wallet. Immediate.
POST /market/createbuyorder/Places a standing order at a price you name. Fills when a seller meets it, possibly never, possibly partially.

buylisting is the instant-buy path. It targets a listing ID, so the listing must still exist at the price you read — losing the race to another buyer is a normal outcome, not an error condition.

Amounts must reconcile

buylisting requires the buyer to send the price breakdown, and Steam validates it:

total = subtotal + fee

subtotal is the seller's take, fee is the combined Steam and publisher cut, total is what the buyer pays. Read all three off the listing rather than computing them: the publisher's share varies per application, so the split is not derivable from the total alone.

curl 'https://steamcommunity.com/market/buylisting/1234567890123456789' \
  -H 'Cookie: steamLoginSecure=<redacted>; sessionid=<redacted>' \
  -H 'Referer: https://steamcommunity.com/market/listings/730/AK-47%20%7C%20Redline%20%28Field-Tested%29' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data 'sessionid=<redacted>&currency=1&subtotal=1200&fee=180&total=1380&quantity=1'

Success is reported inside wallet_info, not at the top level:

{ "wallet_info": { "success": 1, "wallet_balance": "4320" } }

A failure returns HTTP 200 with a top-level message and no wallet_info.success of 1. Check the nested field; a 200 alone means nothing here.

Required headers

Steam rejects mutations that do not look like they came from the Market UI. The sessionid CSRF field is necessary but not sufficient.

HeaderValue
CookiesteamLoginSecure and sessionid for the signed-in session
RefererThe page the action would have come from — see below
Content-Typeapplication/x-www-form-urlencoded
Originhttps://steamcommunity.com
X-Requested-WithXMLHttpRequest

Referer is checked per operation, and a generic one is not accepted:

OperationReferer
buylisting, createbuyorder, getbuyorderstatus/market/listings/{appid}/{market_hash_name}
sellitemThe inventory page for the account
removelisting, cancelbuyorder/market/

The market_hash_name in the Referer must be URL-encoded exactly as the listing page encodes it.

Selling is two steps

POST /market/sellitem/ does not publish a listing. It stages one and tells you what is still required:

{
  "success": true,
  "requires_confirmation": 1,
  "needs_mobile_confirmation": true,
  "needs_email_confirmation": false,
  "email_domain": ""
}

While requires_confirmation is set, the item is not on the Market. Completing the listing means accepting the matching Steam Guard confirmation:

  1. GET /mobileconf/getlist — list pending confirmations. Match yours by creator_id, which carries the asset ID for a sell listing.
  2. GET /mobileconf/ajaxop with op=allow, plus the cid and ck from that entry.

These routes sit under /mobileconf, not /market, and they authenticate differently: instead of the sessionid CSRF field they take an HMAC-SHA1 of the request tag and a Unix timestamp, keyed by the account's identity_secret from its mobile authenticator.

ParameterMeaning
pDevice ID derived from the SteamID
aSteamID64
kBase64 HMAC over tag and t, keyed by identity_secret
tUnix seconds the key was generated for
mandroid
tagconf to list, details{id} for detail, allow or cancel to respond

The signature covers the tag, so a key minted for conf will not work for allow. Generate a new one per request.

Watching a buy order fill

Buy orders fill over time and partially. GET /market/getbuyorderstatus is the only view of that:

{ "success": 1, "active": 1, "purchased": 2, "quantity": 5, "quantity_remaining": 3 }

GET /market/mylistings lists open orders but does not break down fills.

Failure is quiet

Nothing here uses HTTP status to report application failure. createbuyorder returns success: 25 with a message when it is rejected, buylisting hides its result in wallet_info.success, and cancelbuyorder returns success: 1. Read the body on every mutation.

Terms

Automating Market purchases is against the Steam Subscriber Agreement, which prohibits using automation software to modify or automate any Subscription Marketplace process. This page documents how the endpoints behave; whether to call them from a bot is a decision with account consequences.