TradeStation
v1Open API

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.

Request header
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

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).

Success response
{
  "code": 1000,
  "message": "ok",
  "data": { ... }
}
Error response
{
  "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:

Error with data (order failure)
{
  "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.

Paginated response
{
  "code": 1000,
  "message": "ok",
  "count": 142,
  "page": 1,
  "page_size": 10,
  "total_pages": 15,
  "next": 2,
  "previous": null,
  "data": [ ... ]
}
pageintegerPage number (default: 1)
page_sizeintegerItems per page (default: 10, max: 100)
nextinteger | nullNext page number, null if last page
previousinteger | nullPrevious page number, null if first page

Rate Limiting

Requests are rate limited per user. Exceeding the limit returns HTTP 429 with code 9003.

EndpointLimit
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

1000ok
1001Order already exists

3xxx — Buy Pre-validation

3001Item is not available
3006Too many active orders
3007Order is being processed, please try again
3008This external_order_no has already been used
3009Insufficient balance

4xxx — Quick Buy Pre-validation

4001Quick buy is currently disabled
4002No available inventory for this item
4003No available items found within the price limit

5xxx — Order Lifecycle

5001Order not found
5002Order status does not allow this operation
5101Cancelled by admin
5102Trade offer expired or platform cancelled
5201Item unavailable
5202Trade failed
5301Trade offer creation failed
5303Trade offer declined
5304Steam unavailable
5401Invalid trade URL
5402Steam account trade restricted
5403Steam inventory is private
5501Trade reversed on Steam

9xxx — System

9001Authentication required
9002Permission denied
9003Rate limit exceeded
9004Invalid request body
9005Missing required parameter
9006Invalid parameter value
9999Internal server error

API Reference

Complete endpoint reference for the TradeStation Open API.

GET/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_namestringSteam market hash name
phasestringPhase variant (e.g. "Phase 2", "Ruby"). Empty for non-Doppler items.
min_pricedecimalLowest available price
countintegerNumber of available items
Example response
{
  "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
    }
  ]
}
GET/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_namerequiredstringSteam market hash name (exact match)
phasestringFilter by phase (e.g. "Phase 1", "Sapphire")
price_maxdecimalMaximum price filter
pageintegerPage number (default: 1)
page_sizeintegerItems per page (default: 10, max: 100)

Response fields (per item)

idintegerInventory item ID (use for purchase)
hash_namestringSteam market hash name
name_zhstringChinese name
phasestringPhase variant
pricedecimalSelling price (CNY, 4 decimal places)
float_valuedecimal | nullFloat value (up to 18 decimal places)
paint_seedinteger | nullPaint seed
paint_indexinteger | nullPaint index
name_tagstringApplied name tag
stickersarrayApplied stickers
charmarrayAttached charms (keychain slot)
Example request
GET /api/v1/market/items/?hash_name=Souvenir+Galil+AR+%7C+Green+Apple+(Factory+New)&page_size=2

Rows 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.

Example response
{
  "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": [ ... ]
    }
  ]
}
POST/market/orders/buy/

Purchase a specific inventory item by ID. The item will be delivered to your Steam trade URL.

Request body

item_idrequiredintegerInventory item ID (from market listing)
trade_urlrequiredstringSteam trade URL (https://steamcommunity.com/tradeoffer/new/?partner=...&token=...)
external_order_nostringYour 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.

Example request
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"
}
Success response (HTTP 201)
{
  "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
  }
}
POST/market/orders/quick-buy/

Purchase the lowest-priced available item for a given skin. Automatically selects the cheapest item.

Request body

hash_namerequiredstringSteam market hash name
trade_urlrequiredstringSteam trade URL
phasestringLimit to a specific phase
max_pricedecimalMaximum acceptable price — returns 4003 if no items below this price
external_order_nostringYour external order reference (max 64 chars)
Example request
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.

GET/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

statusstringFilter by order status: created pending completed failed cancelled reversed
external_order_nostringFilter by your external order reference (exact match)
start_datestringStart date inclusive (ISO 8601 format: YYYY-MM-DD)
end_datestringEnd date inclusive (ISO 8601 format: YYYY-MM-DD)
pageintegerPage number (default: 1)
page_sizeintegerItems 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_nostringTradeStation order number
external_order_nostringYour external reference
statusstringOrder status
pricedecimalTransaction price
hash_namestringSkin market hash name
name_zhstringChinese name
phasestringPhase variant
float_valuedecimal | nullItem float (this instance)
paint_seedinteger | nullItem paint seed
paint_indexinteger | nullItem paint index
name_tagstringApplied name tag on the item
stickersarrayStickers JSON (same storage shape as market listings)
charmarrayCharms / keychain slot JSON
fail_codeinteger | nullFailure code (5xxx) if applicable
fail_reason_displaystringHuman-readable failure reason
created_atdatetimeISO 8601 timestamp
completed_atdatetime | nullCompletion time
Example request
GET /api/v1/market/orders/?status=completed&page=1&page_size=10
Example response
{
  "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
    }
  ]
}
GET/market/orders/{order_no}/

Retrieve a single order. Response body matches one element from GET /market/orders/ (same fields and nesting).

Path parameters

order_norequiredstringTradeStation 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.

Example request
GET /api/v1/market/orders/T20260415120000123456/
Example response (active / success)
{
  "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.

Example response (terminal: failed / cancelled / reversed)
{
  "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
  }
}
GET/wallet/

Returns your current wallet balance snapshot including available, held, and frozen amounts.

Response fields

currencystringWallet currency (always USD)
availabledecimalAvailable balance — can be used for trading and withdrawal
helddecimalHeld balance — credited but in hold period, can trade but cannot withdraw
frozendecimalFrozen balance — locked for pending orders, cannot trade or withdraw
totaldecimalTotal balance (available + held + frozen)
tradabledecimalTradable balance (available + held)
withdrawabledecimalWithdrawable balance (available only)
statusstringWallet status: active or frozen
updated_atdatetimeLast balance update time (ISO 8601)
Example response
{
  "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"
  }
}
GET/wallet/transactions/

Lists your wallet transactions in reverse chronological order. Supports filtering by type and date range.

Query parameters

tx_typestringFilter by transaction type: deposit withdraw trade_freeze trade_unfreeze trade_pay trade_income adjustment transfer_in transfer_out etc.
start_datestringStart date inclusive (ISO 8601 format: YYYY-MM-DD)
end_datestringEnd date inclusive (ISO 8601 format: YYYY-MM-DD)
pageintegerPage number (default: 1)
page_sizeintegerItems 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_nostringTransaction reference number
tx_typestringTransaction type
amountdecimalChange amount (positive = credit, negative = debit)
balance_beforedecimalAvailable balance before this transaction
held_beforedecimalHeld balance before this transaction
frozen_beforedecimalFrozen balance before this transaction
balance_afterdecimalAvailable balance after this transaction
held_afterdecimalHeld balance after this transaction
frozen_afterdecimalFrozen balance after this transaction
biz_typestringBusiness type (e.g. trade_freeze, adjustment)
biz_idstringRelated business reference (e.g. order number)
descriptionstringHuman-readable description
created_atdatetimeTransaction time (ISO 8601)
Example request
GET /api/v1/wallet/transactions/?start_date=2026-04-01&end_date=2026-04-14&page_size=2
Example response
{
  "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

Normal Flow
createdpendingcompleted
State Transitions
createdfailedPre-execution failure (item unavailable, insufficient balance, etc.)
pendingcancelledTrade offer expired or cancelled by admin
pendingfailedBuyer declined trade offer or technical failure
completedreversedCompleted trade reversed on Steam

Orders 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.

created

Order created, executing purchase

pending

Trade offer sent, awaiting acceptance

completed

Trade completed successfully

failed

Trade failed permanently

cancelled

Cancelled by timeout or admin

reversed

Completed 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.