API Documentation
Browse the CS2 skin marketplace, purchase items, manage orders, and check wallet balance programmatically. All endpoints require API Token authentication.
Overview
The TradeStation Open API provides programmatic access to the CS2 skin marketplace. You can browse available inventory, execute purchases, track order status, and manage your wallet through a RESTful JSON API.
Market
Browse skins & inventory
Catalog aggregates, then list in-stock items by hash name and filters.
Trade
Purchase items
Standard buy and quick-buy; optional price checks and idempotent keys.
Orders
Track order status
List orders with status filters and fetch a single order by number.
Wallet
Balance & transactions
Snapshot of balances plus paginated history of wallet movements.
Authentication
All requests must include your API token in the Authorization header. Tokens can be generated from your account dashboard.
Authorization: Token sst_a1b2c3d4e5f6...Token format: sst_ prefix followed by 48 hex characters. The full token is only shown once at creation time — store it securely.
Base URL
https://api.tradestation.gg/api/v1/All endpoint paths in this documentation are relative to this base URL.
Response Format
Every response is wrapped in a standard envelope. The top-level code field uses TradeStation business status codes (not HTTP status codes).
{
"code": 1000,
"message": "ok",
"data": { ... }
}{
"code": 3001,
"message": "Item is not available",
"data": null
}For failed/cancelled/reversed orders, the response includes both the error code and the order data:
{
"code": 5201,
"message": "Item unavailable",
"data": {
"order_no": "T20260407143022849132",
"status": "failed",
"fail_code": 5201,
...
}
}Pagination
List endpoints use page-based pagination. Control with page and page_size query parameters.
{
"code": 1000,
"message": "ok",
"count": 142,
"page": 1,
"page_size": 10,
"total_pages": 15,
"next": 2,
"previous": null,
"data": [ ... ]
}page | integer | Page number (default: 1) |
page_size | integer | Items per page (default: 10, max: 100) |
next | integer | null | Next page number, null if last page |
previous | integer | null | Previous page number, null if first page |
Rate Limiting
Requests are rate limited per user. Exceeding the limit returns HTTP 429 with code 9003.
| Endpoint | Limit |
|---|---|
GET /market/catalog/ | 5 / minute |
GET /market/items/ | 300 / minute |
POST /market/orders/buy/ | 300 / minute |
POST /market/orders/quick-buy/ | 300 / minute |
GET /wallet/ | 60 / minute |
GET /wallet/transactions/ | 60 / minute |
Status Codes
Business status codes are segmented by range. HTTP status codes are used conventionally (200, 201, 400, 401, 403, 404, 429, 500).
1xxx — Success
1000 | ok |
1001 | Order already exists |
3xxx — Buy Pre-validation
3001 | Item is not available |
3006 | Too many active orders |
3007 | Order is being processed, please try again |
3008 | This external_order_no has already been used |
3009 | Insufficient balance |
4xxx — Quick Buy Pre-validation
4001 | Quick buy is currently disabled |
4002 | No available inventory for this item |
4003 | No available items found within the price limit |
5xxx — Order Lifecycle
5001 | Order not found |
5002 | Order status does not allow this operation |
5101 | Cancelled by admin |
5102 | Trade offer expired or platform cancelled |
5201 | Item unavailable |
5202 | Trade failed |
5301 | Trade offer creation failed |
5303 | Trade offer declined |
5304 | Steam unavailable |
5401 | Invalid trade URL |
5402 | Steam account trade restricted |
5403 | Steam inventory is private |
5501 | Trade reversed on Steam |
9xxx — System
9001 | Authentication required |
9002 | Permission denied |
9003 | Rate limit exceeded |
9004 | Invalid request body |
9005 | Missing required parameter |
9006 | Invalid parameter value |
9999 | Internal server error |
API Reference
Complete endpoint reference for the TradeStation Open API.
/market/catalog/Returns an aggregated overview of all skins with available inventory. Results are cached for 120 seconds.
No parameters required. Useful for building a skin browser — each entry represents a unique skin with its lowest price and available count.
Response fields (per item)
hash_name | string | Steam market hash name |
phase | string | Phase variant (e.g. "Phase 2", "Ruby"). Empty for non-Doppler items. |
min_price | decimal | Lowest available price |
count | integer | Number of available items |
{
"code": 1000,
"message": "ok",
"data": [
{
"hash_name": "AK-47 | Redline (Field-Tested)",
"phase": "",
"min_price": "28.5000",
"count": 12
},
{
"hash_name": "★ Karambit | Doppler (Factory New)",
"phase": "Phase 2",
"min_price": "1523.0000",
"count": 3
}
]
}/market/items/Returns all available listings sorted by price (lowest first), allowing you to compare and select the exact item to buy.
Query parameters
hash_namerequired | string | Steam market hash name (exact match) |
phase | string | Filter by phase (e.g. "Phase 1", "Sapphire") |
price_max | decimal | Maximum price filter |
page | integer | Page number (default: 1) |
page_size | integer | Items per page (default: 10, max: 100) |
Response fields (per item)
id | integer | Inventory item ID (use for purchase) |
hash_name | string | Steam market hash name |
name_zh | string | Chinese name |
phase | string | Phase variant |
price | decimal | Selling price (CNY, 4 decimal places) |
float_value | decimal | null | Float value (up to 18 decimal places) |
paint_seed | integer | null | Paint seed |
paint_index | integer | null | Paint index |
name_tag | string | Applied name tag |
stickers | array | Applied stickers |
charm | array | Attached charms (keychain slot) |
GET /api/v1/market/items/?hash_name=Souvenir+Galil+AR+%7C+Green+Apple+(Factory+New)&page_size=2Rows are sampled from real listings for the same hash_name (IDs and stock change over time). stickers / charm drop skin_id and image_url. Some sources expose market_hash_name plus placement floats; others expose a display name only. The second list entry omits attachment bodies and uses [ ... ] as a shorthand.
{
"code": 1000,
"message": "ok",
"count": 11,
"page": 1,
"page_size": 2,
"total_pages": 6,
"next": 2,
"previous": null,
"data": [
{
"id": 40310,
"hash_name": "Souvenir Galil AR | Green Apple (Factory New)",
"name_zh": "加利尔AR(纪念品) | 绿苹果 (崭新出厂)",
"phase": "",
"price": "10.2500",
"float_value": "0.034173440188169479",
"paint_seed": 780,
"paint_index": 294,
"name_tag": "",
"stickers": [
{
"name": " StarLadder(金色)| 2025年布达佩斯锦标赛",
"slot": 0,
"wear": "0"
},
{
"name": " 火车(金色)",
"slot": 2,
"wear": "0"
},
{
"name": " Natus Vincere(金色)| 2025年布达佩斯锦标赛",
"slot": 1,
"wear": "0"
},
{
"name": " FURIA(金色)| 2025年布达佩斯锦标赛",
"slot": 3,
"wear": "0"
}
],
"charm": [
{
"name": "挂件(纪念品): 2025年布达佩斯锦标赛高光时刻 | YEKINDAR对阵Natus Vincere Train精彩表现",
"pattern": null
}
]
},
{
"id": 40311,
"hash_name": "Souvenir Galil AR | Green Apple (Factory New)",
"name_zh": "加利尔AR(纪念品) | 绿苹果 (崭新出厂)",
"phase": "",
"price": "10.2500",
"float_value": "0.060612890869379043",
"paint_seed": 803,
"paint_index": 294,
"name_tag": "",
"stickers": [ ... ],
"charm": [ ... ]
}
]
}/market/orders/buy/Purchase a specific inventory item by ID. The item will be delivered to your Steam trade URL.
Request body
item_idrequired | integer | Inventory item ID (from market listing) |
trade_urlrequired | string | Steam trade URL (https://steamcommunity.com/tradeoffer/new/?partner=...&token=...) |
external_order_no | string | Your external order reference (max 64 chars, must be unique per user) |
Idempotency
If a request with the same item_id (or same external_order_no) finds an existing active order, the API returns that order with code 1001 instead of creating a duplicate.
POST /api/v1/market/orders/buy/
Content-Type: application/json
Authorization: Token sst_a1b2c3d4e5f6...
{
"item_id": 4821,
"trade_url": "https://steamcommunity.com/tradeoffer/new/?partner=123456&token=AbCdEf",
"external_order_no": "my-order-001"
}{
"code": 1000,
"message": "ok",
"data": {
"order_no": "T20260407143022849132",
"external_order_no": "my-order-001",
"status": "created",
"price": "28.5000",
"hash_name": "AK-47 | Redline (Field-Tested)",
"name_zh": "AK-47 | 红线 (久经沙场)",
"phase": "",
"float_value": "0.256312847137451170",
"paint_seed": 661,
"paint_index": 282,
"name_tag": "",
"stickers": [...],
"charm": [],
"fail_code": null,
"fail_reason_display": "",
"created_at": "2026-04-07T14:30:22.849132Z",
"completed_at": null
}
}/market/orders/quick-buy/Purchase the lowest-priced available item for a given skin. Automatically selects the cheapest item.
Request body
hash_namerequired | string | Steam market hash name |
trade_urlrequired | string | Steam trade URL |
phase | string | Limit to a specific phase |
max_price | decimal | Maximum acceptable price — returns 4003 if no items below this price |
external_order_no | string | Your external order reference (max 64 chars) |
POST /api/v1/market/orders/quick-buy/
Content-Type: application/json
Authorization: Token sst_a1b2c3d4e5f6...
{
"hash_name": "AK-47 | Redline (Field-Tested)",
"trade_url": "https://steamcommunity.com/tradeoffer/new/?partner=123456&token=AbCdEf",
"max_price": "30.0000"
}Response format is identical to the Buy Item endpoint.
/market/orders/Lists your orders with optional filtering by status, external order number, and date range. Ordered by creation time descending. Each row uses the same order object shape as GET /market/orders/{order_no}/ (nested skin metadata plus instance fields).
Query parameters
status | string | Filter by order status: created pending completed failed cancelled reversed |
external_order_no | string | Filter by your external order reference (exact match) |
start_date | string | Start date inclusive (ISO 8601 format: YYYY-MM-DD) |
end_date | string | End date inclusive (ISO 8601 format: YYYY-MM-DD) |
page | integer | Page number (default: 1) |
page_size | integer | Items per page (default: 10, max: 100) |
Date range cannot exceed 90 days. Both start_date and end_date are optional and can be used independently.
Response fields (per order)
order_no | string | TradeStation order number |
external_order_no | string | Your external reference |
status | string | Order status |
price | decimal | Transaction price |
hash_name | string | Skin market hash name |
name_zh | string | Chinese name |
phase | string | Phase variant |
float_value | decimal | null | Item float (this instance) |
paint_seed | integer | null | Item paint seed |
paint_index | integer | null | Item paint index |
name_tag | string | Applied name tag on the item |
stickers | array | Stickers JSON (same storage shape as market listings) |
charm | array | Charms / keychain slot JSON |
fail_code | integer | null | Failure code (5xxx) if applicable |
fail_reason_display | string | Human-readable failure reason |
created_at | datetime | ISO 8601 timestamp |
completed_at | datetime | null | Completion time |
GET /api/v1/market/orders/?status=completed&page=1&page_size=10{
"code": 1000,
"message": "ok",
"count": 24,
"page": 1,
"page_size": 10,
"total_pages": 3,
"next": 2,
"previous": null,
"data": [
{
"order_no": "T20260415120000123456",
"external_order_no": "inv-2026-0415-001",
"status": "completed",
"price": "28.5000",
"hash_name": "AK-47 | Redline (Field-Tested)",
"name_zh": "AK-47 | 红线 (久经沙场)",
"phase": "",
"float_value": "0.256312847137451170",
"paint_seed": 661,
"paint_index": 282,
"name_tag": "",
"stickers": [
{
"slot": 0,
"wear": null,
"market_hash_name": "Sticker | iBUYPOWER (Holo) | Katowice 2014",
"offset_x": -0.08,
"offset_y": 0.02,
"rotation": null
}
],
"charm": [],
"fail_code": null,
"fail_reason_display": "",
"created_at": "2026-04-15T10:12:03.123456Z",
"completed_at": "2026-04-15T10:18:44.987654Z"
},
{
"order_no": "T20260415104500987654",
"external_order_no": "",
"status": "pending",
"price": "120.7143",
"hash_name": "AWP | Chrome Cannon (Factory New)",
"name_zh": "AWP | 镀铬大炮 (崭新出厂)",
"phase": "",
"float_value": "0.069282613694667820",
"paint_seed": 946,
"paint_index": 1170,
"name_tag": "",
"stickers": [ ... ],
"charm": [ ... ],
"fail_code": null,
"fail_reason_display": "",
"created_at": "2026-04-15T09:45:22.100000Z",
"completed_at": null
}
]
}/market/orders/{order_no}/Retrieve a single order. Response body matches one element from GET /market/orders/ (same fields and nesting).
Path parameters
order_norequired | string | TradeStation order number |
Field list is identical to each object in the order list — same flat skin fields (hash_name, name_zh, phase) plus instance attributes (float_value, paint_*, name_tag, stickers, charm).
For orders in terminal states (failed, cancelled, reversed), the top-level code will be the fail_code (5xxx) instead of 1000.
GET /api/v1/market/orders/T20260415120000123456/{
"code": 1000,
"message": "ok",
"data": {
"order_no": "T20260415120000123456",
"external_order_no": "inv-2026-0415-001",
"status": "completed",
"price": "28.5000",
"hash_name": "AK-47 | Redline (Field-Tested)",
"name_zh": "AK-47 | 红线 (久经沙场)",
"phase": "",
"float_value": "0.256312847137451170",
"paint_seed": 661,
"paint_index": 282,
"name_tag": "",
"stickers": [
{
"slot": 0,
"wear": null,
"market_hash_name": "Sticker | iBUYPOWER (Holo) | Katowice 2014",
"offset_x": -0.08,
"offset_y": 0.02,
"rotation": null
}
],
"charm": [],
"fail_code": null,
"fail_reason_display": "",
"created_at": "2026-04-15T10:12:03.123456Z",
"completed_at": "2026-04-15T10:18:44.987654Z"
}
}stickers / charm mirror the stored attachment JSON (same shapes as in List Items); empty arrays when none.
{
"code": 5201,
"message": "Item unavailable",
"data": {
"order_no": "T20260414083000555666",
"external_order_no": "",
"status": "failed",
"price": "15.0000",
"hash_name": "M4A4 | Howl (Field-Tested)",
"name_zh": "M4A4 | 咆哮 (久经沙场)",
"phase": "",
"float_value": "0.180000000000000000",
"paint_seed": 100,
"paint_index": 419,
"name_tag": "",
"stickers": [],
"charm": [],
"fail_code": 5201,
"fail_reason_display": "Item unavailable",
"created_at": "2026-04-14T08:30:00.000000Z",
"completed_at": null
}
}/wallet/Returns your current wallet balance snapshot including available, held, and frozen amounts.
Response fields
currency | string | Wallet currency (always USD) |
available | decimal | Available balance — can be used for trading and withdrawal |
held | decimal | Held balance — credited but in hold period, can trade but cannot withdraw |
frozen | decimal | Frozen balance — locked for pending orders, cannot trade or withdraw |
total | decimal | Total balance (available + held + frozen) |
tradable | decimal | Tradable balance (available + held) |
withdrawable | decimal | Withdrawable balance (available only) |
status | string | Wallet status: active or frozen |
updated_at | datetime | Last balance update time (ISO 8601) |
{
"code": 1000,
"message": "ok",
"data": {
"currency": "USD",
"available": "8997.868000",
"held": "0.000000",
"frozen": "1.066000",
"total": "8998.934000",
"tradable": "8997.868000",
"withdrawable": "8997.868000",
"status": "active",
"updated_at": "2026-04-14T16:18:46.915184Z"
}
}/wallet/transactions/Lists your wallet transactions in reverse chronological order. Supports filtering by type and date range.
Query parameters
tx_type | string | Filter by transaction type: deposit withdraw trade_freeze trade_unfreeze trade_pay trade_income adjustment transfer_in transfer_out etc. |
start_date | string | Start date inclusive (ISO 8601 format: YYYY-MM-DD) |
end_date | string | End date inclusive (ISO 8601 format: YYYY-MM-DD) |
page | integer | Page number (default: 1) |
page_size | integer | Items per page (default: 100, max: 100) |
Date range cannot exceed 31 days. If only start_date is provided, end date defaults to start + 31 days (or today). If only end_date is provided, start date defaults to end − 31 days.
Response fields (per transaction)
tx_no | string | Transaction reference number |
tx_type | string | Transaction type |
amount | decimal | Change amount (positive = credit, negative = debit) |
balance_before | decimal | Available balance before this transaction |
held_before | decimal | Held balance before this transaction |
frozen_before | decimal | Frozen balance before this transaction |
balance_after | decimal | Available balance after this transaction |
held_after | decimal | Held balance after this transaction |
frozen_after | decimal | Frozen balance after this transaction |
biz_type | string | Business type (e.g. trade_freeze, adjustment) |
biz_id | string | Related business reference (e.g. order number) |
description | string | Human-readable description |
created_at | datetime | Transaction time (ISO 8601) |
GET /api/v1/wallet/transactions/?start_date=2026-04-01&end_date=2026-04-14&page_size=2{
"code": 1000,
"message": "ok",
"count": 15,
"page": 1,
"page_size": 2,
"total_pages": 8,
"next": 2,
"previous": null,
"data": [
{
"tx_no": "WT2026041479108331",
"tx_type": "trade_unfreeze",
"amount": "1.660500",
"balance_before": "8996.207500",
"held_before": "0.000000",
"frozen_before": "2.726500",
"balance_after": "8997.868000",
"held_after": "0.000000",
"frozen_after": "1.066000",
"biz_type": "trade_unfreeze",
"biz_id": "T20260414154317644080",
"description": "",
"created_at": "2026-04-14T16:18:46.917017Z"
},
{
"tx_no": "WT2026041433429418",
"tx_type": "trade_freeze",
"amount": "-1.660500",
"balance_before": "8997.868000",
"held_before": "0.000000",
"frozen_before": "1.066000",
"balance_after": "8996.207500",
"held_after": "0.000000",
"frozen_after": "2.726500",
"biz_type": "trade_freeze",
"biz_id": "T20260414154317644080",
"description": "",
"created_at": "2026-04-14T15:43:17.378123Z"
}
]
}Order Status Flow
createdpendingcompletedcreatedfailedPre-execution failure (item unavailable, insufficient balance, etc.)pendingcancelledTrade offer expired or cancelled by adminpendingfailedBuyer declined trade offer or technical failurecompletedreversedCompleted trade reversed on SteamOrders that are still waiting on buyer-side action (for example trade offer acceptance) are automatically cancelled after a platform-configured timeout. The default is 40 minutes (trade.order_timeout_minutes). Your deployment may use a different value — check with your operator if you need the exact limit.
createdOrder created, executing purchase
pendingTrade offer sent, awaiting acceptance
completedTrade completed successfully
failedTrade failed permanently
cancelledCancelled by timeout or admin
reversedCompleted trade reversed on Steam
Integration Best Practices
Use external_order_no for idempotency
Always pass your own unique order reference. If a network error occurs mid-request, retrying with the same external_order_no will return the existing order (code 1001) instead of creating a duplicate.
Use max_price for price protection (quick-buy)
Prices can change between browsing and purchasing. Set max_price in the quick-buy endpoint to reject the trade if the price exceeds your limit.
Poll order status for async fulfillment
Orders transition from created → pending → completed asynchronously. Poll GET /market/orders/{order_no}/ to track progress. Use exponential backoff starting from 5 seconds.
Handle 5xxx codes in order responses
Terminal order responses (failed/cancelled/reversed) return 5xxx codes at the top level. Check the code field before parsing data to handle failures gracefully.
Respect rate limits
If you receive code 9003, back off and retry after the indicated period. Persistent rate limiting violations may result in token revocation.