Skip to content
SteamLabs API

Endpoints

Market

Listings, buy orders, sales history and deliveries on Steam, CSFloat, market.csgo, Skin.Land, Skinport, and DMarket.

Everything the Market pages do, over HTTP. The venue is part of the path: every route lives under /api/v1/market/{venue}/, where venue is steam, csfloat, marketcsgo, skinland, dmarket, skinport or assetpay.

AssetPay behaves differently from the other listing venues and it shows in the responses. Its listings live on a feed AssetPay reads rather than on AssetPay's own servers, so cancelling one and changing its price both take effect immediately and answer 200 with listings_affected, not 202 with a task id. Bulk repricing there accepts exact only. POST /market/assetpay/listings/sync is a 404: there is nothing remote to sync against, our own database is the record. AssetPay also charges nothing on a pool sale, so receive_cents and buyer_pays_cents on those listings are always the same number.

There is no default venue, so no request can quietly read Steam rows while you believed it was reading CSFloat. An unknown venue answers 404 with code unknown_venue.

Two scopes cover the domain. market.read for the listings, orders, history, sales and stats. market.write for everything that changes them.

Venues

The venues do not carry the same surfaces. A surface a venue genuinely lacks answers 404 with code venue_unsupported, not 403: the resource does not exist there, it is not forbidden there.

Surface steam csfloat marketcsgo skinland dmarket skinport assetpay
Stats Yes Yes Yes Yes Yes Yes Yes
Listings: list, cancel Yes Yes Yes No Yes Yes Yes
Listings: sync Yes Yes Yes No Yes Yes No
Reprice a listing No Yes Yes No Yes Yes Yes
Automatic repricing rules No Yes Yes No Yes No No
Inventory (custody, not listed) No No No No No Yes No
Buy orders Yes No No No No No No
Buy a specific listing Yes No No No No No No
Sales history Yes Yes Yes No Yes Yes Yes
Sales (trades) No Yes Yes Yes No No Yes
Deliver or retry a sale No Yes Yes No No No No
Accept a sale No Yes No No No No No
Cancel a sale No Yes No No No No No
Withdraw unsold inventory No No No No Yes No No
Relist unsold inventory No No No No Yes No No
Earnings and payouts No No No No No No Yes

Steam fixes a listing's price at creation, so there is nothing to reprice. Every venue but Steam is sell-only, so they have no buy orders. Steam settles a sale internally the moment it happens, so it has no delivery stage: on CSFloat and market.csgo the marketplace only brokers the deal and you still have to send the item.

Skin.Land has no listings at all. It is a buyer of record: it quotes a fixed price, buys the items outright, and its own bot sends the trade offer, which SteamLabs accepts for you inside the same operation. So there is nothing to list, no price to choose, nothing to reprice or delist, and no delivery left outstanding for you to act on. It has no sales history either, for the same reason: history records listing events, and there are none. What it does have is sales, which you read exactly like the other venues', and terminal ones stay there rather than moving elsewhere, so /market/skinland/trades is the complete record.

AssetPay is the only venue whose money lands at SteamLabs. Everywhere else a sale pays into a wallet you hold at the venue and you withdraw it there. AssetPay pays into one SteamLabs merchant balance, and SteamLabs keeps your share of it, so it is the only venue with earnings and payouts surfaces. It also has no automatic repricing (we are the sole supplier of our own pool, so there is nothing to undercut) and no listing sync (our database is the record). Its sales come in two kinds, instant and pool, which the source field tells apart.

DMarket has listings and history, and no Sales tab. A sale on DMarket does not leave a delivery for you to send. /market/dmarket/trades answers 404 with venue_unsupported. Withdraw unsold inventory with POST /api/v1/market/dmarket/withdraw. Relist it without depositing again with POST /api/v1/market/dmarket/relist. Other venues answer 404 with venue_unsupported there.

What your plan gates

Your subscription plan controls which venues you may sell on. It never gates reads, and it never gates pulling your own items back.

Listing, delisting, manual repricing, syncing, reading history, withdrawing Skinport custody items and delivering a sale all work on every venue, whatever your plan says. Someone who downgraded still has real items on a real marketplace, and an API that hid them would strand inventory they cannot get back. Scheduled automatic repricing checks pause while the user's plan does not include the listing's venue; the rules remain stored and resume when access returns.

Writes here that can still come back 403 plan_limit_reached:

  • Placing a buy order. Buying spends the Steam venue entitlement, so it needs steam in your plan's allowed_marketplaces, plus place_buy_order in allowed_task_types.
  • Buying a specific listing. The same entitlement, plus buy_market_listing in allowed_task_types.
  • Syncing on Steam. A Steam refresh is a real task, so it needs sync_market_listings (or sync_market_history) in allowed_task_types. The CSFloat and market.csgo refreshes are poller requests and are never gated. DMarket sync is a task too, and it is also never gated: it only refreshes listings and history you already have.
  • Relisting from Skinport inventory. Relist puts a new listing up, so it needs skinport in your plan's allowed_marketplaces. Withdraw does not: it only asks Skinport to send a Steam offer.

Read plan from GET /api/v1/me at startup and you will rarely meet either. See Errors for the response shape.

Venue stats

The headline numbers above a venue's tables.

GET/api/v1/market/{venue}/stats

Open listings, recent money moved, and where your balance sits on this venue.

API key required

Requires market.read.

Bash
curl https://dashboard.steamlabs.dev/api/v1/market/steam/stats \
  -H "Authorization: Bearer $STEAMLABS_API_KEY"
JSON
{
    "venue": "steam",
    "window_days": 30,
    "listings": {
        "open_count": 184,
        "open_value_cents": { "EUR": 412300, "USD": 88150 },
        "sold_recent_cents": { "EUR": 96420, "USD": 12005 }
    },
    "buy_orders": {
        "open_count": 12,
        "committed_value_cents": { "EUR": 31400 },
        "bought_recent_cents": { "EUR": 18720 }
    },
    "wallet_cents": { "EUR": 24150, "PLN": 9800 },
    "marketplace_balance": null
}

On CSFloat and market.csgo the shape stays the same, with buy_orders and wallet_cents null and the venue-side balance filled in:

JSON
{
    "venue": "csfloat",
    "window_days": 30,
    "listings": {
        "open_count": 62,
        "open_value_cents": { "USD": 148900 },
        "sold_recent_cents": { "USD": 51230 }
    },
    "buy_orders": null,
    "wallet_cents": null,
    "marketplace_balance": {
        "available_cents": { "USD": 21400 },
        "pending_cents": { "USD": 6800 }
    }
}

On Skin.Land the same keys mean the venue's own lifecycle, because it has no listings: open_count and open_value_cents cover sales still moving (queued, awaiting accept, delivering, or locked in settlement), and sold_recent_cents sums the baskets whose trade offer went through in the window. A queued sale has no price yet (Skin.Land quotes the basket at sell time), so the open value is only ever a partial figure.

window_days is 30, and it applies to sold_recent_cents and bought_recent_cents only. Sales are summed from history events rather than from listings, because an item that sells instantly by crossing a standing buy order never lingers as an open listing.

committed_value_cents is what your open buy orders still hold: per-unit price times the quantity not yet filled.

List listings

What you have up for sale on this venue, and what has happened to it.

GET/api/v1/market/{venue}/listings

Your listings on this venue, paginated and filterable.

API key required

Requires market.read.

Parameter Type Description
state string open, sold, or canceled. open covers pending_confirmation, active and on_hold. canceled covers both a listing you pulled and one that vanished from an authoritative sync
account_id uuid Only listings from this Steam account. Must be an account you own, otherwise 422
origin string steamlabs for listings this platform created, external for ones found already on the venue
game string cs2, tf2, or steam
appid integer The Steam app id, if you already hold the number. Wins over game when both are sent
search string Matches the item name or its market hash name
market_hash_names string[] Exact market hash names, up to 100. Unlike search, AK-47 | Redline (Field-Tested) does not also match its StatTrak™ version
currency string Only listings in this currency, as a code like EUR
price_min_cents integer Lowest buyer_pays_cents to include, in the listing's own currency. Pair with currency when your accounts use more than one
price_max_cents integer Highest buyer_pays_cents to include, in the listing's own currency
older_than_days integer Only listings put up at least this many days ago, 1 to 3650
sort string listed_at (default), resolved_at, buyer_pays_cents, created_at
direction string asc or desc (default)
per_page integer 50 by default, 200 at most
Bash
curl "https://dashboard.steamlabs.dev/api/v1/market/steam/listings?state=open&game=cs2&per_page=1" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY"
JSON
{
    "data": [
        {
            "id": "019fb42e-9a61-70d2-818a-f6a56593f3a5",
            "listing_id": "4258109377312946881",
            "marketplace": "steam",
            "origin": "steamlabs",
            "state": "active",
            "is_open": true,
            "steam_account": {
                "id": "019fb42e-9a7e-728d-b960-8b4c2162898c",
                "username": "farm_017"
            },
            "asset_id": "38294011745",
            "appid": 730,
            "game": "cs2",
            "context_id": "2",
            "market_hash_name": "AK-47 | Redline (Field-Tested)",
            "name": "AK-47 | Redline",
            "icon_url": "https://community.fastly.steamstatic.com/economy/image/…",
            "amount": 1,
            "buyer_pays_cents": 1842,
            "receive_cents": 1602,
            "fee_cents": 240,
            "sold_receive_cents": null,
            "currency": "EUR",
            "listed_at": "2026-07-28T11:40:02+00:00",
            "instant_sell_after_at": null,
            "follow_cheapest": false,
            "cheapest_now_cents": null,
            "resolved_at": null,
            "auto_repricing": null,
            "created_at": "2026-07-28T11:40:05+00:00"
        }
    ],
    "meta": { "page": 1, "per_page": 1, "total": 184, "last_page": 184 }
}

buyer_pays_cents is what the listing shows a buyer. receive_cents is your net after the venue's fee, and sold_receive_cents fills in once it actually sells. is_open saves you mapping the six raw states yourself.

Market.CSGO prices in tenths of a cent, so a market.csgo listing's buyer_pays_cents can carry one decimal place: 40.9 for a listing at $0.409. Whole-cent prices stay integers (41), and every other venue only ever returns integers. receive_cents, fee_cents, the price_min_cents / price_max_cents filters and the buyer_pays_cents sort work in whole cents.

On AssetPay, instant_sell_after_at is when the listing gives up waiting and sells to AssetPay at the Sell now price (see Schedule an instant sell); null means it stays up until it sells. It is null on every other venue.

On AssetPay, cheapest_now_cents is the store price: what the item costs on AssetPay's store right now, not counting SteamLabs listings, and the price to beat there (null when they do not sell it, and for Doppler-family items). follow_cheapest is Stay cheapest: SteamLabs keeps the listing one cent under that price as it moves (see Stay cheapest). Both are false / null on every other venue.

On CSFloat, auto_repricing is either null or the listing's captured rule. It includes enabled, interval_minutes, undercut_cents, floor_percent, the fixed floor_cents, and its last and next check timestamps.

Get listing price history

The current catalog prices and recent price changes behind the listing history panel.

GET/api/v1/market/{venue}/listings/{listing}/price-history

Current provider prices and a seven-day item price series for one listing.

API key required

Requires market.read.

Bash
curl "https://dashboard.steamlabs.dev/api/v1/market/csfloat/listings/019fb42e-9a61-70d2-818a-f6a56593f3a5/price-history" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY"
JSON
{
    "listing_id": "019fb42e-9a61-70d2-818a-f6a56593f3a5",
    "item_id": "019fb421-5484-7c4c-a31b-e247db42df90",
    "active_source": "csfloat",
    "window": {
        "days": 7,
        "starts_on": "2026-08-05",
        "ends_on": "2026-08-11"
    },
    "current_prices": [
        {
            "source": "csfloat",
            "marketplace": "csfloat",
            "price_cents": 1825,
            "safe_price_cents": null,
            "median_price_cents": null,
            "min_price_cents": null,
            "max_price_cents": null,
            "lowest_sell_price_cents": 1799,
            "highest_buy_price_cents": null,
            "volume": 38,
            "currency": "USD",
            "fetched_at": "2026-08-11T12:04:18+00:00"
        }
    ],
    "series": [
        {
            "source": "csfloat",
            "points": [
                { "recorded_on": "2026-08-05", "price_cents": 1610, "currency": "USD" },
                { "recorded_on": "2026-08-08", "price_cents": 1740, "currency": "USD" },
                { "recorded_on": "2026-08-11", "price_cents": 1825, "currency": "USD" }
            ]
        }
    ],
    "sales": {
        "recent": [
            { "price_cents": 1790, "currency": "USD", "marketplace": "assetpay", "sold_at": "2026-08-10T15:22:08+00:00" }
        ],
        "window": { "count": 1, "median_cents": 1790 }
    }
}

current_prices can contain Steam, CSFloat, market.csgo and AssetPay snapshots for the item, regardless of which venue owns the listing. active_source tells a client which series the dashboard highlights for this route.

History is change-only. When a price was already known before the seven-day window, the first point is carried forward to starts_on; the current snapshot extends the final step to ends_on. Draw the points as a stepped line rather than interpolating between them.

active_source is assetpay for an AssetPay listing, and that series carries two lines. points is the Sell now price (its deposit price, what AssetPay pays you for the item on the spot). store_points is the store price, what the item costs on AssetPay's store. It has the same shape as points (recorded_on, price_cents, currency) and follows the same stepped rules. Both are recorded once a day when they move. Only the AssetPay series has store_points, and it is empty while AssetPay has no store price for the item (Doppler-family items, for instance). The dashboard chart draws the store price by default. In current_prices, the AssetPay snapshot's price_cents is the Sell now price and its lowest_sell_price_cents is the store price.

sales is what pool-listed items actually sold for: platform-wide and anonymised (price, venue and time only), delivered sales only, and a reversed sale's print is removed again. recent holds the last five prints newest first; window counts the prints inside the seven-day window and gives their median.

The item link can be absent on older imported listings. Those listings still answer 200, with item_id: null, current_prices: [] and series: []. A listing belonging to another user or another venue answers the same plain 404 as the other single-listing routes.

Refresh listings

Re-read the venue for the accounts you name.

POST/api/v1/market/{venue}/listings/sync

Pull fresh listings, wallet and buy orders from the venue.

API key required

Requires market.write.

Field Type Description
account_ids uuid[] Accounts to refresh, up to 1,000. Leave it out for the whole eligible fleet

A sync is account-oriented, never listing-oriented: the venue is asked for an account's whole state at once. That is why an absent account_ids is safe here and nowhere else in this domain. It creates no listings, spends no money and moves no items.

Bash
curl -X POST "https://dashboard.steamlabs.dev/api/v1/market/steam/listings/sync" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"account_ids":["019fb42e-9a7e-728d-b960-8b4c2162898c"]}'

On Steam a refresh is a task, so you get a task to follow:

JSON
{
    "task_id": "019fb440-1c22-73a4-9f0e-2b7c5d1e8a44",
    "accounts_affected": 412,
    "async": false,
    "accounts_skipped": 18
}

async is true above 500 accounts, where the batch is built by a background job. accounts_skipped counts accounts left out because they already had market work queued.

On CSFloat and market.csgo there is no task. Those venues use scheduled HTTP checks. A refresh requests a full check of the selected accounts, while preserving marketplace rate-limit delays. Repeated requests are combined. Refreshing does not keep idle Market.CSGO accounts online or put idle CSFloat accounts on the fastest schedule:

JSON
{
    "task_ids": [],
    "accounts_affected": 34,
    "sync": "poll_requested"
}

On Skinport (and Skin.Land) a refresh is a task again: { "task_ids": [...], "accounts_affected": N, "sync": "task_queued" }. SteamLabs also queues that same task about every 30 minutes for connected accounts that have gone stale, so a sale that happens on the venue website still lands without this call. A vanished Skinport listing is sold only when /api/transactions has a matching sale; otherwise it is canceled. A newly sold listing sends the same sold notification as a CSFloat poller tick.

Answers 422 nothing_eligible when nothing matched.

Cancel many listings

Pull a selection of listings off the marketplace.

POST/api/v1/market/{venue}/listings/cancel

Delist many listings, grouped into one task per account.

API key required

Requires market.write.

Field Type Description
listing_ids uuid[] The listings to pull, up to 1,000. Required unless you send filters
filters object The same filter keys the listings index accepts, resolved server-side. Required unless you send listing_ids
dry_run boolean Report what this call would cancel, and queue nothing. See Preview a cancel

Send one or the other, never neither. An empty body delisting your entire market is exactly the accident an API should refuse. See Bulk operations for the shared contract.

Bash
curl -X POST "https://dashboard.steamlabs.dev/api/v1/market/csfloat/listings/cancel" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"filters":{"state":"open","game":"cs2"}}'

Answers 202, with one task per account rather than a single parent:

JSON
{
    "task_ids": [
        "019fb441-2c88-71ea-b0a3-8ce2f5d19b07",
        "019fb441-3d19-7285-9c41-72b0e4a9d233"
    ],
    "accounts_affected": 2,
    "listings_affected": 47,
    "accounts_busy": 1
}

listings_affected is counted off the tasks that were really created, so an account the single-flight guard refused is reported in accounts_busy instead of being counted as queued.

Listings that are already closed are dropped rather than refused, so a sale that lands between reading the page and pressing the button does not fail the other forty-nine. If none of the selection is still open you get 422 nothing_to_cancel with matched.

To have Steam listings pulled automatically once they sit unsold for a number of days, turn on the cancel unsold rule instead of calling this on a timer.

Preview a cancel

Send the same body with "dry_run": true to see what it would pull. It answers 200, queues nothing, and lists the SteamLabs ids of the open listings it matched:

JSON
{
    "dry_run": true,
    "matched": 48,
    "listings_affected": 47,
    "accounts_affected": 2,
    "listing_ids": ["019fb43f-9a12-7c44-8b1e-3d5f6a7b8c90", "019fb43f-9a12-7c44-8b1e-3d5f6a7b8c91"]
}

An empty match answers 200 with zeros rather than 422 nothing_to_cancel. The preview cannot tell you accounts_busy, which changes from one second to the next.

Only the delist previews. The reprice, stay-cheapest, instant-sell and cash-out writes refuse dry_run with 422, so a guessed flag never changes a price or sells anything for real.

Cancel one listing

POST/api/v1/market/{venue}/listings/{listing}/cancel

Pull one listing off the marketplace.

API key required

Requires market.write.

Bash
curl -X POST "https://dashboard.steamlabs.dev/api/v1/market/steam/listings/019fb42e-9a61-70d2-818a-f6a56593f3a5/cancel" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY"
JSON
{
    "task_ids": ["019fb441-2c88-71ea-b0a3-8ce2f5d19b07"],
    "accounts_affected": 1,
    "listings_affected": 1
}

202, not 204. The venue is reached by a worker holding the account's session, so the listing keeps its current state until the task comes back. Reporting 204 would tell you the item is already delisted, which is the lie that makes an integration relist it twice.

A listing that is no longer open answers 422 listing_not_open with its state. An account that already has market work in flight answers 409 account_busy; wait for that task and try again. A listing id that belongs to another venue answers a plain 404.

Reprice a listing

Change what a live listing asks a buyer to pay.

POST/api/v1/market/{venue}/listings/{listing}/price

Set a new buyer-pays price. CSFloat, market.csgo, DMarket, and Skinport.

API key required

Requires market.write. On AssetPay it is a local write that answers 200, and a price set this way turns Stay cheapest off for the listing.

Field Type Description
price_cents number The new buyer-pays price in cents. At least 1, at most 100000000. Whole cents on every venue except market.csgo, which prices in tenths of a cent and takes one decimal place (40.9)
Bash
curl -X POST "https://dashboard.steamlabs.dev/api/v1/market/csfloat/listings/019fb42e-9a61-70d2-818a-f6a56593f3a5/price" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"price_cents":1795}'
JSON
{
    "task_ids": ["019fb442-8a10-7c33-b4d2-0f1e6c7a9b55"],
    "accounts_affected": 1,
    "listings_affected": 1,
    "price_cents": 1795,
    "repricing_paused": true
}

Changing a CSFloat or market.csgo price manually pauses that listing's automatic rule. This prevents a scheduled check from replacing the price you just chose. Resume it through the rule endpoint when that is intentional.

On market.csgo, {"price_cents":40.9} lists at $0.409 and the response echoes "price_cents": 40.9. Two decimal places (40.95) answer 422, and so does a fraction on any other venue.

/market/steam/listings/{id}/price answers 404 venue_unsupported. A Steam listing's price is fixed at creation, and the equivalent is a delist plus a fresh listing, which costs a fee and a new asset id. Doing that silently under a "change price" call would surprise every caller exactly once.

Reprice many listings

Change the prices of a whole selection at once. On CSFloat, market.csgo, DMarket, and Skinport this is the listings table's Change price of selected bulk action. On AssetPay it is Update price.

POST/api/v1/market/{venue}/listings/price

Reprice many listings. Other venues queue one task per account. AssetPay applies the price immediately.

API key required

Requires market.write.

Field Type Description
listing_ids uuid[] The listings to reprice, up to 1,000. Required unless you send filters
filters object The same filter keys the listings index accepts, resolved server-side. Required unless you send listing_ids
pricing.mode string exact or undercut. AssetPay also accepts percent and amount
pricing.price_cents number exact only: the buyer-pays price applied to every selected listing. At least 1, at most 100000000. Whole cents, except on market.csgo, which takes one decimal place (40.9)
pricing.undercut_cents number undercut only: how far under each item's lowest live listing to go. Whole cents from 1 to 10000, except on market.csgo, which takes one decimal place from 0.1 to 10000
pricing.percent number AssetPay percent only: how far to move each listing from its own price. 0.01 to 1000, up to 2 decimal places
pricing.amount_cents integer AssetPay amount only: how many cents to add or subtract from each listing. At least 1, at most 100000000
pricing.direction string AssetPay percent and amount only: up or down

exact sets one price everywhere, which is what a selection of fifty identical cases wants. undercut prices each distinct item under its venue's lowest live listing, read from the same cached quotes the reprice modal shows; a listing whose item has no quote yet (or whose computed price would fall below one cent) is skipped and counted in skipped_no_quote.

Market.CSGO prices in tenths of a cent, so {"mode":"undercut","undercut_cents":0.1} is a real step there. The cached quote is kept in whole cents, which is too coarse for that step, so when the step is not a whole number of cents the task re-reads the item's live order book when it runs and undercuts that. If the order book cannot be read, it uses the price planned from the cached quote. A listing whose live lowest ask less the step would fall below one cent is reported in the task's failed list. A whole-cent step is priced from the cached quote, as on the other venues.

Bash
curl -X POST "https://dashboard.steamlabs.dev/api/v1/market/csfloat/listings/price" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"filters":{"state":"open","search":"Revolution Case"},"pricing":{"mode":"exact","price_cents":20}}'

Answers 202, with one task per account:

JSON
{
    "task_ids": [
        "019fb441-2c88-71ea-b0a3-8ce2f5d19b07",
        "019fb441-3d19-7285-9c41-72b0e4a9d233"
    ],
    "accounts_affected": 2,
    "listings_affected": 47,
    "skipped_no_quote": 3,
    "accounts_busy": 1
}

Like the single reprice, every listing that gets a new price has its automatic-repricing rule paused, so a scheduled check does not immediately replace the price you just set. Closed listings are dropped rather than refused; if nothing in the selection is still open you get 422 nothing_to_reprice with matched. The selection is capped like the bulk delist: over 1,000 matched listings answers 422 bulk_limit_exceeded.

DMarket accepts exact only. It has no cached order book for undercut, so that mode answers 422 undercut_unsupported.

AssetPay

AssetPay accepts exact, percent, and amount. It has no order book to undercut, so undercut answers 422 undercut_unsupported. There is no worker task: the call answers 200, and the new prices are on the feed immediately.

On AssetPay the buyer pays the whole price and you receive the same number, so price_cents is both. percent and amount move each listing from its own current price and round to the nearest cent (a half cent rounds away from zero). A result under 1 cent or over 100000000 cents is left unchanged.

listings_affected counts listings whose price changed. results has one entry per listing in the selection that this account can see, including ones left alone. price_cents at the top is present for exact only, and is the price you asked for.

results.*.status Meaning
updated The price changed. Stay cheapest is turned off for that listing.
stopped_following The price was already the target, and Stay cheapest was turned off so the next check does not overwrite it.
unchanged Already at the target price.
skipped Left alone. reason is sold, not_open, reserved, delivering, below_minimum, or above_maximum.

reserved means a buyer has already committed to the listing. delivering means the item is in a sale that is still being handed over. Neither is repriced. A price set this way turns Stay cheapest off. Leaving it on would put the old price back on the next check.

percent and amount on any other venue answer 422 pricing_unsupported.

Bash
curl -X POST "https://dashboard.steamlabs.dev/api/v1/market/assetpay/listings/price" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"listing_ids":["019fb42e-9a61-70d2-818a-f6a56593f3a5"],"pricing":{"mode":"percent","direction":"down","percent":10}}'
JSON
{
    "listings_affected": 1,
    "results": [
        {
            "id": "019fb42e-9a61-70d2-818a-f6a56593f3a5",
            "name": "Kilowatt Case",
            "status": "updated",
            "reason": null,
            "previous_price_cents": 1200,
            "price_cents": 1080
        }
    ]
}

Schedule an instant sell

AssetPay only. Set or clear when a pool listing gives up waiting and sells to AssetPay at the Sell now price. The hourly check then takes the listing down and sells the item, provided the venue's instant sell unsold rule is switched on and the item's Sell now price is at least its minimum at that moment. Anything AssetPay does not take goes straight back up at its old price.

POST/api/v1/market/{venue}/listings/{listing}/instant-sell

Set or clear one AssetPay listing's instant sell deadline.

API key required

Requires market.write. A local write, like an AssetPay reprice: it answers 200, not 202.

Field Type Description
after_days integer or null Days from now, 1 to 365. null clears the deadline so the listing stays up until it sells
Bash
curl -X POST "https://dashboard.steamlabs.dev/api/v1/market/assetpay/listings/019fb42e-9a61-70d2-818a-f6a56593f3a5/instant-sell" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"after_days":7}'
JSON
{
    "listings_affected": 1,
    "after_days": 7,
    "instant_sell_after_at": "2026-09-22T10:15:00+00:00"
}
POST/api/v1/market/{venue}/listings/instant-sell

The same deadline for many AssetPay listings, by id or by filter.

API key required

Takes after_days plus the same listing_ids or filters selection as Cancel many listings. Listings that are no longer open are skipped and not counted.

Stay cheapest

AssetPay only. Keep pool listings one cent under the store price (cheapest_now_cents), so they stay the cheapest on AssetPay's store as that price moves. SteamLabs listings do not count toward the store price, so a listing never chases itself and followers of the same item tie. Turning it on reprices the listing right away. After that SteamLabs checks every few minutes, moves the price down or back up with the store price, never asks less than the Sell now price, and leaves the price alone while AssetPay has no store price for the item.

POST/api/v1/market/{venue}/listings/{listing}/follow-cheapest

Turn Stay cheapest on or off for one AssetPay listing.

API key required

Requires market.write. A local write: it answers 200, not 202.

Field Type Description
enabled boolean true to follow the cheapest price, false to stop and keep the current price
JSON
{
    "listings_affected": 1,
    "follow_cheapest": true,
    "price_cents": 103
}
POST/api/v1/market/{venue}/listings/follow-cheapest

Stay cheapest for many AssetPay listings, by id or by filter.

API key required

Takes enabled plus the same listing_ids or filters selection as Cancel many listings. Listings that are no longer open are skipped and not counted. Setting a price with Reprice a listing turns Stay cheapest off again.

Cash out listings

AssetPay only. Take pool listings down and sell their items to AssetPay at the Sell now price right now, instead of waiting for a buyer. This is the Cash out instead button on the listings page, for a whole selection.

POST/api/v1/market/{venue}/listings/cash-out

Sell many AssetPay listings at the Sell now price, by id or by filter.

API key required

Requires market.write. Takes the same listing_ids or filters selection as Cancel many listings. Each account's listings are sold together in one instant sale, which shows on the AssetPay Sales tab like any other.

Bash
curl -X POST "https://dashboard.steamlabs.dev/api/v1/market/assetpay/listings/cash-out" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"listing_ids":["019fb42e-9a61-70d2-818a-f6a56593f3a5","019fb42e-9a62-7c1e-8f0b-2d7a1c9e4b31"]}'
JSON
{
    "listings_cashed_out": 2,
    "listings_relisted": 0,
    "listings_skipped": 0,
    "sales": 1,
    "gross_cents": 142
}

Nothing is taken down for a sale that cannot happen:

  • A listing that is no longer open, or whose item has no Sell now price right now, is left alone and counted in listings_skipped.
  • An account that cannot sell right now is skipped with its listings left up: no trade URL, no mobile authenticator, no proxy, an AssetPay sale already in progress, or Steam will not let it trade its CS2 items (trading on the account).
  • Whatever AssetPay does not buy goes straight back up at its old price and is counted in listings_relisted.

A refusal from SteamLabs' own AssetPay limits (too many open instant sales, the daily cap) answers 422 assetpay_refused with a reason, and every listing stays up.

Withdraw unsold inventory

Send unsold DMarket inventory back to Steam. Delisting leaves the item in DMarket inventory. This is the step that asks DMarket to trade it back. SteamLabs accepts that offer for you.

POST/api/v1/market/{venue}/withdraw

Queue a withdraw of unsold DMarket inventory. DMarket only.

API key required

Requires market.write. Other venues answer 404 with venue_unsupported.

Field Type Description
account_ids uuid[] Accounts to withdraw from, up to 1,000. Leave it out for every DMarket-ready account
assets object[] Specific in-market rows. Each needs asset_id, class_id, and game_id. Omit it and the worker finds unsold in-market items itself

Named assets need exactly one account_id. Missing that is 422 account_required. No DMarket-ready account matching the selection is 422 nothing_eligible. An account that already has DMarket work in flight is counted busy like the other writes.

Bash
curl -X POST "https://dashboard.steamlabs.dev/api/v1/market/dmarket/withdraw" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"account_ids":["019fb42e-9a7e-728d-b960-8b4c2162898c"]}'
JSON
{
    "task_ids": ["019fb441-2c88-71ea-b0a3-8ce2f5d19b07"],
    "accounts_affected": 1,
    "withdraw": "queued"
}

202, not 204. The worker still has to talk to DMarket, then accept the Steam trade. Reporting 204 would tell you the items are already back.

This write is never plan-gated. A lapsed subscriber still owns those items.

List unsold inventory

List items that already sit in DMarket inventory and are not currently for sale. Delisting leaves the item in DMarket inventory. This is the step that puts it back on sale without depositing again.

POST/api/v1/market/{venue}/relist

Queue a listing of unsold DMarket inventory. DMarket only.

API key required

Requires market.write. Other venues answer 404 with venue_unsupported. This write is plan-gated: it puts something new up for sale. A plan that does not include DMarket answers 403 with plan_limit_reached.

Field Type Description
account_ids uuid[] Accounts to list from, up to 1,000. Leave it out for every DMarket-ready account
assets object[] Specific in-market rows. Each needs asset_id, appid, and market_hash_name. Optional context_id (defaults to 2) and reference_usd_cents. Omit assets and the worker finds unsold in-market items itself
pricing object Same modes as selling: undercut, reference_percent, manual, top_bid. Defaults to undercut by 1 cent

Named assets need exactly one account_id. Missing that is 422 account_required. No DMarket-ready account matching the selection is 422 nothing_eligible. An account that already has DMarket work in flight is counted busy like the other writes.

Bash
curl -X POST "https://dashboard.steamlabs.dev/api/v1/market/dmarket/relist" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"account_ids":["019fb42e-9a7e-728d-b960-8b4c2162898c"],"pricing":{"mode":"undercut","undercut_cents":1}}'
JSON
{
    "task_ids": ["019fb441-2c88-71ea-b0a3-8ce2f5d19b07"],
    "accounts_affected": 1,
    "relist": "queued"
}

202, not 204. The worker still has to talk to DMarket. Reporting 204 would tell you the items are already listed.

Manage automatic repricing

Opt one open CSFloat, market.csgo, or DMarket listing into decrease-only competitive repricing.

PUT/api/v1/market/{venue}/listings/{listing}/repricing

Create or replace the automatic repricing rule for one listing.

API key required

Requires market.write. PATCH on the same path changes selected fields, and DELETE disables the retained rule.

PATCH/api/v1/market/{venue}/listings/{listing}/repricing

Change, pause, or resume an existing automatic repricing rule.

API key required
DELETE/api/v1/market/{venue}/listings/{listing}/repricing

Disable an automatic repricing rule while retaining its history.

API key required
Field Type Description
enabled boolean Pause or resume an existing rule. Used by PATCH
interval_minutes integer 15, 30, 60, or 240
undercut_cents number Cents below a true competing lowest price. Whole cents from 1 to 10,000, except on market.csgo, which takes one decimal place from 0.1
floor_percent integer 1 to 100. Resolves to a fixed USD floor when the rule is enrolled
Bash
curl -X PUT "https://dashboard.steamlabs.dev/api/v1/market/csfloat/listings/019fb42e-9a61-70d2-818a-f6a56593f3a5/repricing" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"interval_minutes":30,"undercut_cents":1,"floor_percent":70}'
JSON
{
    "data": {
        "marketplace": "csfloat",
        "strategy": "undercut",
        "enabled": true,
        "interval_minutes": 30,
        "undercut_cents": 1,
        "floor_percent": 70,
        "reference_cents": 1842,
        "floor_cents": 1289,
        "reference_fetched_at": "2026-08-07T14:10:00+00:00",
        "next_check_at": "2026-08-07T14:40:00+00:00",
        "last_checked_at": null,
        "last_repriced_at": null,
        "last_outcome": null,
        "last_error": null,
        "pause_reason": null
    }
}

The checker only lowers a price. It compares the public lowest price with every copy of that item in your live stall, so it does not undercut your own managed or imported listings. A tie is left alone. A target below floor_cents is skipped and checked again later.

Scheduled checks are off for every account until the first explicit opt-in: creating or resuming a rule (here, from the dashboard, or through a listing created with auto_reprice) turns the venue's scheduling on. The per-venue master switch in Settings pauses all of a venue's rules again without deleting them.

Skinport inventory

Items sitting in Skinport custody and not currently listed. Cancel leaves them here. Relist puts them back on Skinport with no Steam offer. Withdraw asks Skinport to send a Steam trade offer and stops there: SteamLabs does not accept that offer.

Other venues answer 404 with code venue_unsupported.

GET/api/v1/market/{venue}/inventory

Items in Skinport custody that are not listed.

API key required

Requires market.read. Skinport only.

Parameter Type Description
account_id uuid Only items from this Steam account. Must be one you own
search string Matches the item name, market hash name, or Skinport product id
sort string created_at (default), suggested_price_cents, name
direction string asc or desc (default)
per_page integer 50 by default, 200 at most
Bash
curl "https://dashboard.steamlabs.dev/api/v1/market/skinport/inventory?per_page=1" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY"
JSON
{
    "data": [
        {
            "id": "019fb42e-9a61-70d2-818a-f6a56593f3a5",
            "product_id": "59334964",
            "skinport_asset_id": "693023720",
            "steam_asset_id": "52808880736",
            "market_hash_name": "Sealed Dead Hand Terminal",
            "name": "Sealed Dead Hand Terminal",
            "icon_url": null,
            "appid": 730,
            "suggested_price_cents": 82,
            "currency": "EUR",
            "lock_at": null,
            "trade_locked": false,
            "steam_account": { "id": "019fb42e-9a7e-728d-b960-8b4c2162898c", "username": "farm_014" },
            "created_at": "2026-08-19T18:02:11+00:00",
            "updated_at": "2026-08-19T18:02:11+00:00"
        }
    ],
    "meta": { "page": 1, "per_page": 1, "total": 1, "last_page": 1 }
}

product_id is Skinport's own id for the held item. Relist and withdraw key off that, not the Steam asset id and not a listing saleId. trade_locked is true while lock_at is still in the future. A CS2 trade lock blocks withdraw.

POST/api/v1/market/{venue}/inventory/relist

List held Skinport items at one price, with no Steam offer.

API key required

Requires market.write. Skinport only. This puts a new listing up, so it is plan-gated: a plan without skinport answers 403 plan_limit_reached.

Field Type Description
item_ids uuid[] Skinport inventory row ids from the list above
price_cents integer Buyer-pays price in EUR cents, at least 2
Bash
curl -X POST "https://dashboard.steamlabs.dev/api/v1/market/skinport/inventory/relist" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"item_ids":["019fb42e-9a61-70d2-818a-f6a56593f3a5"],"price_cents":4999}'

Answers 202 with one task per account:

JSON
{
    "task_ids": ["019fb445-77c3-7f21-a0b6-9c4e0d1a8b62"],
    "accounts_affected": 1,
    "items_affected": 1,
    "accounts_busy": 0
}

IDs that are not yours are not matched. If none of the ids exist, the call answers 404 with code not_found.

POST/api/v1/market/{venue}/inventory/withdraw

Ask Skinport to send a Steam withdraw offer. SteamLabs does not accept it.

API key required

Requires market.write. Skinport only. Not plan-gated: a lapsed subscriber must still be able to pull items back.

Field Type Description
item_ids uuid[] Skinport inventory row ids from the list above

Trade-locked rows are skipped. If every selected row is locked, the call answers 422 with code nothing_withdrawable.

Bash
curl -X POST "https://dashboard.steamlabs.dev/api/v1/market/skinport/inventory/withdraw" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"item_ids":["019fb42e-9a61-70d2-818a-f6a56593f3a5"]}'

The queued task asks Skinport to send the Steam offer. Steam offerId is null at that send. SteamLabs does not accept or mobile-confirm it.

List buy orders

Standing bids resting on the Steam market, waiting to be filled.

GET/api/v1/market/{venue}/buy-orders

Your buy orders. Steam only.

API key required

Requires market.read.

Parameter Type Description
state string open, canceled, or closed. closed means it vanished from an authoritative sync: filled or cancelled outside our sight
account_id uuid Only orders from this Steam account. Must be one you own
game string cs2, tf2, or steam
appid integer The Steam app id. Wins over game when both are sent
search string Matches the item name or its market hash name
market_hash_names string[] Exact market hash names, up to 100. Unlike search, AK-47 | Redline (Field-Tested) does not also match its StatTrak™ version
currency string Only orders in this wallet currency, as a code like EUR
price_min_cents integer Lowest buyer_pays_per_unit_cents to include, in the order's own currency. Pair with currency when your accounts use more than one
price_max_cents integer Highest buyer_pays_per_unit_cents to include, in the order's own currency
older_than_days integer Only orders at least this many days old, 1 to 3650. Steam does not date buy orders, so this counts from when SteamLabs first saw the order, which for an order placed here is when you placed it
sort string created_at (default), buyer_pays_per_unit_cents, closed_at
direction string asc or desc (default)
per_page integer 50 by default, 200 at most
Bash
curl "https://dashboard.steamlabs.dev/api/v1/market/steam/buy-orders?state=open&per_page=1" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY"
JSON
{
    "data": [
        {
            "id": "019fb443-6b71-70aa-8f3c-51d0c9e4a712",
            "buy_order_id": "6412887301",
            "state": "open",
            "steam_account": {
                "id": "019fb42e-9a7e-728d-b960-8b4c2162898c",
                "username": "farm_017"
            },
            "appid": 730,
            "game": "cs2",
            "market_hash_name": "Fracture Case",
            "name": "Fracture Case",
            "icon_url": "https://community.fastly.steamstatic.com/economy/image/…",
            "buyer_pays_per_unit_cents": 21,
            "currency": "EUR",
            "quantity": 250,
            "quantity_remaining": 187,
            "quantity_filled": 63,
            "closed_at": null,
            "created_at": "2026-07-24T08:12:44+00:00"
        }
    ],
    "meta": { "page": 1, "per_page": 1, "total": 12, "last_page": 12 }
}

On CSFloat and market.csgo this answers 404 venue_unsupported. Those venues are sell-only.

Place a buy order

Rest one bid across a selection of accounts.

POST/api/v1/market/{venue}/buy-orders

Place one buy order across a selection of accounts. Steam only.

API key required

Requires market.write.

Field Type Description
market_hash_name string The exact market hash name to bid on. Up to 255 characters
game string cs2, tf2, or steam
prices_cents object Per-unit buyer-pays price in cents, keyed by ISO wallet currency. At least one entry, each at least 3 cents
quantity_mode string fixed (default) or max_affordable
quantity integer Units per order in fixed mode. 1 by default, 1,000 at most. Refused with max_affordable
max_quantity integer Optional cap in max_affordable mode, 1 to 1,000. Refused in fixed mode
account_ids uuid[] Accounts to place on, up to 1,000. Leave it out for the whole eligible fleet
Bash
curl -X POST "https://dashboard.steamlabs.dev/api/v1/market/steam/buy-orders" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"game":"cs2","market_hash_name":"Fracture Case","quantity":250,"prices_cents":{"EUR":21,"PLN":92}}'

Answers 202, one task per currency group:

JSON
{
    "task_ids": [
        "019fb444-9e02-72c1-b7a8-3d5e1f0b6c49",
        "019fb444-9e33-7410-84be-c1a72d9f5e80"
    ],
    "accounts_affected": 128,
    "async": false,
    "accounts_underfunded": 14,
    "accounts_busy": 2,
    "accounts_unknown_currency": 3,
    "selection_currencies": ["EUR", "PLN"]
}

202 rather than 201 is not a technicality: nothing exists yet. Steam only knows about an order once a worker has logged the account in and placed it. The order rows appear later, through the sync that confirms them, so watch the returned tasks to know when.

The two skip counts need different fixes. accounts_underfunded means Steam's cap of ten times the wallet balance would reject the order, so add funds or lower the price. In max_affordable mode it means the wallet, as last synced and after open orders, cannot pay for a single unit. accounts_busy means the account already had market work in flight, and the same submission works again in a minute. accounts_unknown_currency counts accounts whose wallet currency has never been synced, so they could not be priced at all.

Only accounts that can actually place are targeted, named or not: market access allowed, an identity secret stored, and a billing address on file.

A price more than three times the item's Steam market price in that currency is treated as a mistake: the account's task fails with the reason in error and nothing is bid. See the place_buy_order notes in Tasks.

Refusals:

Status Code Meaning
422 missing_price_for_currency A currency in the selection had no price. Adds missing_currencies and selection_currencies. Nothing was placed
422 nothing_eligible No selected account could fund the order. Adds the four counts above
403 plan_limit_reached Your plan does not sell on Steam (allowed_marketplaces) or does not include place_buy_order (allowed_task_types)

Buy as many as the wallet covers

Send "quantity_mode": "max_affordable" instead of a quantity and each account bids on as many units as its own wallet can pay for. The worker works the number out when the order is placed: the live wallet balance, minus what the account's other open buy orders still hold, divided by that currency's price and rounded down. max_quantity caps it. Steam's ten-times allowance is not used, so the wallet can pay for every unit if the whole order fills.

JSON
{
    "game": "tf2",
    "market_hash_name": "Mann Co. Supply Crate Key",
    "quantity_mode": "max_affordable",
    "max_quantity": 50,
    "prices_cents": {"EUR": 206}
}

An account that turns out to be unable to pay for one unit completes its task as skipped rather than failing. Each task's task_data reports the quantity it bid on, or the skip_reason (see Tasks).

Refresh buy orders

POST/api/v1/market/{venue}/buy-orders/sync

Pull fresh buy orders from Steam. Steam only.

API key required

Requires market.write.

Takes the same optional account_ids as the listings refresh and answers the same 202 envelope with task_id, accounts_affected, async and accounts_skipped.

Bash
curl -X POST "https://dashboard.steamlabs.dev/api/v1/market/steam/buy-orders/sync" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

Cancel many buy orders

POST/api/v1/market/{venue}/buy-orders/cancel

Cancel many resting orders, grouped into one task per account. Steam only.

API key required

Requires market.write.

Field Type Description
buy_order_ids uuid[] The orders to cancel, up to 1,000. Required unless you send filters
filters object The same filter keys the buy orders index accepts. Required unless you send buy_order_ids
dry_run boolean Report what this call would cancel, and queue nothing. Answers 200 with dry_run, matched, buy_orders_affected, accounts_affected and buy_order_ids, the same way as previewing a listings cancel

To retire one position across your accounts, filter on its exact name. Each account holding it gets one task that cancels only that order, and accounts without it are not logged in at all:

Bash
curl -X POST "https://dashboard.steamlabs.dev/api/v1/market/steam/buy-orders/cancel" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"filters":{"state":"open","market_hash_names":["Fracture Case"]}}'
JSON
{
    "task_ids": ["019fb445-4411-7b90-9d0c-6e2a5f38c114"],
    "accounts_affected": 1,
    "buy_orders_affected": 9,
    "accounts_busy": 0
}

Cancelling frees the wallet balance an open order commits, so it is never plan-gated and never needs an Idempotency-Key. Its target state is "not resting", and a repeat is a no-op.

Orders that are no longer open are dropped. If none of the selection is still open you get 422 nothing_to_cancel with matched. A filter matching more than 1,000 orders answers 422 bulk_limit_exceeded.

Cancel one buy order

POST/api/v1/market/{venue}/buy-orders/{buyOrder}/cancel

Cancel one resting order. Steam only.

API key required

Requires market.write.

Bash
curl -X POST "https://dashboard.steamlabs.dev/api/v1/market/steam/buy-orders/019fb443-6b71-70aa-8f3c-51d0c9e4a712/cancel" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY"
JSON
{
    "task_ids": ["019fb445-77c3-7f21-a0b6-9c4e0d1a8b62"],
    "accounts_affected": 1,
    "buy_orders_affected": 1
}

An order that is not open answers 422 buy_order_not_open with its state. An account with market work already in flight answers 409 account_busy.

Buy a specific listing

Buy the copy you picked, not whichever copy is cheapest.

POST/api/v1/market/{venue}/listings/buy

Buy one or more specific Steam market listings by listing id, each on a named account. Steam only.

API key required

Requires market.write.

A buy order fills with whichever copy of an item is cheapest. For a skin the copy matters: two listings at the same price can carry a 0.16 and a 0.37 float. Steam's market page identifies each copy by its listing id, and that id is what you send here. The account pays from its own Steam wallet.

Send one purchase as top-level fields, or up to 100 as purchases. Every entry is a complete instruction of its own:

Field Type Description
account_id uuid The account that buys and pays. One of yours, or the entry fails validation
game string cs2, tf2, or steam
market_hash_name string The exact market hash name of the item the listing belongs to, up to 255 characters. Steam only serves a listing's price on its item page, so this has to match
listing_id string The Steam listing id: a number of up to 20 digits, as the market page and the listings render endpoint report it
max_total_cents integer The most the account may pay, fees included, in cents of its own wallet currency. At least 3
purchases object[] The batch form: 1 to 100 entries of the five fields above, instead of sending them at the top level
Bash
curl -X POST "https://dashboard.steamlabs.dev/api/v1/market/steam/listings/buy" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"account_id":"019fb432-6d10-70bb-a1c9-4e2f8b7d5a01","game":"cs2","market_hash_name":"AK-47 | Redline (Field-Tested)","listing_id":"7416299133811234567","max_total_cents":1250}'

Answers 202, one buy_market_listing task per entry that could be queued, with a per-entry report in the order you sent them:

JSON
{
    "task_ids": [
        "019fb444-9e02-72c1-b7a8-3d5e1f0b6c49"
    ],
    "accounts_affected": 1,
    "purchases_queued": 1,
    "purchases_skipped": 1,
    "purchases": [
        {
            "index": 0,
            "account_id": "019fb432-6d10-70bb-a1c9-4e2f8b7d5a01",
            "listing_id": "7416299133811234567",
            "task_id": "019fb444-9e02-72c1-b7a8-3d5e1f0b6c49",
            "status": "queued",
            "skip_reason": null
        },
        {
            "index": 1,
            "account_id": "019fb432-6d10-70bb-a1c9-4e2f8b7d5a02",
            "listing_id": "7416299133811234568",
            "task_id": null,
            "status": "skipped",
            "skip_reason": "insufficient_funds"
        }
    ]
}

Entries never refuse each other. An account that cannot buy right now is skipped with its reason and the other entries still queue. skip_reason is one of insufficient_funds (the account's last synced wallet balance is below the cap), cannot_place_buy_orders (no market access, no mobile authenticator, or no billing address), no_wallet_currency (Steam has not opened a wallet for the account yet) or task_in_flight (the account already has market work queued or running; send that entry again once it finishes). When every entry was skipped the answer is 422 nothing_eligible with the same purchases report.

What the task reports

Each task does the work in this order: logs the account in, checks it may use the market, reads the listing's live price in the account's wallet currency from the item's listings on Steam (the ones priced at or under your cap, cheapest first, up to 200 of them, then the cheapest above the cap), refuses if that total is above max_total_cents, and only then submits the purchase with exactly those amounts. Steam re-checks the amounts server-side, so the account can never pay more than the cap. Steam asks for a mobile confirmation on market purchases, which the task accepts with the account's identity secret.

A finished task carries outcome in its task_data (read it with GET /api/v1/tasks/{id}):

outcome Meaning
purchased Bought. total_cents is what was paid (fees included), subtotal_cents and fee_cents split it, wallet_balance_after_cents is the new balance, and asset_id is the id the item got in the account's inventory
sold_out The listing is gone: it sold to someone else or was removed
price_changed The listing is live but costs more than your cap (total_cents is its live total), or Steam reported a price change between the read and the buy
insufficient_funds The live wallet balance is below the listing's total
not_found The listing was not among the cheapest listings the task checked (listings_scanned; the item had listings_within_cap priced at or under the cap), so its price could not be read
currency_mismatch The account's wallet currency changed since the cap was set, so the two could not be compared

Every outcome but purchased is a refusal that cost nothing, reported as a completed task with a readable message. The task only fails on a genuine fault: no session, a Steam error, or a confirmation that would not accept.

Whenever the listing was read, task_data also carries the copy's identity: listing_asset_id (the seller-side asset id) and, for CS2 items, wear (the float) and paint_seed (the pattern), as Steam reports them per listing.

asset_id is read from the account's market history a few seconds after the purchase settles. It is null when Steam had not written that record yet; the item is in the inventory either way, and an inventory refresh shows it. A purchase also counts as an "items received" event for the account's automatic inventory refresh.

Refusals:

Status Code Meaning
422 validation_failed A field is wrong on an entry. Batch errors are keyed purchases.{index}.{field}; an account that is not yours fails on its account_id
422 nothing_eligible Every entry was skipped. Adds purchases with the reasons
403 plan_limit_reached Your plan does not sell on Steam (allowed_marketplaces) or does not include buy_market_listing (allowed_task_types)

Sales history

What has already happened on this venue: listed, cancelled, sold, bought, plus the marketplace-only lifecycle steps.

Steam, CSFloat, market.csgo, DMarket and Skinport. skinland answers 404 with code venue_unsupported, on both endpoints below: these are listing events, and it has no listings. Read /market/skinland/trades instead, which keeps terminal sales alongside live ones.

GET/api/v1/market/{venue}/history

Market history events on this venue, newest first.

API key required

Requires market.read.

Parameter Type Description
event_type integer One of the codes below
account_id uuid Only events from this Steam account. Must be one you own
listing_id string Only events for this venue listing. Pair with account_id when the same external id can exist on more than one account
game string cs2, tf2, or steam
appid integer The Steam app id. Wins over game when both are sent
search string Matches the item name or its market hash name
sort string happened_at (default), created_at
direction string asc or desc (default)
per_page integer 50 by default, 200 at most

event_type is the stored integer. Codes 1 to 4 are Steam's own history codes, 5 is a repricing detected by SteamLabs, and 10 to 12 are marketplace lifecycle transitions.

Code event_type_key Meaning
1 listing_created An item went up for sale
2 listing_canceled A listing was pulled
3 listing_sold A listing sold
4 purchased You bought an item
5 listing_repriced An open listing's price changed
10 delivered The item reached the buyer
11 settled The venue released the funds
12 failed The lifecycle step failed
Bash
curl "https://dashboard.steamlabs.dev/api/v1/market/steam/history?event_type=3&per_page=1" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY"

Use listing_id with account_id to build the timeline for one listing. CSFloat and Market.CSGO add a listing_repriced event whenever a fresh venue snapshot shows a different price.

JSON
{
    "data": [
        {
            "id": "019fb446-1a05-7c88-9f42-88b1e0c3d975",
            "event_type": 3,
            "event_type_key": "listing_sold",
            "marketplace": "steam",
            "steam_account": {
                "id": "019fb42e-9a7e-728d-b960-8b4c2162898c",
                "username": "farm_017"
            },
            "listing_id": "4258109377312946881",
            "purchase_id": null,
            "actor_steam64_id": "76561198000000042",
            "asset_id": "38294011745",
            "new_asset_id": "38301884012",
            "appid": 730,
            "game": "cs2",
            "context_id": "2",
            "market_hash_name": "AK-47 | Redline (Field-Tested)",
            "name": "AK-47 | Redline",
            "icon_url": "https://community.fastly.steamstatic.com/economy/image/…",
            "listed_price_cents": 1842,
            "paid_amount_cents": 1842,
            "paid_fee_cents": 240,
            "received_amount_cents": 1602,
            "currency": "EUR",
            "purchase_failed": false,
            "happened_at": "2026-07-30T14:02:11+00:00",
            "created_at": "2026-07-30T14:07:36+00:00"
        }
    ],
    "meta": { "page": 1, "per_page": 1, "total": 2941, "last_page": 2941 }
}

event_type_key rides alongside the integer so you can branch on something legible. Nobody reads 11 and thinks "settled".

All three listing venues write into one history table and every query here is venue-scoped, so CSFloat proceeds never show up under Steam.

Refresh history

POST/api/v1/market/{venue}/history/sync

Pull fresh history from the venue.

API key required

Requires market.write.

Takes the same optional account_ids as the listings refresh, capped at 1,000.

Bash
curl -X POST "https://dashboard.steamlabs.dev/api/v1/market/steam/history/sync" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

Steam has its own history task, because its history page is a separate and expensive fetch from the listings one. You get the task_id envelope back.

CSFloat and market.csgo carry history on the same poll as everything else, so this is the same poll-now request the listings refresh makes: { "task_ids": [], "accounts_affected": 34, "sync": "poll_requested" }. Asking for either gets both.

Skinport history refresh queues the same sync_skinport task as the listings refresh: { "task_ids": [...], "accounts_affected": N, "sync": "task_queued" }. A vanished listed item is sold only when /api/transactions has a matching sale; otherwise it is canceled.

List sale deliveries

Sales in flight on the P2P venues: the item sold, and you still have to hand it over.

GET/api/v1/market/{venue}/trades

Sales awaiting or completing delivery. Not Steam or DMarket.

API key required

Requires market.read.

On CSFloat and market.csgo the marketplace only brokers the deal. Between "sold" and "paid" there is a Steam trade offer you must send, on a clock, or the venue penalises you. These rows track that window. /market/steam/trades answers 404 venue_unsupported, because Valve holds the item and a Steam sale is finished the moment it happens.

Parameter Type Description
state string A venue state (below), or all, or needs_action for the sales waiting on you right now
account_id uuid Only sales from this Steam account. Must be one you own
origin string steamlabs or external. Not on AssetPay, where every sale is ours
source string AssetPay only: instant or pool
search string Matches the item name or its market hash name
sort string A venue sort (below)
direction string asc or desc (default)
per_page integer 50 by default, 200 at most

The state and sort vocabularies are both per venue, because the lifecycles genuinely differ. CSFloat has an accept stage and a 2 hour clock; market.csgo has neither and roughly 7 hours; Skin.Land has a 10 minute window that SteamLabs answers for you.

Venue States needs_action covers Sorts (first is the default)
csfloat queued, accepted, delivering, delivered, settled, canceled, failed queued, accepted created_at, sale_price_cents
marketcsgo queued, delivering, delivered, settled, canceled, failed queued sold_at, created_at, sale_price_cents
skinland queued, offered, accepted, settling, settled, declined, expired, failed offered created_at, sum_cents
assetpay queued, sending, offered, clearing, settled, declined, canceled, failed, reversed failed, reversed created_at, gross_cents
Bash
curl "https://dashboard.steamlabs.dev/api/v1/market/csfloat/trades?state=needs_action&per_page=1" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY"

A CSFloat sale:

JSON
{
    "data": [
        {
            "id": "019fb447-2f60-7d13-b8a4-5c0e9d7f2136",
            "trade_id": "3f9a1c2e-77bd-4d0a-9f21-8ac4e5b60d11",
            "contract_id": "b1c7d0e4-2a55-4f88-9d33-6e2b7a9c1f04",
            "marketplace": "csfloat",
            "state": "accepted",
            "origin": "steamlabs",
            "steam_account": {
                "id": "019fb42e-9a7e-728d-b960-8b4c2162898c",
                "username": "farm_017"
            },
            "buyer": { "steam64_id": "76561198000000042", "persona": "kessler" },
            "asset_id": "38294011745",
            "appid": 730,
            "game": "cs2",
            "market_hash_name": "AK-47 | Redline (Field-Tested)",
            "name": "AK-47 | Redline",
            "icon_url": "https://csfloat.com/…",
            "sale_price_cents": 1980,
            "fee_cents": 40,
            "receive_cents": 1940,
            "currency": "USD",
            "steam_offer_id": null,
            "steam_offer_state": null,
            "delivery_task_id": null,
            "delivery_attempts": 0,
            "last_error": null,
            "accepted_at": "2026-07-30T13:58:02+00:00",
            "accept_deadline_at": "2026-07-30T15:58:02+00:00",
            "delivered_at": null,
            "buyer_accepted_at": null,
            "settlement_ends_at": null,
            "settled_at": null,
            "created_at": "2026-07-30T13:41:19+00:00"
        }
    ],
    "meta": { "page": 1, "per_page": 1, "total": 6, "last_page": 6 }
}

A market.csgo sale carries market_item_id instead of trade_id and contract_id, no buyer block, and its own clock fields: sold_at, delivery_deadline_at, registered_at, delivered_at, settlement_ends_at, settled_at.

An AssetPay sale, like a Skin.Land one, is a basket: the money is on the row (gross_cents) and the identity is in items.

JSON
{
    "data": [
        {
            "id": "019fd1a2-4c7e-7b10-9b2e-3c1f7a9d2e44",
            "marketplace": "assetpay",
            "source": "pool",
            "state": "clearing",
            "order_id": "ap_ord_8H2KQ4",
            "steam_account": {
                "id": "019fb42e-9a7e-728d-b960-8b4c2162898c",
                "username": "farm_017"
            },
            "item_count": 1,
            "items": [
                {
                    "asset_id": "38912044517",
                    "appid": 730,
                    "game": "cs2",
                    "market_hash_name": "AK-47 | Case Hardened (Field-Tested)",
                    "name": "AK-47 | Case Hardened",
                    "icon_url": "https://community.cloudflare.steamstatic.com/…",
                    "price_cents": 18450
                }
            ],
            "gross_cents": 18450,
            "currency": "USD",
            "steam_offer_id": "7812345678",
            "bot_name": null,
            "task_id": "019fd1a2-9b31-70ac-8f52-2d7c1b4e6a08",
            "failure_reason": null,
            "last_error": null,
            "reversed_by": null,
            "queued_at": "2026-09-12T10:15:03+00:00",
            "offered_at": "2026-09-12T10:15:41+00:00",
            "accepted_at": "2026-09-12T10:16:40+00:00",
            "hold_until": "2026-09-19T10:16:40+00:00",
            "last_checked_at": "2026-09-13T11:02:15+00:00",
            "settled_at": null,
            "reversed_at": null,
            "created_at": "2026-09-12T10:15:03+00:00"
        }
    ],
    "meta": { "page": 1, "per_page": 1, "total": 4, "last_page": 4 }
}

source is the fork. An instant sale is a basket AssetPay bought outright at the Sell now price, so bot_name names the AssetPay bot that sent the offer we accepted. A pool sale is one skin their store sold to a buyer, so order_id is set and steam_offer_id is the offer our bot sent that buyer.

hold_until is Steam's trade protection, read off the accepted offer rather than computed, which is why settled_at lags a delivery by about a week. last_checked_at is the last time we logged in to check that trade had not been reversed; there are no fee fields, because AssetPay charges nothing on either kind and the SteamLabs fee is taken at cash-out instead.

delivery_task_id is the thing to watch. It is set the moment a delivery is queued, and it is why repeating a deliver call finds nothing to do.

Deliver many sales

POST/api/v1/market/{venue}/trades/deliver

Send the items for many due sales, grouped into one task per account.

API key required

Requires market.write.

Field Type Description
trade_ids uuid[] The sales to deliver, up to 1,000. Required unless you send filters
filters object The same filter keys the sales index accepts. Required unless you send trade_ids
Bash
curl -X POST "https://dashboard.steamlabs.dev/api/v1/market/marketcsgo/trades/deliver" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"filters":{"state":"needs_action"}}'
JSON
{
    "task_ids": [
        "019fb448-05aa-7e34-b1f7-2d9c8e0a4b73",
        "019fb448-0611-7c02-9a58-4f3b1d7e6055"
    ],
    "accounts_affected": 2,
    "sales_affected": 19,
    "sales_busy": 0,
    "sales_ineligible": 3
}

sales_ineligible counts sales that were not deliverable from their current state, and they are skipped rather than failing the batch.

When nothing could be queued you get one of two answers, and they need different responses from you:

Status Code Meaning
409 account_busy Every selected sale belongs to an account with market work already in flight. Retry shortly
422 nothing_deliverable No selected sale was in a deliverable state. Fix the selection

Both add sales_ineligible and sales_busy.

Cancel many sales

POST/api/v1/market/{venue}/trades/cancel

Refuse many sales before anything moves. CSFloat only.

API key required

Requires market.write.

Takes the same trade_ids or filters selection as the deliver endpoint.

Bash
curl -X POST "https://dashboard.steamlabs.dev/api/v1/market/csfloat/trades/cancel" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"trade_ids":["019fb447-2f60-7d13-b8a4-5c0e9d7f2136"]}'

Answers 200, not 202. Cancelling is a local state change with no worker involved, so by the time you get this it has already happened:

JSON
{
    "sales_affected": 1,
    "matched": 1
}

The window is narrow on purpose: only while the sale is still queued and unassigned. Nothing cancellable in the selection answers 422 nothing_cancelable with matched.

market.csgo offers no cancel at all, here or in the dashboard, and answers 404 venue_unsupported. Its sales are registered with the venue the moment they land, so a local refusal would leave your row saying cancelled while the venue waits for an item and holds you responsible.

Accept and deliver one sale

POST/api/v1/market/{venue}/trades/{trade}/accept-and-deliver

Accept the buyer's offer and send the item. CSFloat only.

API key required

Requires market.write.

Bash
curl -X POST "https://dashboard.steamlabs.dev/api/v1/market/csfloat/trades/019fb447-2f60-7d13-b8a4-5c0e9d7f2136/accept-and-deliver" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY"
JSON
{
    "task_ids": ["019fb449-3b12-70ef-8c47-1a6d5e2f9073"],
    "accounts_affected": 1,
    "sales_affected": 1
}

One endpoint rather than two, on purpose. Accepting without sending starts a 2 hour penalty clock you could not then satisfy from the API.

The sale must be queued with no delivery already assigned, otherwise 422 trade_not_in_state with state and required_state. On market.csgo this answers 404 venue_unsupported: there is no accept stage.

Deliver one sale

POST/api/v1/market/{venue}/trades/{trade}/deliver

Send the item now for a sale that is already due.

API key required

Requires market.write.

"Due" means accepted on CSFloat and queued on market.csgo: the same moment in two vocabularies. Either way the sale must have no delivery assigned yet.

Bash
curl -X POST "https://dashboard.steamlabs.dev/api/v1/market/marketcsgo/trades/019fb447-9c31-7a80-bd12-70e5c3f4a819/deliver" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY"
JSON
{
    "task_ids": ["019fb449-6d70-7188-a933-52c0e7b1f486"],
    "accounts_affected": 1,
    "sales_affected": 1
}

Wrong state gives 422 trade_not_in_state, naming the state it wanted. An account with market work in flight gives 409 account_busy.

Retry a failed delivery

POST/api/v1/market/{venue}/trades/{trade}/retry-delivery

Try a failed delivery again.

API key required

Requires market.write.

Bash
curl -X POST "https://dashboard.steamlabs.dev/api/v1/market/csfloat/trades/019fb447-2f60-7d13-b8a4-5c0e9d7f2136/retry-delivery" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY"

Answers the same 202 envelope as Deliver one sale.

Separate from deliver even though both end in the same task, because the states they start from are disjoint. This one requires failed. Anything else gives 422 trade_not_in_state, which is more useful than one endpoint that silently accepts both.

Check last_error and delivery_attempts on the sale before retrying. A delivery that failed because the item is gone will fail again.

Cancel one sale

POST/api/v1/market/{venue}/trades/{trade}/cancel

Refuse one sale before anything moves. CSFloat only.

API key required

Requires market.write.

Bash
curl -X POST "https://dashboard.steamlabs.dev/api/v1/market/csfloat/trades/019fb447-2f60-7d13-b8a4-5c0e9d7f2136/cancel" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY"

Answers 200 with the whole updated sale, in the same shape the index returns:

JSON
{
    "id": "019fb447-2f60-7d13-b8a4-5c0e9d7f2136",
    "trade_id": "3f9a1c2e-77bd-4d0a-9f21-8ac4e5b60d11",
    "marketplace": "csfloat",
    "state": "canceled",
    "sale_price_cents": 1980,
    "receive_cents": 1940,
    "currency": "USD",
    "delivery_task_id": null,
    "created_at": "2026-07-30T13:41:19+00:00"
}

Only a sale that is still queued and unassigned can be refused. Anything else gives 422 trade_not_in_state. market.csgo answers 404 venue_unsupported.

Earnings

What your AssetPay sales paid, and where the money is now. AssetPay only: every other venue pays into a wallet you hold at the venue, so they answer 404 venue_unsupported here.

GET/api/v1/market/{venue}/earnings

Available, clearing and paid-out totals for the venue. AssetPay only.

API key required

Requires market.read.

Bash
curl "https://dashboard.steamlabs.dev/api/v1/market/assetpay/earnings" \
  -H "Authorization: Bearer $STEAMLABS_API_KEY"
JSON
{
    "currency": "USD",
    "available_cents": 4210,
    "clearing_cents": 18450,
    "next_release_at": "2026-09-19T10:16:40+00:00",
    "paid_out_cents": 129000,
    "payout_count": 4,
    "platform_credit_cents": 98498,
    "platform_credit_currency": "EUR",
    "payout": {
        "fee_percent": 5,
        "minimum_cents": 500,
        "networks": [
            { "chain": "BSC", "currencies": ["USDT", "USDC"], "network_fee_cents": 0 },
            { "chain": "ETH", "currencies": ["USDT", "USDC"], "network_fee_cents": 100 },
            { "chain": "SOL", "currencies": ["USDT", "USDC"], "network_fee_cents": 0 },
            { "chain": "TRON", "currencies": ["USDT"], "network_fee_cents": 250 }
        ],
        "requestable_via_api": false
    }
}

Three pots, and they never mix. available_cents has cleared Steam's trade protection and is yours to withdraw. clearing_cents is sold but still inside that protection, and next_release_at is when the earliest of it comes out. platform_credit_cents is prepaid SteamLabs credit in the billing currency: it buys the platform and never comes back out, which is why it is reported separately and not added to anything.

payout holds the terms a cash-out would apply. fee_percent is the SteamLabs fee, taken from the amount. Each entry in networks is a network you can be paid on, the coins it pays, and AssetPay's flat network_fee_cents for it, which comes out of what is sent. AssetPay does not quote that fee in advance, so it is the fee AssetPay charged on the most recent payout on that network, or its published fee until there has been one; a payout's own network_fee_cents is the exact figure.

available_cents can be negative. A trade reversed after the money was already credited claws it back, and the balance is allowed to go under zero rather than silently absorbing the loss.

Earnings ledger

Every movement of the earnings balance, newest first.

GET/api/v1/market/{venue}/earnings/ledger

The earnings ledger. AssetPay only.

API key required

Requires market.read.

Parameter Type Description
type string sale_settled, sale_reversed, payout_hold, payout_release or adjustment
per_page integer 50 by default, 200 at most
JSON
{
    "data": [
        {
            "id": "019fd1b7-4a02-73de-9c11-0f6a2e4b8d97",
            "type": "sale_settled",
            "amount_cents": 930,
            "balance_after_cents": 4210,
            "currency": "USD",
            "reason": "AssetPay pool sale settled",
            "source_type": "App\\Models\\AssetpaySale",
            "source_id": "019fd1a2-4c7e-7b10-9b2e-3c1f7a9d2e44",
            "created_at": "2026-09-19T10:31:52+00:00"
        }
    ],
    "meta": { "page": 1, "per_page": 50, "total": 12, "last_page": 1 }
}

amount_cents is signed, so balance_after_cents adds up: a settled sale is positive, a payout or a reversal negative. source_id points at whatever caused the row, which for a sale is the id you read from /market/assetpay/trades.

Payouts

Cash-outs and where each one stands.

GET/api/v1/market/{venue}/payouts

Payout history. AssetPay only.

API key required

Requires market.read.

Parameter Type Description
state string requested, sending, completed, failed or rejected
per_page integer 50 by default, 200 at most
JSON
{
    "data": [
        {
            "id": "019fd1c4-8e55-7a20-b7f3-91c4d0e2a6b8",
            "state": "completed",
            "amount_cents": 5000,
            "fee_cents": 250,
            "net_cents": 4750,
            "network_fee_cents": 30,
            "receive_cents": 4720,
            "currency": "USDT",
            "chain": "BSC",
            "address": "0x2f1c…",
            "tx_hash": "0x9ab3…",
            "explorer_url": "https://bscscan.com/tx/0x9ab3…",
            "assetpay_status": "completed",
            "failure_reason": null,
            "requested_at": "2026-09-14T08:02:11+00:00",
            "sent_at": "2026-09-14T08:44:03+00:00",
            "resolved_at": "2026-09-14T08:44:03+00:00"
        }
    ],
    "meta": { "page": 1, "per_page": 50, "total": 4, "last_page": 1 }
}

amount_cents is what left your balance and net_cents is what went to AssetPay after the SteamLabs fee. AssetPay then takes the network's flat transfer fee out of that, so receive_cents is what the address actually received and network_fee_cents is the difference; both are null until AssetPay has taken the payout, and stay null on a payout an admin sent by hand. chain is BSC, ETH, SOL or TRON, and currency is USDT or USDC (Tron pays USDT only). assetpay_status is AssetPay's own word for where a sending payout stands (awaiting_approval, in_review, approved or sent) and is null for manual payouts. A failed payout's failure_reason says why, and the full amount is back on your balance. The whole address is returned rather than a truncated one: checking it against a block explorer is the only reason to read this. explorer_url links the transaction on the chain's explorer (BscScan, Etherscan, Solscan or Tronscan) and is null until there is a tx_hash.

Errors

Beyond the universal codes, this group returns:

Status Code Meaning
404 unknown_venue The path segment is not a marketplace. Adds venues
404 venue_unsupported The venue has no such surface. Adds venue and supported_venues
409 account_busy The account already has marketplace work queued or running. Wait for that task
422 listing_not_open The listing is no longer open. Adds state
422 buy_order_not_open The buy order is no longer open. Adds state
422 trade_not_in_state The sale is in the wrong state. Adds state and required_state
422 nothing_to_cancel Nothing in the selection is still open. Adds matched
422 nothing_cancelable No selected sale can still be cancelled. Adds matched
422 nothing_deliverable No selected sale can be delivered from its state
422 nothing_eligible No account matched the refresh, none could fund the order, or every listing purchase was skipped (adds purchases)
422 missing_price_for_currency A wallet currency in the selection had no price. Adds missing_currencies and selection_currencies
422 bulk_limit_exceeded Over 1,000 ids, or a filter matching over 1,000 rows. Adds max, and matched for a filter
503 maintenance_mode Platform maintenance pauses new listings and buy orders. Cancels, syncs and reads keep working. Adds reason

Everything else, including 401, 403 missing_scope, 403 plan_limit_reached, 422 validation_failed and 429, is on Errors.