BuyCS2 API Documentation

Request API access

Authentication

All API requests require 2 headers:

HeaderDescription
x-api-keyYour merchant API Key
x-merchant-idYour Merchant ID
Auth Error (401)
{ "error": "unauthorized", "message": "Invalid API key or Merchant ID" }

Base URL

Base URL
api.buycs2.com

Compression

Responses are gzip-compressed. Clients must send:

Required Header
Accept-Encoding: gzip

Rate Limits

EndpointLimit
GET /Items/GetAllItemsOnSale10 requests per minute
All other endpoints300 requests per minute

Currency

All prices and balances are in USD cents (1 USD = 100 cents). For example, 1500 = $15.00.

Timestamps

All timestamps are UTC in ISO 8601 format:

Timestamp Format
"2025-01-15T12:30:45.000Z"

Error Handling

Error responses include a JSON body with error and message fields:

Error Response Example
{
  "error": "invalid_request",
  "message": "Missing required fields: itemId, assetId, price, tradeUrl"
}
StatusMeaning
200Success
400Bad request - invalid parameters
401Unauthorized - invalid or missing API key / Merchant ID
403Forbidden - partner blocked, or too many active trades
429Rate limited - too many requests
500Internal server error

Get All Items on Sale

GET /Items/GetAllItemsOnSale

Returns all items currently on sale. Use for inventory sync.

Rate limit. 10 requests per minute.

Response

200 OK
{
  "totalItems": 1,
  "totalValue": 1500,
  "items": [
    {
      "itemId": 123,
      "assetId": "12345678901",
      "classId": "310776585",
      "instanceId": "480085569",
      "paintIndex": 12,
      "paintSeed": 225,
      "rarityColor": "#eb4b4b",
      "market_hash_name": "AK-47 | Redline (Field-Tested)",
      "img": "https://steamcdn-a.akamaihd.net/apps/730/icons/...",
      "phase": null,
      "price": 1500,
      "float": 0.15234,
      "stickers": [
        {
          "name": "Sticker | Natus Vincere | Katowice 2014",
          "img": "https://cdn.steamstatic.com/apps/730/icons/econ/stickers/katowice2014/navi.png",
          "slot": 0,
          "wear": 0.6416051387786865,
          "wearPercent": "35%",
          "rotation": 45,
          "offsetX": 0.13,
          "offsetY": 0.19
        }
      ],
      "keyChains": [
        {
          "name": "Charm | Snowman",
          "img": "https://cdn.steamstatic.com/apps/730/icons/econ/charms/charm_snowman.png",
          "slot": 0,
          "pattern": 123,
          "offsetX": -0.15,
          "offsetY": 0.07,
          "offsetZ": 1.78
        }
      ],
      "steamId": "76561198012345678",
      "inspectInGame": "steam://rungame/730/...",
      "tradeUrl": "https://steamcommunity.com/tradeoffer/new/?partner=1551362882&token=czMFCtWq"
    }
  ]
}
FieldTypeDescription
totalItemsintegerTotal number of items
totalValueintegerTotal value of all items (USD cents)
itemIdintegerItem ID (used for buy endpoint)
assetIdstringSteam Asset ID
classIdstringSteam Class ID
instanceIdstringSteam Instance ID
paintIndexinteger|nullPaint index (skin ID). 0 = vanilla, null = no data
paintSeedinteger|nullPaint seed (pattern seed, 0–999). 0 = vanilla, null = no data
rarityColorstring|nullRarity color hex code: #b0c3d9, #5e98d9, #4b69ff, #8847ff, #d32ce6, #eb4b4b, #e4ae39. null = no data
market_hash_namestringFull CS2 market hash name
imgstring|nullItem image URL (null if not available)
phasestring|nullDoppler phase (null if not Doppler)
priceintegerSelling price (USD cents)
floatnumber|nullFloat value (null if not available)
stickersarraySticker/Patch list (name, img, slot, wear, wearPercent, rotation?, offsetX?, offsetY?). wear is the raw float32 value returned by Steam inspect (range 0..1, where 0 = unscratched and 1 = fully scratched; null when inspect data is unavailable). wearPercent is a human-readable string for the remaining condition = floor((1 - wear) * 100) + "%": "100%" when wear=0 (pristine), "0%" when wear=1 (fully scratched); null when wear is null. Use whichever field fits your use case. rotation/offset* are optional and only present for custom placement. slot may not be unique in CS2; use array order if you need stable identification
keyChainsarrayAttached item list (name, img, slot, pattern?, rotation?, offsetX?, offsetY?, offsetZ?). This array can contain standard charms, souvenir charms, and sticker slabs. Optional fields are only present when available. slot may not be unique in CS2
steamIdstring|nullSteam ID of the account holding this item (null if not enabled). Contact admin to enable
inspectInGamestring|nullIn-game inspect link (null if not enabled). Contact admin to enable
tradeUrlstring|nullTrade offer URL of the account holding this item (null if not enabled). Contact admin to enable

Search Items

POST /Items/SearchItems

Search items by name or item ID. Returns the latest availability and pricing for matching items.

Request Body

Provide exactly one of market_hash_name or itemId.

JSON - search by name
{
  "market_hash_name": [
    "AK-47 | Panthera onca (Minimal Wear)",
    "★ StatTrak™ Paracord Knife | Case Hardened (Well-Worn)"
  ]
}
JSON - search by item ID
{
  "itemId": [12345, 67890]
}
FieldTypeRequiredDescription
market_hash_namestring[]NoArray of market hash names to search (max 10)
itemIdinteger[]NoArray of item IDs to search (max 10, positive integers)

Response

Same format as Get All Items - returns only matching items.

Error Responses

HTTPError CodeDescription
400invalid_requestMissing, invalid, or conflicting search fields

Get Balance

GET /Wallet/GetBalance

Returns merchant balance, credit limit, and total available.

Response

200 OK
{
  "balance": 500000,
  "credit_limit": 10000,
  "total_available": 510000
}
FieldTypeDescription
balanceintegerCurrent balance (USD cents). Can be negative if credit is in use
credit_limitintegerCredit limit granted by admin (USD cents). Default 0
total_availableintegerTotal spending power = balance + credit_limit (USD cents)

Balance History

GET /Wallet/BalanceHistory

Query merchant's balance transaction history. All params are optional.

Query Parameters

ParamTypeRequiredDescription
typestringNoFilter by type (see transaction types below)
tradeIdstringNoFilter by exact trade ID
limitintegerNoResults per page (default 50, max 500)
pageintegerNoPage number (default 1)

Transaction Types

TypeDescription
ADMIN TOP UPAdmin top-up
BUY COMPLETEDBuy trade completed
BUY CANCELLEDBuy trade cancelled
ADMIN DEDUCTAdmin deduction
TRADE ROLLBACKTrade rollback refund
CRYPTO DEPOSITCrypto deposit top-up
FREEZEBalance frozen for pending buy

Response

200 OK
{
  "transactions": [
    {
      "id": 1,
      "type": "BUY COMPLETED",
      "amount": -1500,
      "balanceBefore": 500000,
      "balanceAfter": 498500,
      "tradeId": "abc-123-def",
      "note": null,
      "createdAt": "2025-01-01T12:05:00.000Z",
      "market_hash_name": "AK-47 | Redline (Field-Tested)"
    }
  ],
  "total": 100,
  "limit": 50,
  "page": 1
}
FieldTypeDescription
idintegerTransaction ID
typestringTransaction type (see table above)
amountintegerAmount changed (USD cents, negative = deduct)
balanceBeforeintegerBalance before transaction (USD cents)
balanceAfterintegerBalance after transaction (USD cents)
tradeIdstringRelated trade ID (null if not trade-related)
notestringNote (null if none)
createdAtstringTransaction time (ISO 8601 UTC)
market_hash_namestringRelated item name (null if not trade-related)
totalintegerTotal matching transactions (for pagination)
limitintegerResults per page
pageintegerCurrent page number

Buy Item by ID

POST /Items/Buy

Purchase an item by ID and send a Steam trade offer to the recipient.

Request Body

JSON
{
  "itemId": 123,
  "assetId": "12345678901",
  "price": 1500,
  "tradeUrl": "https://steamcommunity.com/tradeoffer/new/?partner=123&token=abc",
  "externalId": "order_abc123",
  "tradeDurationSeconds": 1800
}
FieldTypeRequiredDescription
itemIdintegerYesItem ID from inventory endpoint
assetIdstringYesSteam Asset ID (must match the item)
priceintegerYesExpected price (USD cents). Rejected if price has changed
tradeUrlstringYesRecipient's Steam trade URL
externalIdstringNoYour order ID (must be unique per merchant, or null). Duplicate returns error duplicate_external_id
tradeDurationSecondsintegerNoHow long (seconds) the recipient has to accept the trade before it auto-cancels. Min: 600 (10 min), Max: 43200 (12h), Default: 1800 (30 min)

Success Response

200 OK
{
  "tradeId": "abc-123-def",
  "tradeUrl": "https://steamcommunity.com/tradeoffer/new/?partner=123&token=abc",
  "assetId": "12345678901",
  "market_hash_name": "AK-47 | Redline (Field-Tested)",
  "phase": null,
  "price": 1500,
  "externalId": "order_abc123"
}
FieldTypeDescription
tradeIdstringTrade ID - use this to match with webhooks
tradeUrlstringRecipient's Steam trade URL
assetIdstringSteam Asset ID of the purchased item
market_hash_namestringFull CS2 market hash name
phasestringDoppler phase (null if not Doppler)
priceintegerPrice paid (USD cents)
externalIdstringYour order ID (null if not provided)
Note. A successful response means the trade is already in PENDING status. A PENDING webhook will be sent immediately after.

Error Responses

HTTPError CodeDescription
400invalid_requestMissing required fields
400item_unavailableItem is currently unavailable
400asset_mismatchassetId does not match the item
400price_changedPrice has changed (message contains new price)
400invalid_tradeurlInvalid Steam trade URL format
400duplicate_external_idexternalId already used for another trade
400insufficient_balanceInsufficient merchant balance
400invalid_pricePrice must be greater than 0
400invalid_trade_durationtradeDurationSeconds must be between 600 (10 min) and 43200 (12h)
403partner_blockedTrade URL owner is temporarily blocked due to repeated declines/expired trades (10 times in 24h). Includes expiresAt in message
403too_many_active_tradesTrade URL owner has too many active trades (max 30 PENDING/SENT/CREATING)

Buy Item by Name

POST /Items/BuyByName

Purchase an item by name. By default, picks the cheapest matching item. Optionally pass itemId and assetId to target a specific item with maxPrice protection.

Request Body

JSON
{
  "market_hash_name": "AK-47 | Redline (Field-Tested)",
  "phase": null,
  "tradeUrl": "https://steamcommunity.com/tradeoffer/new/?partner=123&token=abc",
  "maxPrice": 1500,
  "externalId": "order_abc123",
  "tradeDurationSeconds": 1800,
  "itemId": 12345,
  "assetId": "50754412249"
}
FieldTypeRequiredDescription
market_hash_namestringYesFull CS2 market hash name
phasestringNoDoppler phase filter (e.g. "Phase 1", "Ruby", "Sapphire"). Only used when itemId is not provided
tradeUrlstringYesRecipient's Steam trade URL
maxPriceintegerYesMaximum price willing to pay (USD cents). Rejected if item price exceeds this
externalIdstringNoYour order ID (must be unique per merchant, or null). Duplicate returns error duplicate_external_id
tradeDurationSecondsintegerNoHow long (seconds) the recipient has to accept the trade before it auto-cancels. Min: 600 (10 min), Max: 43200 (12h), Default: 1800 (30 min)
itemIdintegerNoSpecific item ID to buy. Must be used together with assetId
assetIdstringNoSteam Asset ID of the item. Must be used together with itemId

Success Response

Same format as Buy Item by ID.

Error Responses

HTTPError CodeDescription
400invalid_requestMissing required fields, or only one of itemId/assetId provided
400item_unavailableItem is currently unavailable
400asset_mismatchassetId does not match the item
400price_too_highItem price exceeds maxPrice
400invalid_tradeurlInvalid Steam trade URL format
400duplicate_external_idexternalId already used for another trade
400insufficient_balanceInsufficient merchant balance
400invalid_pricemaxPrice must be greater than 0
400invalid_trade_durationtradeDurationSeconds must be between 600 (10 min) and 43200 (12h)
403partner_blockedTrade URL owner is temporarily blocked due to repeated declines/expired trades (10 times in 24h). Includes expiresAt in message
403too_many_active_tradesTrade URL owner has too many active trades (max 30 PENDING/SENT/CREATING)

Trade History

GET /Trades/History

Query trade history. All params are optional - without any filter, returns the 50 most recent trades.

Query Parameters

ParamTypeRequiredDescription
tradeIdstringNoFind a specific trade by ID
statusstringNoFilter by status (PENDING, COMPLETED, ...)
externalIdstringNoFind by your order ID
webhookStatusstringNoFilter by webhook status (sent, failed)
isActivestringNoSet to true to return all trades created within the last 14 days (no limit)
limitintegerNoResults per page (default 50, max 500). Ignored when isActive=true
pageintegerNoPage number (default 1). Ignored when isActive=true

Response

200 OK
{
  "trades": [
    {
      "tradeId": "abc-123-def",
      "externalId": "order_abc123",
      "status": "COMPLETED",
      "price": 1500,
      "itemId": 123,
      "assetId": "12345678901",
      "offerId": "5678901234",
      "tradeUrl": "https://steamcommunity.com/tradeoffer/new/?partner=123&token=abc",
      "market_hash_name": "AK-47 | Redline (Field-Tested)",
      "webhookStatus": "sent",
      "failReason": null,
      "errorCode": null,
      "createdAt": "2025-01-01T12:00:00.000Z",
      "updatedAt": "2025-01-01T12:05:00.000Z",
      "completedAt": "2025-01-01T12:05:00.000Z",
      "cancelledAt": null,
      "endProtection": "2026-03-17T07:00:00.000Z",
      "rollbackAt": null,
      "stage": 2
    }
  ],
  "total": 150,
  "limit": 50,
  "page": 1
}
FieldTypeDescription
tradeIdstringTrade ID (from buy endpoint)
externalIdstringYour order ID sent during purchase
statusstringCurrent trade status
priceintegerPrice (USD cents)
itemIdintegerItem ID
assetIdstringSteam Asset ID
offerIdstringSteam Trade Offer ID (null if not created yet)
tradeUrlstringRecipient's Steam trade URL
market_hash_namestringCS2 item name
webhookStatusstringWebhook delivery status (sent, failed, or null)
failReasonstringFailure reason (null if successful)
errorCodeintegerError code (null if successful)
createdAtstringTrade creation time (ISO 8601 UTC)
updatedAtstringLast update time (ISO 8601 UTC)
completedAtstringCompletion time (ISO 8601 UTC, null if not completed)
cancelledAtstringCancellation time (ISO 8601 UTC, null if not cancelled)
endProtectionstringEnd protection time (ISO 8601 UTC, null if no data)
rollbackAtstringRefund time when a completed trade was reversed (ISO 8601 UTC, null if not reversed)
stageinteger1 = trade can still be reversed; 2 = trade can't be reversed
totalintegerTotal matching trades (for pagination)
limitintegerResults per page
pageintegerCurrent page number

Trade Statuses

These values appear in trade_updated payloads and GET /Trades/History responses.

StatusDescription
PENDINGRequest received, waiting for trade offer to be created
SENTSteam trade offer sent, waiting for user to accept
COMPLETEDTrade completed - item has been delivered
CANCELLEDTrade cancelled - user declined, countered, or items sold elsewhere
FAILEDTrade failed - Steam error, user unavailable, or items invalid
EXPIREDTrade offer expired - user did not accept in time
REVERSEDCompleted trade was reversed by Steam
REJECTEDTrade rejected before request received
Refund. If a completed trade is reversed by Steam, the merchant is refunded 100% of the trade value.

Error Codes & Fail Reasons

StatuserrorCodefailReasonDescription
COMPLETEDnullnullItem delivered successfully
EXPIRED503Trade offer expiredBuyer didn't accept in time
CANCELLED504Trade declined by userBuyer declined the trade offer
CANCELLED505Items no longer validTrade offer was sent but the item was sold elsewhere before the buyer accepted
CANCELLED506Trade counteredBuyer countered the trade offer
FAILED500(raw error message from Steam)General Steam error
REVERSED512Completed trade was reversed by SteamTrade rolled back

Webhooks

When a trade status changes or an item is removed from inventory, a POST request is sent to the merchant's configured webhook URL.

Webhook Authentication

HeaderValue
x-signatureHMAC-SHA256 of JSON body using API Key as secret
x-webhook-typetrade_updated or item_removed
Content-Typeapplication/json

Verify Signature

Pseudo-code
expected = HMAC_SHA256(key=api_key, message=JSON.stringify(body))
valid = (expected === headers['x-signature'])

Webhook: trade_updated

Payload
{
  "tradeId": "abc-123-def",
  "status": "COMPLETED",
  "externalId": "order_abc123",
  "offerId": "5678901234",
  "failReason": null,
  "errorCode": null
}
FieldTypeDescription
tradeIdstringTrade ID (from buy endpoint)
statusstringCurrent status
externalIdstringYour order ID sent during purchase
offerIdstringSteam Trade Offer ID (null if not created yet)
failReasonstringFailure reason (null if successful)
errorCodeintegerError code (null if successful)
Reference. See Trade Statuses and Error Codes & Fail Reasons for all possible status, errorCode, and failReason values.

Webhook: item_removed

Sent when an item is removed from inventory. Use to invalidate your local cache between syncs.

Payload
{ "itemId": 123 }

Circuit Breaker

If your webhook endpoint fails repeatedly (timeout, network error, or non-2xx), delivery is paused.

To resume, go to Merchant Portal → Settings and click Test Webhook. Your server must accept the test event and return HTTP 2xx. Updating the webhook URL also resumes delivery.

Test Webhook Payload
{
  "event": "test",
  "message": "Webhook test from BuyCS2 Portal",
  "timestamp": "2025-01-15T10:30:00.000Z"
}

The test webhook is sent with header x-webhook-type: test.

Changelog

2026-08-20

  • GET /Trades/History now includes stage: 1 = trade can still be reversed, 2 = trade can't be reversed.
  • If a completed trade is reversed by Steam (REVERSED), the merchant is refunded 100% of the trade value.