Appearance
Items API
Browse, search, and purchase items on the marketplace.
Base path: /api/items
List All Items
GET /api/items
Returns all items currently for sale. Results are cached for 60 seconds per game_id.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
game_id | number | No | Game ID filter. Default: 730 |
include_hold | boolean | No | Also include trade-locked items. Default: false. Held items are appended with hold: true and an unhold_at ISO timestamp; they are cached separately for 60 seconds. See the Holds API |
Headers
| Header | Description |
|---|---|
x-api-key | API key for authentication |
x-inspect-password | If provided, sensitive fields (inspect, bot_id) are included |
Rate Limit
4 requests per minute per user. Response includes X-RateLimit-Limit and X-RateLimit-Remaining headers.
Cache
60 seconds per game_id
bash
curl -X GET "https://market.vpsbot.io/api/items?game_id=730" \
-H "x-api-key: YOUR_API_KEY"js
const { data } = await client.get('/items', {
params: { game_id: 730 }
});Example Response
json
{
"success": true,
"data": [
{
"market_id": "abc123",
"asset_id": "30000000001",
"game_id": 730,
"instanceid": "302028390",
"classid": "310776560",
"market_hash_name": "AK-47 | Redline (Field-Tested)",
"phase": null,
"float": 0.2531,
"paint_index": 282,
"paint_seed": 412,
"rarity_color": "#D2D2D2",
"price": 1245,
"icon_url": "https://steamcdn-a.akamaihd.net/...",
"stickers": [],
"inspect": null,
"bot_id": null,
"instant_delivery": false,
"average_delivery_time": 1680,
"delivery_rate": 98.5
}
]
}Delivery — average_delivery_time, delivery_rate
| Field | Type | Description |
|---|---|---|
average_delivery_time | integer | null | Average delivery time, in seconds |
delivery_rate | number | null | Delivery success rate, percent 0–100 |
Both are null when not available for an item.
The same two fields appear on GET /api/items/:asset_id and on every item body sent over the WebSocket.
Delivery speed — instant_delivery
Every catalog item carries an explicit boolean:
| Value | Meaning |
|---|---|
true | standard delivery — the Steam trade offer is usually created within seconds |
false | slower fulfilment — the offer can take minutes up to ~1 hour to arrive |
Nothing else about the purchase changes: the buy request, statuses and refund behaviour are identical. For instant_delivery: false items simply poll GET /api/trades (or listen on the WebSocket) until the offer appears.
The value can change over time; the change arrives over the WebSocket like any other item update.
Filtering — instant_delivery query parameter
GET /api/items accepts an optional instant_delivery=true|false filter: true returns only near-instant items, false only slower-fulfilment items, and omitting it returns the mixed catalog. The same parameter works on GET /public/prices and the deprecated GetAllItemsOnSale.
bash
curl 'https://market.vpsbot.io/api/items?game_id=730&instant_delivery=true' \
-H 'x-api-key: YOUR_KEY'Get Item by Asset ID
GET /api/items/:asset_id
Returns a single item by its Steam asset ID.
Cached — safe to poll
Responses are served from a 60-second server-side cache that is rewritten the instant any purchase or status change touches the asset (the same computation is pushed as the market-items-changed websocket event). Rapid consecutive requests hit the cache, and a change is visible on the very next request — you never wait out the TTL for purchase-driven changes.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
asset_id | string | Yes | Steam asset ID |
Headers
| Header | Description |
|---|---|
x-api-key | API key for authentication |
x-inspect-password | If provided, sensitive fields are included |
bash
curl -X GET "https://market.vpsbot.io/api/items/30000000001" \
-H "x-api-key: YOUR_API_KEY"js
const { data } = await client.get('/items/30000000001');Example Response
json
{
"success": true,
"data": {
"market_id": "abc123",
"asset_id": "30000000001",
"game_id": 730,
"market_hash_name": "AK-47 | Redline (Field-Tested)",
"phase": null,
"float": 0.2531,
"price": 1245,
"icon_url": "https://steamcdn-a.akamaihd.net/...",
"stickers": [],
"average_delivery_time": 4,
"delivery_rate": 100
}
}Search Items
POST /api/items/search
Search items by market hash names or market IDs. At least one search parameter is required.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
market_ids | string[] | No | Array of internal market IDs |
market_hash_names | string[] | No | Array of Steam market hash names |
phases | string[] | No | Filter by Doppler phases |
WARNING
At least one of market_ids or market_hash_names must be provided.
Rate Limit
150 requests per minute per user.
bash
curl -X POST "https://market.vpsbot.io/api/items/search" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"market_hash_names": [
"AK-47 | Redline (Field-Tested)",
"AWP | Asiimov (Field-Tested)"
]
}'js
const { data } = await client.post('/items/search', {
market_hash_names: [
'AK-47 | Redline (Field-Tested)',
'AWP | Asiimov (Field-Tested)'
]
});Example Response
json
{
"success": true,
"data": [
{
"market_id": "abc123",
"asset_id": "30000000001",
"game_id": 730,
"market_hash_name": "AK-47 | Redline (Field-Tested)",
"phase": null,
"float": 0.2531,
"price": 1245,
"icon_url": "https://steamcdn-a.akamaihd.net/...",
"stickers": []
}
]
}Buy Item by Asset ID
POST /api/items/buy
Purchase a specific item by its asset ID. Deducts the price from your balance and initiates a Steam trade.
Trade-locked items
Items under a Steam trade hold cannot be bought with this endpoint — the purchase is refused with code: "item_on_trade_hold" (see Refused Purchase). Buy them via the Holds API instead.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
asset_id | string | Yes | Steam asset ID to purchase |
game_id | number | Yes | Game ID (e.g., 730) |
trade_url | string | Yes | Your Steam trade offer URL |
price | number | Yes | Expected price (must match current price) |
custom_id | string | null | No | Your custom reference ID for this trade |
bash
curl -X POST "https://market.vpsbot.io/api/items/buy" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"asset_id": "30000000001",
"game_id": 730,
"trade_url": "https://steamcommunity.com/tradeoffer/new/?partner=XXXXX&token=YYYYY",
"price": 1245,
"custom_id": "order-001"
}'js
const { data } = await client.post('/items/buy', {
asset_id: '30000000001',
game_id: 730,
trade_url: 'https://steamcommunity.com/tradeoffer/new/?partner=XXXXX&token=YYYYY',
price: 1245,
custom_id: 'order-001'
});
if (!data.success) {
// A refused purchase answers HTTP 200: branch on data.code
console.log(`Purchase refused: ${data.code} (${data.error})`);
}Example Response
json
{
"success": true,
"data": {
"trade_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"steam_trade_id": "5234567890", // may be null at first — see note below
"custom_id": "order-001",
"trade_url": "https://steamcommunity.com/tradeoffer/new/?partner=XXXXX&token=YYYYY",
"asset_id": "30000000001",
"market_hash_name": "AK-47 | Redline (Field-Tested)",
"phase": null,
"price": 1245,
"status": "processing",
"summary": "InProgress",
"steam_trade_status": "Active"
}
}steam_trade_id can be null
The Steam offer is created asynchronously. steam_trade_id may be null in the buy response (and, for some fulfilment paths, stay null in GET /api/trades even after delivery). Track the purchase by trade_id / custom_id and rely on status (processing → accepted → completed), not on the offer id.
Refused Purchase
If the purchase cannot go through, it is refused and your balance is not charged: an amount already debited is refunded before the response is sent. The response is HTTP 200 with success: false, a machine-readable code and a human-readable error:
json
{
"success": false,
"code": "trade_partner_banned",
"error": "Your Steam account has a trade ban and cannot receive trade offers"
}code | error | Meaning |
|---|---|---|
item_not_found | Item not found or already sold | The item is no longer for sale. On buy-by-name: no item matches the name and phase within max_price |
item_unavailable | Item is no longer available | The item was still listed, but the seller can no longer deliver it. Your balance is not charged. Pick another listing |
item_on_trade_hold | Item is on trade hold | The item is under a Steam trade hold. Buy it via the Holds API |
price_changed | Price mismatch: listing price does not match the offered price | The listing price differs from the price you sent, or it changed while the purchase was being placed. Fetch the current price and retry |
insufficient_balance | Insufficient balance to buy the item | Your available balance is below the item price |
duplicate_custom_id | A trade with this custom_id already exists | A purchase with this custom_id already exists. Look it up in GET /api/trades, or send a new custom_id |
item_reserved | Item is being purchased by another buyer; please retry | Another buyer is purchasing this item right now. Retry shortly |
invalid_trade_url | The trade URL cannot receive trade offers | Your trade_url cannot receive trade offers: it is malformed or out of date (regenerate it in Steam), or the account cannot trade right now. Check the URL |
trade_partner_banned | Your Steam account has a trade ban and cannot receive trade offers | The Steam account behind your trade_url has a trade ban and cannot receive trade offers. Retrying fails the same way until the ban is lifted |
trade_banned | The bot for this trade has a Steam trade ban | The bot holding this item has a Steam trade ban and cannot deliver it. Retrying this item fails the same way while the ban lasts |
Check success and code, not the HTTP status
A refused purchase still answers HTTP 200. Always check success, and when it is false, branch on code rather than on the error text. HTTP 4xx / 5xx keep their usual meaning: an invalid request answers 400 with code: "validation_failed", a server failure answers 500 with code: "internal_error". See Response Format.
Hold purchases have their own codes: see Refused Hold Purchase.
Buy Item by Name
POST /api/items/buy-by-name
Purchase the cheapest available item matching the given market hash name. Useful when you don't care about a specific listing.
Trade-locked items
Items under a Steam trade hold are refused with code: "item_on_trade_hold" — they can only be bought via the Holds API.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
market_hash_name | string | Yes | Steam market hash name |
game_id | number | Yes | Game ID (e.g., 730) |
phase | string | null | No | Doppler phase filter |
trade_url | string | Yes | Your Steam trade offer URL |
max_price | number | Yes | Maximum price you're willing to pay |
custom_id | string | null | No | Your custom reference ID |
bash
curl -X POST "https://market.vpsbot.io/api/items/buy-by-name" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"market_hash_name": "AK-47 | Redline (Field-Tested)",
"game_id": 730,
"phase": null,
"trade_url": "https://steamcommunity.com/tradeoffer/new/?partner=XXXXX&token=YYYYY",
"max_price": 1500,
"custom_id": "order-002"
}'js
const { data } = await client.post('/items/buy-by-name', {
market_hash_name: 'AK-47 | Redline (Field-Tested)',
game_id: 730,
phase: null,
trade_url: 'https://steamcommunity.com/tradeoffer/new/?partner=XXXXX&token=YYYYY',
max_price: 1500,
custom_id: 'order-002'
});
if (!data.success) {
// A refused purchase answers HTTP 200: branch on data.code
console.log(`Purchase refused: ${data.code} (${data.error})`);
}Example Response
json
{
"success": true,
"data": {
"trade_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"steam_trade_id": "5234567891",
"custom_id": "order-002",
"trade_url": "https://steamcommunity.com/tradeoffer/new/?partner=XXXXX&token=YYYYY",
"asset_id": "30000000001",
"market_hash_name": "AK-47 | Redline (Field-Tested)",
"phase": null,
"price": 1245,
"status": "processing",
"summary": "InProgress",
"steam_trade_status": "Active"
}
}Refused Purchase
Same as POST /api/items/buy: a refused purchase answers HTTP 200 with success: false, a machine-readable code and a human-readable error, with the same codes. When no item matches the name and phase within max_price, the code is item_not_found. Your balance is not charged.
Recently Sold Items
GET /api/items/recently-sold
Returns asset IDs of items sold in the last 10 seconds. Useful for filtering out unavailable items from your local cache.
Cache
10 seconds
bash
curl -X GET "https://market.vpsbot.io/api/items/recently-sold" \
-H "x-api-key: YOUR_API_KEY"js
const { data } = await client.get('/items/recently-sold');Example Response
json
{
"success": true,
"data": [
"30000000001",
"30000000042",
"30000000099"
]
}Check Availability
POST /api/items/check-availability
Check if an item can be purchased before attempting to buy.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
asset_id | string | No | Steam asset ID |
market_id | string | No | Internal market ID |
bash
curl -X POST "https://market.vpsbot.io/api/items/check-availability" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"asset_id": "30000000001"}'js
const { data } = await client.post('/items/check-availability', {
asset_id: '30000000001'
});Example Response
json
{
"success": true,
"data": {
"can_buy": true,
"bot_id": "76561198...",
"reason": null
}
}Every response carries can_hold_buy. For an item under a Steam trade hold that is hold-sellable, can_buy is false but can_hold_buy is true, together with the hold listing price and the unlock timestamp — buy it via the Holds API:
json
{
"success": true,
"data": {
"can_buy": false,
"can_hold_buy": true,
"bot_id": "76561199...",
"reason": "trade_hold",
"hold_price": 2800,
"unhold_at": "2026-08-19T07:00:00Z"
}
}A trade-locked item without a hold price range set by its seller reports can_hold_buy: false. Regular (unlocked, listed) items report can_buy: true, can_hold_buy: false.
Held items in Get Item by Asset ID
GET /api/items/:asset_id also resolves hold-sellable trade-locked items: instead of a 404 it returns the item with hold: true, unhold_at, and price set to the hold listing price.
Get Item Availability
GET /api/items/:asset_id/availability
Check whether a specific item is available and not banned.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
asset_id | string | Yes | Steam asset ID |
bash
curl -X GET "https://market.vpsbot.io/api/items/30000000001/availability" \
-H "x-api-key: YOUR_API_KEY"js
const { data } = await client.get('/items/30000000001/availability');Example Response
json
{
"success": true,
"data": {
"asset_id": "30000000001",
"available": true,
"banned": false,
"reason": null
}
}Item Object Schema
| Field | Type | Description |
|---|---|---|
market_id | string | null | Internal market listing ID |
asset_id | string | Steam asset ID |
game_id | number | Game ID (730, 570, 252490, 440) |
instanceid | string | Steam instance ID |
classid | string | Steam class ID |
market_hash_name | string | Steam market hash name |
phase | string | null | Doppler phase (e.g., "Phase 1") |
float | number | null | Float value (wear) |
paint_index | number | null | Paint index |
paint_seed | number | null | Paint seed |
rarity_color | string | null | Hex color code for rarity |
price | number | null | Price (1$ = 1000) |
icon_url | string | Steam CDN icon URL |
stickers | object | Sticker data |
inspect | string | null | Inspect link (requires x-inspect-password) |
bot_id | string | Bot Steam ID (requires x-inspect-password) |
source_id | string | null | Fulfilment source: local, an instant-delivery market, or a provider key (requires x-inspect-password) |
hold | boolean | Optional. true when the item is under a Steam trade hold (only returned with include_hold=true) |
unhold_at | string | Optional. ISO timestamp of when the trade hold ends (held items only) |
Buy Response Fields
The buy response includes status fields for tracking the trade lifecycle:
| Field | Type | Description |
|---|---|---|
trade_id | string | Internal trade identifier (UUID) |
steam_trade_id | string | null | Steam trade offer ID |
status | string | IMT status (processing on creation) |
summary | string | Business-level status (InProgress on creation) |
steam_trade_status | string | null | Steam trade status string (e.g. Active) |
TIP
For full status reference (all possible status, summary, and steam_trade_status values), see the Trades API.