Skip to content

Available Items

GET /api/v1/merchant/purchase/available

Returns available items with purchase prices for a given game.

Request

Headers

HeaderRequiredDescription
X-Api-KeyYour merchant API key
Acceptapplication/json

Query Parameters

ParameterTypeRequiredDescription
gamestringGame code: csgo, rust, dota2, tf2
fullbooleanWhen true, returns individual items with full details. Default (omitted or false) returns items grouped by name
extendedbooleanWhen true, includes class_id, instance_id, float, inspect_url, phase fields in each item (full format only)
pageintegerFetch one page of the catalogue instead of all of it. 1 to 16. Omit for the whole catalogue in a single response

Pagination

The full catalogue is large enough that taking it in one response is awkward. Pass page to walk it in parts instead.

There are always 16 pages, for every game and every merchant. A page is not a range of positions ("items 100 000 to 200 000"): it is a fixed slice of the catalogue keyed by item id. That is what makes a walk safe — items sold or added between two of your requests do not shift anything, so a walk from page 1 to page 16 never skips an item and never returns one twice, even if the catalogue changes underneath you.

Pages are not equal in size: each holds a fixed slice of the catalogue, not a fixed number of items, so a page of a large game carries more than a page of a small one.

bash
curl "https://api.skinslink.com/api/v1/merchant/purchase/available?game=csgo&full=true&extended=true&page=1" \
  -H "X-Api-Key: your-api-key" \
  --compressed

A paginated response carries the same items as an unpaginated one, with the walk's fields in front of them:

json
{
  "success": true,
  "message": "Successfully retrieved purchase prices",
  "data": {
    "game": "csgo",
    "total": 48000,
    "page": 1,
    "total_pages": 16,
    "count": 3010,
    "next": "https://api.skinslink.com/api/v1/merchant/purchase/available?extended=true&full=true&game=csgo&page=2",
    "previous": null,
    "items": [ ... ],
    "last_update_at": "2026-08-21T14:00:00Z"
  }
}
FieldTypeDescription
pageintegerThe page you asked for
total_pagesintegerAlways 16
countintegerItems on this page. Note this is not the catalogue size — that is total
totalintegerItems in the whole catalogue available to you
nextstring | nullURL of the next page, null on the last one
previousstring | nullURL of the previous page, null on the first one

Follow next until it is null, or loop pages 1 through 16 — a page past the last one simply returns an empty items list rather than an error.

Two things worth knowing:

  • 503 means retry, not failure. A page is served from the pre-built catalogue only. While it is being rebuilt you get 503 with a Retry-After header; wait that long and ask for the same page again. Your walk continues where it left off.
  • An item added after you passed its page arrives on your next walk, not this one. Nothing is lost — it simply appears one cycle later.

With full=false the response is small enough that pagination has nothing to do: it comes back as page 1 of 1, so the same loop works against both modes.

ETag is per page: send it back as If-None-Match and an unchanged page answers 304 with no body.

Response

Grouped format (default)

json
{
  "success": true,
  "message": "Successfully retrieved purchase prices",
  "data": {
    "game": "csgo",
    "total": 542,
    "items": [
      {
        "name": "AK-47 | Redline",
        "count": 3,
        "price": 11.20,
        "game": "csgo",
        "image_url": "https://steamcommunity-a.akamaihd.net/economy/image/class/730/..."
      }
    ]
  }
}

Full format (full=true)

json
{
  "success": true,
  "message": "Successfully retrieved purchase prices",
  "data": {
    "game": "csgo",
    "total": 1847,
    "items": [
      {
        "id": "38029384123",
        "name": "AK-47 | Redline (Field-Tested)",
        "price": 12.45,
        "image_url": "https://steamcommunity-a.akamaihd.net/economy/image/class/730/...",
        "exterior": "Field-Tested",
        "rarity": "Classified",
        "rarity_color": "#8650AC"
      }
    ]
  }
}

Response Fields (grouped)

FieldTypeDescription
gamestringGame code
totalintegerNumber of unique item names
itemsarrayList of items grouped by name
items[].namestringItem name
items[].countintegerNumber of items available with this name
items[].pricenumberMinimum price among items with this name (USD)
items[].gamestringGame code
items[].image_urlstringSteam CDN image URL

Response Fields (full)

FieldTypeDescription
gamestringGame code
totalintegerTotal number of available items
itemsarrayList of available items with prices
items[].idstringID — use this in Create Purchase
items[].namestringItem market name
items[].pricenumberPurchase price (USD)
items[].image_urlstringSteam CDN image URL
items[].exteriorstring | nullItem exterior condition (e.g. "Field-Tested", "Minimal Wear"). Omitted if unavailable
items[].raritystring | nullItem rarity name. Omitted if unavailable
items[].rarity_colorstring | nullRarity color hex code. Omitted if unavailable
items[].class_idinteger | nullSteam class ID. Only present when extended=true
items[].instance_idinteger | nullSteam instance ID. Only present when extended=true
items[].asset_idstring | nullSteam asset ID, as a string. Only present when extended=true
items[].floatnumber | nullItem float value. Only present when extended=true
items[].paint_seedinteger | nullPaint seed (pattern index). Only present when extended=true
items[].inspect_urlstring | nullSteam inspect link. Only present when extended=true
items[].phasestring | nullItem phase (e.g. "Ruby", "Sapphire"). Only present when extended=true

Where asset_id, float and paint_seed come from

These three are not part of every item's record. Where an item carries an inspect_url, we read them straight out of that link, so they are present even when the item reached the catalogue without them. Where there is no inspect link there is nothing to read, and the fields are absent — so expect them on much of the CS2 catalogue, but not on all of it.

Two cases where a link is present but a field still is not: some inspect links are generated for items already held in stock and name no particular asset, so asset_id is absent rather than wrong; and items that are not painted — stickers, cases, capsules — have no float or paint_seed to report. Treat every one of the three as optional.

item_id is not an asset ID: it identifies the offer in our catalogue and is what you pass to Create Purchase. Use asset_id when you need to line an item up against Steam.

The inspect link is always passed through untouched, so anything we do not surface — stickers, keychains, name tags, StatTrak counts — you can decode from it yourself.

Example

Get all available CS2 items

bash
curl "https://api.skinslink.com/api/v1/merchant/purchase/available?game=csgo" \
  -H "X-Api-Key: your-api-key" \
  -H "Accept: application/json"

Get full item details

bash
curl "https://api.skinslink.com/api/v1/merchant/purchase/available?game=csgo&full=true" \
  -H "X-Api-Key: your-api-key" \
  -H "Accept: application/json"

Get full item details with extended info (float, class_id, etc.)

bash
curl "https://api.skinslink.com/api/v1/merchant/purchase/available?game=csgo&full=true&extended=true" \
  -H "X-Api-Key: your-api-key" \
  -H "Accept: application/json"

WARNING

Prices and availability are point-in-time and may change between lookup and purchase creation. Items are re-priced at purchase time.

Errors

StatusMessageCause
400invalid game codeInvalid or missing game parameter
400validation errorMissing or invalid fields
401missing authorization headerX-Api-Key header not provided
401invalid API keyAPI key not found or inactive
403merchant account is disabledMerchant account deactivated
403invalid IP: <ip>Request IP not in whitelist
400page must be 1 or greaterpage is zero, negative or not a number
503internal errorPricing service temporarily unavailable — retry
503catalogue page is being rebuilt, retry shortlyOnly when page is used. Wait for Retry-After seconds and repeat the same request