BUFF sale history is now available - POST /v1/archive/buff returns sale prices and daily total supply since September 2024.

How to Build a CS2 Skin Arbitrage Bot

Updated

Endpoints used: GET /v1/prices/latest, GET /v1/liquidity/items & GET /v1/schema

A CS2 skin arbitrage bot should compare the current ask on one cash marketplace with the current bid on another, subtract every fee and transfer cost, reject stale or illiquid markets, and alert or trade only when the remaining profit clears a safety margin. cs2.sh's GET /v1/prices/latest supplies the cross-market prices; GET /v1/liquidity/items supplies sale-activity context. Marketplace accounts and trading APIs handle the actual purchase and sale.

Scope: This is a broad, high-level v0 guide, not a complete application. cs2.sh is designed as a flexible market-data layer for whatever you want to build on top of it, so adapt the implementation to your own product, strategy, and integrations.

The first useful version is a scanner, not an automatic trader. It produces a ranked list of item, buy marketplace, sell marketplace, landed cost, expected proceeds, net profit, margin, freshness, and liquidity. Automation can be added after those candidates survive live manual checks.

The data each candidate needs#

Input API field or source Why it changes the result
Exact item market_hash_name or variant version Prevents comparing a base Doppler with a specific phase
Buy price Source ask Lowest current sell listing on the marketplace
Sell price Different source bid Highest current generic buy order on the marketplace
Available orders ask_volume, bid_volume where supported Shows whether a price is backed by more than one active order
Observation time Source updated_at and collected_at Stops an old price from being paired with a current one
Sale activity liquidity, estimated_sale_time Separates a tradable gap from a thin market that may not clear

BUFF, Youpin, and Steam return both sell-listing and buy-order counts. CSFloat and C5Game return a highest buy order without bid_volume; Skinport has no buy-order field. A scanner must preserve those gaps instead of treating a missing count as zero.

Calculate executable profit#

For every ordered pair of different marketplaces, calculate:

text
landed_buy_cost = ask + buy_fee + deposit_cost + transfer_cost
net_sale_proceeds = bid - sell_fee - withdrawal_cost
net_profit = net_sale_proceeds - landed_buy_cost
net_margin = net_profit / landed_buy_cost

Fee inputs belong in your configuration because cs2.sh returns market data, not account-specific fee schedules. Store percentage fees and fixed costs separately. A fixed withdrawal fee can erase the apparent margin on a cheap item even when the percentage gap looks large.

Do not use an ask on both sides. The cheaper sell listing shows where the bot might buy, while a bid shows what a buyer currently offers on the destination marketplace. Comparing two asks measures a listing-price difference but does not prove an immediate sale exists.

Steam also requires a separate model. Steam transactions settle to Steam Wallet funds, not withdrawable cash. Keep Steam candidates out of a cash arbitrage ranking unless the strategy explicitly models the value and allowed use of wallet funds.

Build the fetch, filter, and act loop#

  1. Fetch GET /v1/schema and retain tradable items, canonical names, marketplace ids, and supported variants. Refresh the local catalog when generation_id changes.
  2. Download and cache GET /v1/prices/latest on the backend. It returns the current snapshot for every tracked item across BUFF, Youpin, CSFloat, Skinport, Steam, and C5Game.
  3. For each item, enumerate every source with a non-null ask and every different source with a non-null bid.
  4. Reject either side when collected_at is older than the strategy's freshness bound. If source freshness matters, also reject an old updated_at even when collection was recent.
  5. Apply fees, account limits, region rules, payment costs, and any transfer delay obtained from the relevant marketplace integrations.
  6. Join the daily liquidity snapshot. Require a minimum liquidity bucket or widen the required safety margin as liquidity weakens.
  7. Rank the survivors by net profit and net margin, then send candidates to an alert queue or a marketplace-specific execution adapter.
  8. Before submitting an order, re-read the exact listing or buy order from the marketplace. The price snapshot identifies a candidate; it does not reserve either side.

Use POST /v1/prices/latest for repeat checks after the full scan has produced a shortlist. It accepts up to 100 market_hash_name values and returns successful items alongside per-item errors[], so one missing item should not stop the entire cycle.

Filters that remove false arbitrage#

Freshness mismatch. Sources refresh independently. Two prices in one response can have different observation times, so response_time is not a valid freshness check for either side.

Insufficient order support. A lowest ask backed by one listing can disappear before the bot acts. Where order counts exist, require enough ask_volume and bid_volume for the intended quantity. A top price and an order count still do not provide full depth on every marketplace.

Weak sale activity. A large gap on an illiquid item may reflect weeks of waiting instead of profit. estimated_sale_time assumes a competitive listing price; it is not a fill guarantee for an outlying bid or ask.

Variant mismatch. Variant source maps are sparse. If BUFF has a Phase 2 price and another source has only the base Doppler, there is no valid Phase 2 pair. Missing variant data is absence, not a base-price fallback.

Asset-specific premiums. Generic prices do not appraise a rare paint seed, applied stickers, or every exact float. A generic bid may undervalue the asset, while a conditional buy order may apply only to assets satisfying its conditions. Use the CSFloat orderbook endpoint when the destination decision depends on float, paint index, sticker, charm, or paint-seed requirements.

What cs2.sh does not execute#

The public cs2.sh API does not log into marketplaces, inspect your balances, buy listings, transfer skins, place sell orders, or bypass trade restrictions. Those actions require official or authorized marketplace interfaces and compliance with each service's terms.

Keep the market-data adapter separate from execution. That boundary lets the same scanner run in alert-only mode, makes fee and account assumptions auditable, and prevents a temporary marketplace failure from corrupting the price model.

References: current prices, liquidity, item schema, and data coverage.