Skip to content

Skinslink API — LLM Reference

Single-page API reference optimized for LLMs, AI agents, and code generation tools. For full interactive docs, see the API Reference.

Overview

Skinslink is a Steam skin trading platform. Merchants integrate with Skinslink to accept Steam item deposits from users and purchase skins for delivery to users. The API handles inventory pricing, deposit creation, skin purchases, trade offer management, and status tracking via webhooks.

Base URL: https://api.skinslink.com/api/v1

Auth: All requests require X-Api-Key: <your-api-key> header.

Response envelope: Every response follows { "success": bool, "message": string, "data": ... }.

Supported games: csgo (CS2), rust, dota2, tf2


Endpoints

POST /merchant/create-intent

Creates a deposit intent for the redirect flow. Returns a URL where the user completes the deposit on Skinslink's hosted page.

Request body (JSON):

FieldTypeRequiredDescription
merchant_tx_idstringyesYour unique order ID
gamestringnocsgo, rust, dota2, tf2
partnerintegernoSteam trade partner ID
tokenstringnoSteam trade token
result_urlstringnoWebhook URL override for this deposit
success_urlstringnoRedirect URL on success
fail_urlstringnoRedirect URL on failure
custom_currencystringnoCurrency code (1–4 chars). Requires all 3 currency fields
custom_currency_multipliernumbernoMultiplier (0.5–2.0)
custom_currency_ratenumbernoExchange rate (≥ 0.1)

Response data: { "id": int, "merchant_tx_id": string, "url": string }

Example:

bash
curl -X POST https://api.skinslink.com/api/v1/merchant/create-intent \
  -H "X-Api-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{"merchant_tx_id":"order-123","game":"csgo","partner":123456789,"token":"AbCdEfGh"}'

POST /merchant/inventory

Fetches a user's Steam inventory with real-time pricing.

Request body (JSON):

FieldTypeRequiredDescription
gamestringyescsgo, rust, dota2, tf2
partnerintegeryesSteam trade partner ID
tokenstringyesSteam trade token (exactly 8 characters)

Response data:

json
{
  "items": [
    {
      "id": "38029384123",
      "name": "AK-47 | Redline (Field-Tested)",
      "price": 12.45,
      "image_url": "https://community.cloudflare.steamstatic.com/economy/image/...",
      "exterior": "Field-Tested",
      "rarity": "Classified",
      "rarity_color": "#d32ce6"
    }
  ],
  "total": 47,
  "sum": 284.90,
  "game": "csgo"
}

Notes:

  • Cached responses: ~100–200ms. Fresh fetch: ~1–4s.
  • Prices are point-in-time; items are re-priced at deposit creation.
  • Use items[].id as asset_ids in create-deposit.

Example:

bash
curl -X POST https://api.skinslink.com/api/v1/merchant/inventory \
  -H "X-Api-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{"game":"csgo","partner":123456789,"token":"AbCdEfGh"}'

POST /merchant/create-deposit

Creates a deposit with selected Steam items. Returns trade offer details.

Request body (JSON):

FieldTypeRequiredDescription
merchant_tx_idstringyesYour unique order ID
gamestringyescsgo, rust, dota2, tf2
partnerintegeryesSteam trade partner ID
tokenstringyesSteam trade token
asset_idsstring[]yesItem IDs from inventory response
result_urlstringnoWebhook URL override for this deposit
success_urlstringnoRedirect URL on success
fail_urlstringnoRedirect URL on failure
custom_currencystringnoCurrency code (1–4 chars). Requires all 3 currency fields
custom_currency_multipliernumbernoMultiplier (0.5–2.0)
custom_currency_ratenumbernoExchange rate (≥ 0.1)

Response data:

json
{
  "id": 42,
  "merchant_tx_id": "order-123",
  "status": "active",
  "amount": 36.25,
  "bot_name": "Skinslink Bot #3",
  "bot_steam_id": 76561199012345678,
  "trade_offer_id": "6912345678",
  "trade_offer_expiry_at": "2026-02-16T12:30:00Z"
}

Notes:

  • Status is active on success, failed on error.
  • bot_name, bot_steam_id, trade_offer_id may be null if the bot hasn't assigned yet.
  • Custom currency fields are not included in the create-deposit response. Use GET /merchant/deposit/status to retrieve them once the trade reaches hold or completed.

Example:

bash
curl -X POST https://api.skinslink.com/api/v1/merchant/create-deposit \
  -H "X-Api-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{"merchant_tx_id":"order-123","game":"csgo","partner":123456789,"token":"AbCdEfGh","asset_ids":["38029384123","38029384124"]}'

POST /merchant/get-prices

Quotes provider prices by market hash name. By default also creates a draft trade record (status new) that locks the quote for 5 minutes; commit it with create-deposit-by-hash-name using the returned id.

Request headers:

  • X-Api-Key (required)
  • X-Provider (optional) — comma-separated provider whitelist

Request body (JSON):

FieldTypeRequiredDescription
gamestringyescsgo, rust, dota2, tf2
marketHashNamesstring[]yesItem market hash names. Min 1, max 2000
no_deposit_intentbooleannoWhen true, skip trade creation (price-only quote). Default false

Response data:

json
{
  "id": 742,
  "total": 2,
  "sum": 45.50,
  "items": [
    { "name": "AK-47 | Redline (Field-Tested)", "price": 22.75, "originalPrice": 23.10 }
  ]
}

Notes:

  • id is the trade ID — pass to create-deposit-by-hash-name. Omitted when no_deposit_intent=true.
  • price is the final price after multipliers; originalPrice is the provider's raw price.
  • Trade quote is valid for 5 minutes.
  • Empty inventory deletes the draft trade and returns total: 0, sum: 0, items: [] with no id.
  • Provider selection respects deposit toggles, circuit breakers, merchant exclusions, and the X-Provider header.
  • 502 returned when upstream pricing service is unreachable.

Example:

bash
curl -X POST https://api.skinslink.com/api/v1/merchant/get-prices \
  -H "X-Api-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{"game":"csgo","marketHashNames":["AK-47 | Redline (Field-Tested)"]}'

POST /merchant/create-deposit-by-hash-name

Commits a deposit using a quote id from get-prices. Identifies items by market hash name + Steam asset_id. Supports per-item min_price price-drop protection.

Request headers:

  • X-Api-Key (required)
  • X-Provider (optional) — comma-separated provider whitelist

Request body (JSON):

FieldTypeRequiredDescription
idintegeryesTrade ID from get-prices (min 1)
merchant_tx_idstringyesYour unique order ID (overwrites the temporary ID from get-prices)
gamestringyescsgo, rust, dota2, tf2
partnerintegeryesSteam trade partner ID
tokenstringyesSteam trade token (exactly 8 chars)
itemsobject[]yesItems to deposit (min 1)
items[].asset_idstringyesSteam asset ID (numeric string)
items[].namestringyesMarket hash name (must match a name in get-prices)
items[].min_pricenumbernoMinimum acceptable price (USD); deposit fails if current price drops below
result_urlstringnoWebhook URL override
success_urlstringnoSuccess redirect URL
fail_urlstringnoFailure redirect URL
custom_currencystringnoCurrency code (1–4 chars). Requires all 3 currency fields
custom_currency_multipliernumbernoMultiplier (0.5–2.0)
custom_currency_ratenumbernoExchange rate (≥ 0.1)

Response data: Same shape as POST /merchant/create-deposit (id, merchant_tx_id, status, amount, bot_name, bot_steam_id, trade_offer_id, trade_offer_expiry_at).

Processing:

  1. Validates Steam trade key.
  2. Loads trade by id, verifies merchant ownership and status new.
  3. Writes merchant_tx_id + game/partner/token/URLs in a DB transaction → status pending.
  4. 5-minute price expiry — if quote is older than 5 minutes, fails with inventory_reload.
  5. Recalculates resale margin using cached inventory data.
  6. min_price check — fails with item_specified_price_not_found if any item's current price < its min_price.
  7. Inserts trade items.
  8. Dispatches to provider (30s timeout, detached from client).
  9. On provider failure → failed + fail_reason: provider_unavailable. On success → active.

Fail reasons: item_specified_price_not_found, provider_unavailable

Errors: 400 (validation, expired prices, min_price not met), 401 (invalid key), 404 (trade not found / not yours), 409 (duplicate merchant_tx_id), 500.

Example:

bash
curl -X POST https://api.skinslink.com/api/v1/merchant/create-deposit-by-hash-name \
  -H "X-Api-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{"id":742,"merchant_tx_id":"order-9999","game":"csgo","partner":123456789,"token":"AbCdEfGh","items":[{"asset_id":"38029384123","name":"AK-47 | Redline (Field-Tested)","min_price":20.00}]}'

GET /merchant/deposit/status

Retrieves current status of a deposit.

Query parameters:

FieldTypeRequiredDescription
idintegerone requiredInternal trade ID
merchant_tx_idstringone requiredYour order ID

At least one of id or merchant_tx_id must be provided.

Response data:

json
{
  "id": 42,
  "merchant_tx_id": "order-123",
  "status": "completed",
  "bot_steam_id": 76561199012345678,
  "bot_name": "Skinslink Bot #3",
  "trade_offer_id": "6912345678",
  "trade_offer_expiry_at": "2026-02-16T12:30:00Z",
  "success_url": "https://yoursite.com/deposit/success",
  "fail_url": "https://yoursite.com/deposit/failed",
  "hold_end_date": null,
  "fail_reason": null,
  "custom_currency": "EUR",
  "custom_currency_multiplier": 1.0,
  "custom_currency_rate": 0.92,
  "custom_currency_sum": 33.35
}

Notes:

  • Custom currency fields only included when status is hold or completed.
  • success_url and fail_url are only present if set on the deposit. hold_end_date is only present when status is hold. fail_reason is only present when status is failed or canceled.
  • For real-time updates, use webhooks instead of polling.

Example:

bash
curl "https://api.skinslink.com/api/v1/merchant/deposit/status?merchant_tx_id=order-123" \
  -H "X-Api-Key: your-api-key"

Purchase Endpoints

POST /merchant/purchase

Creates a skin purchase. Skinslink sends a trade offer with the requested item to the specified Steam account.

Request body (JSON):

FieldTypeRequiredDescription
partnerintegeryesSteam trade partner ID (minimum: 8)
tokenstringyesSteam trade token (exactly 8 characters)
gamestringyescsgo, rust, dota2, tf2
namestringconditionalItem market name. Provide either name or asset_id
asset_idstringconditionalSpecific asset ID. Provide either name or asset_id
merchant_tx_idstringnoYour unique order ID
max_pricenumbernoMaximum price you're willing to pay (USD)

Response data:

json
{
  "id": 178,
  "merchant_tx_id": "order-123",
  "status": "pending",
  "steam_name": "John Doe",
  "steam_avatar_url": "https://avatars.steamstatic.com/...",
  "trade_offer_id": null,
  "fail_reason": null,
  "steam_id": "76561198338314767",
  "amount": 45.99,
  "date": "2026-03-24T10:30:00Z",
  "item": {
    "id": "38029384123",
    "name": "AK-47 | Redline (Field-Tested)",
    "price": 45.99,
    "image_url": "https://community.cloudflare.steamstatic.com/economy/image/..."
  }
}

Note: Optional fields (merchant_tx_id, fail_reason, steam_name, steam_avatar_url, trade_offer_id, item) are omitted from the response when not available — they will not appear as null.

Fail reasons: insufficient_balance, price_changed, item_not_available, item_specified_price_not_found, provider_unavailable

Example:

bash
curl -X POST https://api.skinslink.com/api/v1/merchant/purchase \
  -H "X-Api-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{"partner":123456789,"token":"AbCdEfGh","game":"csgo","name":"AK-47 | Redline (Field-Tested)","merchant_tx_id":"order-123"}'

GET /merchant/purchase/status

Retrieves current status of a purchase.

Query parameters:

FieldTypeRequiredDescription
idintegerone requiredPurchase ID
merchant_tx_idstringone requiredYour order ID

At least one of id or merchant_tx_id must be provided.

Response data: Same as POST /merchant/purchase response.

Example:

bash
curl "https://api.skinslink.com/api/v1/merchant/purchase/status?merchant_tx_id=order-123" \
  -H "X-Api-Key: your-api-key"

GET /merchant/purchase

Retrieves purchase history with pagination and filtering.

Query parameters:

FieldTypeRequiredDescription
limitintegernoItems per page
offsetintegernoPagination offset
statusstringnoFilter: new, pending, active, hold, completed, failed, canceled, reverted
date_rangeintegernoDays to look back: 1, 7, 30, 90, 365
searchstringnoSearch query (1-100 chars)
sortstringnoSort: id, -id, merchant_tx_id, -merchant_tx_id, status, -status, amount, -amount, created_at, -created_at

Response data: { "data": [PurchaseResponse, ...], "total": int }

Example:

bash
curl "https://api.skinslink.com/api/v1/merchant/purchase?limit=100&status=completed" \
  -H "X-Api-Key: your-api-key"

GET /merchant/purchase/available

Returns available items with purchase prices for a given game.

Query parameters:

FieldTypeRequiredDescription
gamestringyescsgo, rust, dota2, tf2
fullbooleannoWhen true, returns individual items with full details. Default returns items grouped by name
extendedbooleannoWhen true, includes class_id, instance_id, float, inspect_url, phase in each item (full format only)

Response data (grouped, default):

json
{
  "game": "csgo",
  "total": 542,
  "items": [
    {
      "name": "AK-47 | Redline",
      "count": 3,
      "price": 11.20,
      "game": "csgo",
      "image_url": "https://community.cloudflare.steamstatic.com/economy/image/..."
    }
  ]
}

Response data (full, full=true):

json
{
  "game": "csgo",
  "total": 1847,
  "items": [
    {
      "id": "38029384123",
      "name": "AK-47 | Redline (Field-Tested)",
      "price": 12.45,
      "image_url": "https://community.cloudflare.steamstatic.com/economy/image/...",
      "exterior": "Field-Tested",
      "rarity": "Classified",
      "rarity_color": "#8650AC"
    }
  ]
}

Notes:

  • Prices and availability are point-in-time; items are re-priced at purchase time.
  • Use items[].id or items[].name + game in POST /merchant/purchase.
  • exterior, rarity, rarity_color are included when available. class_id, instance_id, float, inspect_url, phase are only included when extended=true (full format only).

Example:

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

Returns purchase prices for specific item names.

Query parameters:

FieldTypeRequiredDescription
gamestringyescsgo, rust, dota2, tf2
namesstring[]yesItem names (names=Item1&names=Item2)
extendedbooleannoWhen true, includes class_id, instance_id, float, inspect_url, phase in each item

Response data: Same format as GET /merchant/purchase/available full format (full=true). Supports extended=true for the same extended fields.

Example:

bash
curl "https://api.skinslink.com/api/v1/merchant/purchase/search?game=csgo&names=AK-47+%7C+Redline+(Field-Tested)" \
  -H "X-Api-Key: your-api-key"

Transaction Status Machine

new → pending → active → completed
 |       |        |
 |       |        ├→ hold → completed
 |       |        |           |
 |       |        |           └→ reverted
 |       |        ├→ failed
 |       |        └→ canceled
 |       ├→ failed
 |       └→ canceled
 └→ canceled
StatusDescriptionTerminal
newCreated, not yet processedno
pendingAwaiting trade offer creationno
activeTrade offer sent, waiting for user to acceptno
holdItems on Steam 7-day trade holdno
completedSuccessful, items transferredyes
failedTransaction failedyes
canceledTransaction canceledyes
revertedHeld transaction reversedyes

Webhooks

Skinslink sends POST requests to your webhook URL when trade statuses change.

Webhook-triggering statuses: hold, completed, failed, canceled, reverted

Statuses that do NOT trigger webhooks: new, pending, active

Payload:

json
{
  "sign": "b64EncodedSHA256Signature==",
  "status": "completed",
  "trade_id": 178,
  "trade_date": "2026-02-16T12:00:00Z",
  "merchant_tx_id": "order-123",
  "steam_id": "76561198338314767",
  "offer_id": "6912345678",
  "amount": 36.25,
  "amount_currency": "usd",
  "hold_end_date": null,
  "fail_reason": null
}

Signature verification:

sign = base64( sha256( trade_id + merchant_secret ) )
  • Custom currency fields are not yet included in webhook payloads. Use GET /merchant/deposit/status to retrieve custom currency data for hold/completed trades.
  • hold_end_date is included when status is hold. fail_reason is included when status is failed or canceled.
  • Respond 200 OK quickly; process asynchronously.
  • Retries with exponential backoff on non-2xx responses.
  • Deduplicate using merchant_tx_id + status.

Purchase Webhooks

Payload:

json
{
  "sign": "b64EncodedSHA256Signature==",
  "status": "completed",
  "purchase_id": 178,
  "trade_date": "2026-03-24T10:30:00Z",
  "merchant_tx_id": "order-123",
  "asset_id": "38029384123",
  "offer_id": "6912345678",
  "amount": 45.99,
  "amount_currency": "usd",
  "fail_reason": null
}

Signature verification:

sign = base64( sha256( purchase_id + merchant_secret ) )
  • purchase_id is an integer — convert to string before hashing.
  • Purchase webhooks always use your merchant-level webhook URL (no per-purchase override).
  • Same retry behavior and deduplication as deposit webhooks.
  • Unlike deposit webhooks, purchase webhooks ARE sent for active status (trade offer sent to user). Statuses new and pending do not trigger notifications.
  • fail_reason — string | null. Only present when status is failed.

Error Handling

Error response: { "success": false, "message": "error description" }

Validation errors include field details:

json
{
  "success": false,
  "message": "validation error",
  "data": [
    { "field": "InventoryRequest.game", "code": "required", "message": "game is a required field" }
  ]
}
HTTP CodeMeaning
400Bad request / validation error
401Missing or invalid API key
403Merchant disabled or IP not whitelisted
404Resource not found
408Timeout (retry)
409Duplicate merchant_tx_id
500Internal error (retry)
502Upstream service error (retry)

Domain-Specific Validation Error Codes

When message is validation error, the data array may contain these domain-specific codes in addition to standard validation codes (required, len, oneof):

FieldCodeMeaning
merchant_tx_idexistDuplicate merchant_tx_id
inventoryinventory_reloadInventory data is stale — refetch before retrying
tokentrade_link_revokedUser reset their Steam trade URL
partnertrade_link_invalidSteam trade link is incorrect or expired
partnertrade_bannedUser's Steam account has a trade ban
partnerprofile_privateUser's Steam profile is private
partnerlimited_accountLimited Steam account (hasn't spent $5 on Steam)
partnerholdTemporary Steam trade hold is active
gamepermissionsUser's Steam inventory for this game is private
partnerhold_and_permissionsTrade hold + game permission issues combined

These codes apply to POST /merchant/create-intent, POST /merchant/create-deposit, POST /merchant/inventory, and POST /merchant/purchase. The code field is stable and safe for programmatic error handling.


Integration Flows

Flow 1: Redirect (with UI)

  1. POST /merchant/create-intent → get url
  2. Redirect user to url
  3. User selects items and confirms on Skinslink's page
  4. Receive webhook with final status

Flow 2: API-only (without UI)

  1. POST /merchant/inventory → get items with prices
  2. User selects items on your UI
  3. POST /merchant/create-deposit with selected asset_ids → get trade offer info
  4. User accepts Steam trade offer
  5. Receive webhook with final status
  6. Optionally poll GET /merchant/deposit/status for real-time tracking

Flow 3: Iframe

  1. POST /merchant/create-intent → get url
  2. Load url as iframe src inside your page
  3. User selects items and confirms trade inside the iframe
  4. Iframe sends window.postMessage events to parent with { type: "skinslink:deposit-status", txId: string, status: string }
  5. Statuses: new, active, hold, completed, canceled, failed
  6. Use PostMessage for real-time UI updates; rely on server-side webhooks for balance crediting

Flow 4: Purchase

  1. GET /merchant/purchase/available?game=csgo → browse available items
  2. User selects an item on your UI (or use GET /merchant/purchase/search for specific items)
  3. POST /merchant/purchase with item details and Steam credentials → get purchase info
  4. User accepts the Steam trade offer
  5. Receive webhook with final status
  6. Optionally poll GET /merchant/purchase/status for real-time tracking

Flow 5: Hash-Name Deposit (API)

  1. POST /merchant/get-prices with game + marketHashNames → get id, prices (5-minute quote window)
  2. Show quote to the user; user confirms
  3. POST /merchant/create-deposit-by-hash-name with id, merchant_tx_id, Steam credentials, and per-item {asset_id, name, min_price?} → get trade offer info
  4. User accepts the Steam trade offer
  5. Receive webhook with final status
  6. Optionally poll GET /merchant/deposit/status for real-time tracking

Use this flow when you already know the item names and want a confirmed price quote (with optional per-item min_price floor) before committing.


Quick Reference

ActionMethodEndpoint
Create intent (redirect flow)POST/merchant/create-intent
Get inventoryPOST/merchant/inventory
Create deposit (API flow)POST/merchant/create-deposit
Get prices by hash namePOST/merchant/get-prices
Create deposit by hash namePOST/merchant/create-deposit-by-hash-name
Check statusGET/merchant/deposit/status
Browse available itemsGET/merchant/purchase/available
Search items by nameGET/merchant/purchase/search
Create purchasePOST/merchant/purchase
Check purchase statusGET/merchant/purchase/status
Purchase historyGET/merchant/purchase

Auth header: X-Api-Key: your-api-key

Games: csgo, rust, dota2, tf2