Inventory
Valuation, performance and collections for any public Steam inventory, and purchase records and stack changes for your own.
Items in a profile inventory, with market value
/api/inventory/{profileId}One row per item held, with its quantity and current market value, paginated. Accepts a profile id or guid, a Steam vanity name, or a 64-bit Steam id.
The default page size is large (2,000) because this is the whole-inventory view, and pageSize is clamped to 5,000 rather than rejected. metric chooses what the primary sort ranks on and priceSort gives it a direction.
It answers 401 when the profile has opted out of item analytics and the caller is neither its owner nor an administrator. That applies to every per-profile inventory read.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
| profileId | path | yes | Profile id, profile guid, vanity url, or 64-bit Steam id. |
| search | query | no | Filter by item name or type. |
| collection | query | no | Filter to a single collection name (all = no filter). |
| priceSort | query | no | Primary sort by per-item market price. Defaults to desc.One of: |
| nameSort | query | no | Name order (A-Z / Z-A). Defaults to az.One of: |
| sortKey | query | no | Which dropdown is the primary sort; the other only breaks ties. Defaults to price.One of: |
| metric | query | no | What the primary sort ranks on (priceSort gives it a direction). price = per-unit market price, stack = unit price × owned quantity, ath/atl = the current Steam ask as a ratio of the all-time high/low sale (ath desc / atl asc = "closest to"), demand = Steam units sold in the last 24 h, supply = Steam sell-order count. Defaults to price; an unrecognised value falls back to it rather than rejecting. ath, atl, demand and supply are Steam-only measures, so unlike price and stack they ignore the market parameter and always rank on Steam’s figures.One of: |
| page | query | no | 1-based page index. Defaults to 1. |
| pageSize | query | no | Items per page. Defaults to 2000, max 5000. |
| market | query | no | Valuation source for each item price: steam (default) or a specific market key (e.g. Skinport) present in this inventory. Also scopes visibility: unless includeUnpriced=true, only items priced by the selected view are listed. |
| includeUnpriced | query | no | true includes every owned item. Default (false) hides items the selected view cannot price — Steam view requires a resale price (store-only items are hidden), a market view requires that market's price. The inventory value endpoint keeps counting the full owned set.One of: |
| currency | query | no | 3-letter currency code. Defaults to the profile FK / USD. |
Request
curl "https://api.scmm.app/api/inventory/<profileId>?search=<search>"Response
array<object>- page*
number - pageSize*
number - total*
number - hasMore*
boolean - collections*
array<string> - markets*
array<string>
Collections represented in a profile inventory
/api/inventory/{profileId}/collectionsOne row per collection the profile owns at least one item from, with how much of the set it holds and what that is worth. It is the set-completion view of an inventory rather than a list of items.
It answers 401 when the profile has opted out of item analytics and the caller is neither its owner nor an administrator.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
| profileId | path | yes | Profile id, profile guid, vanity url, or 64-bit Steam id. |
| includeUnowned | query | no | If true, returns every tracked collection regardless of ownership (development env only). |
| currency | query | no | 3-letter currency code. Defaults to the profile FK / USD. |
Request
curl "https://api.scmm.app/api/inventory/<profileId>/collections?includeUnowned=false"Response
- name*
string - totalItems*
number - ownedItems*
number - completionPercent*
numberShare of the collection's items the profile owns, from 0 to 100.
- totalCost*
number | nullCost of buying every item in the collection at current prices, in hundredths of
currency, or null when it cannot be priced. - ownedValue*
numberValue of the items the profile owns, in hundredths of
currency. - currency*
string array<object>
Total inventory value over a trailing window
/api/inventory/{profileId}/historyOne point per day of the profile’s total inventory value, oldest first. A day the value was never computed on is absent rather than zero — never interpolate across a gap, because a missing day means no snapshot, not a worthless inventory.
It answers 401 when the profile has opted out of item analytics and the caller is neither its owner nor an administrator.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
| profileId | path | yes | Profile id, profile guid, vanity url, or 64-bit Steam id. |
| period | query | no | Window: 1d, 7d, 30d, 90d. Defaults to 30d.One of: |
| currency | query | no | 3-letter currency code. Defaults to the profile FK / USD. |
Request
curl "https://api.scmm.app/api/inventory/<profileId>/history?period=1d"Response
- timestamp*
string - totalValue*
number
Purchase price, market price and return per item
/api/inventory/{profileId}/investmentAuth requiredRequires authentication, and answers 401 for anyone but the inventory owner or an administrator. Rows are one per inventory item (never grouped by skin) because the purchase price is recorded per item. Every money field is in the resolved display currency.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
| profileId | path | yes | Profile id, profile guid, vanity url, or 64-bit Steam id. |
| search | query | no | Filter by item name or type. |
| sortBy | query | no | Column to sort on. Defaults to buyPrice.One of: |
| sortDirection | query | no | Sort direction. Defaults to desc.One of: |
| page | query | no | 1-based page index. Defaults to 1. |
| pageSize | query | no | Items per page. Defaults to 25, max 100. |
| currency | query | no | 3-letter currency code. Defaults to the profile FK / USD. |
Request
curl "https://api.scmm.app/api/inventory/<profileId>/investment?search=<search>" \
-H "x-api-key: YOUR_KEY_HERE"Response
array<object>- page*
number - pageSize*
number - total*
numberMatching rows (inventory assets). Smaller than
totalUnitswhen the profile holds a stack. - totalUnits*
numberMatching units —
sum(quantity), the figure the page header calls "Inventory Items". - hasMore*
boolean - currency*
string - includeMarketFees*
boolean
Invested, gains, losses and net return, totalled
/api/inventory/{profileId}/investment/totalsAuth requiredRequires authentication, and answers 401 for anyone but the inventory owner or an administrator. Every figure is null until more than half the inventory carries purchase data — below that the numbers describe the missing data, not the portfolio.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
| profileId | path | yes | Profile id, profile guid, vanity url, or 64-bit Steam id. |
| currency | query | no | 3-letter currency code. Defaults to the profile FK / USD. |
Request
curl "https://api.scmm.app/api/inventory/<profileId>/investment/totals?currency=USD" \
-H "x-api-key: YOUR_KEY_HERE"Response
- invested*
number | null - gains*
number | null - losses*
number | null - netReturn*
number | null - currency*
string - itemsWithBuyPrices*
number - itemCount*
number - hasSetupInvestment*
boolean
Performance overview for one profile inventory
/api/inventory/{profileId}/performanceThe summary numbers for one inventory over the chosen window: its current value, the change across the window, the best and worst movers and the per-collection deltas. It is the overview the more specific performance/* endpoints break down.
Every figure is computed over period, which defaults to 24h — the shortest window and the noisiest, so widen it before drawing conclusions. It answers 401 when the profile has opted out of item analytics and the caller is neither its owner nor an administrator.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
| profileId | path | yes | Profile id, profile guid, vanity url, or 64-bit Steam id. |
| period | query | no | Window: 24h, 7d, 30d, 90d. Defaults to 24h.One of: |
Request
curl "https://api.scmm.app/api/inventory/<profileId>/performance?period=24h"Response
objectarray<object>array<object>- historyBackfillPending*
boolean
Per-collection performance over a window
/api/inventory/{profileId}/performance/collectionsOne row per collection the profile owns from, with its value and its value-weighted change over the window. Value-weighted rather than a simple mean, so a collection’s change reflects what the holder actually owns rather than treating one cheap item as equal to a set.
It answers 401 when the profile has opted out of item analytics and the caller is neither its owner nor an administrator.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
| profileId | path | yes | Profile id, profile guid, vanity url, or 64-bit Steam id. |
| period | query | no | Window: 24h, 7d, 30d, 90d. Defaults to 24h.One of: |
Request
curl "https://api.scmm.app/api/inventory/<profileId>/performance/collections?period=24h"Response
- name*
string - iconUrl*
string | null - value*
number - changePercent*
number | null - currency*
string - ownedCount*
number - totalCount*
number
Wipe and store-release events in a window
/api/inventory/{profileId}/performance/eventsDated game events inside the same window a performance series covers: monthly force wipes and item-store releases. They are returned separately from the series so a client can annotate it without a second time axis, and they explain most of the sharp moves in one.
It answers 401 when the profile has opted out of item analytics and the caller is neither its owner nor an administrator.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
| profileId | path | yes | Profile id, profile guid, vanity url, or 64-bit Steam id. |
| days | query | no | Trailing window in days. 0 returns all time. Defaults to 30. |
Request
curl "https://api.scmm.app/api/inventory/<profileId>/performance/events?days=30"Response
- kind*
enumwipefor a monthly force wipe,storefor an item store release - label*
string - timestamp*
string
Inventory performance report as CSV
/api/inventory/{profileId}/performance/exportThe same figures as the performance endpoints, as a CSV file: the portfolio summary followed by one row per owned item. Responds text/csv as an attachment rather than JSON, and the figures are computed over period in the resolved currency.
It answers 401 when the profile has opted out of item analytics and the caller is neither its owner nor an administrator.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
| profileId | path | yes | Profile id, profile guid, vanity url, or 64-bit Steam id. |
| period | query | no | Window the figures are computed over: 24h, 7d, 30d, 90d. Defaults to 24h.One of: |
| currency | query | no | 3-letter currency code. Defaults to the profile FK / USD. |
Request
curl "https://api.scmm.app/api/inventory/<profileId>/performance/export?period=24h"Portfolio value series over a trailing window
/api/inventory/{profileId}/performance/historyOne point per day of the profile’s portfolio value, oldest first, over a trailing window in days. days=0 returns the whole recorded history. A day with no snapshot is absent rather than zero.
It answers 401 when the profile has opted out of item analytics and the caller is neither its owner nor an administrator.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
| profileId | path | yes | Profile id, profile guid, vanity url, or 64-bit Steam id. |
| days | query | no | Trailing window in days. 0 returns all time. Defaults to 30. |
Request
curl "https://api.scmm.app/api/inventory/<profileId>/performance/history?days=30"Response
- timestamp*
string - value*
number
Per-item performance for one profile inventory
/api/inventory/{profileId}/performance/itemsOne row per item held, with its price, its change over the window, its recent volume and a sparkline of its recent levels — paginated, searchable and sortable. It is the detail behind the performance overview.
It answers 401 when the profile has opted out of item analytics and the caller is neither its owner nor an administrator.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
| profileId | path | yes | Profile id, profile guid, vanity url, or 64-bit Steam id. |
| period | query | no | Window: 24h, 7d, 30d, 90d. Defaults to 24h.One of: |
| search | query | no | Filter by item name or type. |
| sort | query | no | Sort order. Defaults to price_desc.One of: |
| page | query | no | 1-based page index. Defaults to 1. |
| pageSize | query | no | Items per page. Defaults to 24, max 100. |
Request
curl "https://api.scmm.app/api/inventory/<profileId>/performance/items?period=24h"Response
array<object>- total*
number - page*
number - pageSize*
number
Profile summary for an inventory
/api/inventory/{profileId}/summaryWho an inventory belongs to, in one small response: Steam id, name, avatar and when the inventory was last imported. It is the header a client needs before any of the heavier inventory reads, and it accepts the same identifier forms they do.
It answers 401 when the profile has opted out of item analytics and the caller is neither its owner nor an administrator.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
| profileId | path | yes | Profile id, profile guid, vanity url, or 64-bit Steam id. |
Request
curl "https://api.scmm.app/api/inventory/<profileId>/summary"Response
- profileId*
string - steamId*
string - name*
string | null - avatarUrl*
string | null - lastUpdatedInventoryOn*
string | null - privacy*
number - lastImportError*
string | nullWhy the most recent attempt to refresh this inventory did not finish, or
nullif it did.lastUpdatedInventoryOnstays the truth about the snapshot; this is the truth about the attempt to move it, and the two are independent — a non-null value here does not mean the inventory is unreadable.Prose meant for display, not a code to branch on: the wording is chosen to be shown to a person and can change without notice.
- refreshSuggested*
booleantruewhen this inventory's stored snapshot is past the staleness threshold and nothing has attempted to refresh it in the last hour — that is, asking us to refresh it now would actually do something.falsewheneverlastUpdatedInventoryOnisnull: an inventory that has never been imported is a different flow, not a very stale one.A suggestion, not a promise. It answers a question about this inventory alone; a refresh can still be declined for reasons that have nothing to do with it, such as a site-wide budget, and the value is recomputed per request rather than stored.
Current total value of a profile inventory
/api/inventory/{profileId}/valueThe current total market value of one inventory, plus the item counts behind it. This is the cheapest inventory read and the one to poll; the item list and the performance endpoints answer the same question in far more detail and cost accordingly.
It answers 401 when the profile has opted out of item analytics and the caller is neither its owner nor an administrator.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
| profileId | path | yes | Profile id, profile guid, vanity url, or 64-bit Steam id. |
| market | query | no | Valuation market. steam (default) prices via the Steam Community Market and refreshes the stored snapshot; a MarketType key returns a view-only total under that market’s listing prices. |
| currency | query | no | 3-letter currency code. Defaults to the profile FK / USD. |
Request
curl "https://api.scmm.app/api/inventory/<profileId>/value?market=steam"Response
- totalValue*
number - itemCount*
number - currency*
string - profitLoss*
number
Resolve a Steam id and queue an inventory import
/api/inventory/calculateResolves the identifier to a 64-bit Steam id (resolving vanity names via Steam when needed), creates a lightweight profile on first sight, and enqueues an inventory import. The import runs asynchronously — poll GET /api/inventory/import-status/{steamId} with the returned steamId until importing is false. Anonymous callers share an hourly import budget (per address and site-wide); when it is spent the response is 429 with a Retry-After header for the top of the hour. A caller signed in with a session is not subject to that budget. An x-api-key header is not a session on this route, so a key holder is budgeted as an anonymous caller.
Request body
- identifier*
string
Request
curl -X POST "https://api.scmm.app/api/inventory/calculate" \
-H "Content-Type: application/json" \
-d '{"identifier":"<identifier>"}'Response
- profileId*
stringProfile id to use on the other inventory endpoints.
- steamId*
stringThe 64-bit Steam id the identifier resolved to.
- name*
string | null - avatarUrl*
string | null - privacy*
numberSteam community visibility: 0 unknown, 1 private, 2 friends-only, 3 public.
- queued*
booleanWhether this call queued an import.
falsewhen nothing new was queued, for example because the inventory was refreshed recently. PollGET /api/inventory/import-status/{steamId}either way.
Combine every stack of each item in your inventory
/api/inventory/combine-allAuth requiredRequires authentication and your own Steam Web API key. For every item held in more than one stack, moves each other stack into the stack with the lowest asset id on Steam, one stack at a time. Stacks that cannot be traded or sold are left out unless stackUntradableAndUnmarketable is true. One request makes at most 25 changes, starts none after 45 seconds, and returns how many it made and how many remain; repeat it until remaining is 0. Each change Steam confirms is saved even if a later one fails. To see how many stacks it would combine before making any change, and without a key, use GET /api/inventory/combine-all/plan. Answers 400 when Steam refuses the change (its reason is in message), 401 when Steam rejects the key, 409 when another stack change is running for your inventory, 429 when Steam is rate-limiting the key, and 502 when Steam did not confirm a change; after a 502, queue a fresh import with POST /api/inventory/import/{steamId}?force=true and poll GET /api/inventory/import-status/{steamId} until importing is false before retrying, because the change may have happened. This request is not safe to retry automatically: a repeated request repeats the change, so turn off automatic retries for it in your HTTP client. Instead, after a timeout or a 502, import the inventory and read the stacks again before sending anything. Allow at least 60 seconds per request.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
| steam-api-key | header | yes | Your own Steam Web API key, from https://steamcommunity.com/dev/apikey. It is used for this one request to Steam and is not stored. |
Request body
- stackUntradableAndUnmarketable
booleanAlso combine stacks that cannot currently be traded or sold. The combined stack takes on their restriction.
Request
curl -X PUT "https://api.scmm.app/api/inventory/combine-all" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_KEY_HERE" \
-H "steam-api-key: YOUR_STEAM_API_KEY" \
-d '{"stackUntradableAndUnmarketable":true}'Response
- combined*
numberStacks combined by this request.
- remaining*
numberStacks still to combine. Repeat the request until this is 0.
Preview what combining every stack would do
/api/inventory/combine-all/planAuth requiredRequires authentication; no Steam Web API key, and nothing is sent to Steam. Returns how many items in your inventory are held in more than one stack and how many stacks PUT /api/inventory/combine-all would move into another stack, with the same rules and the same stackUntradableAndUnmarketable default. stacks is the number of changes that operation would make, so it is the combined plus remaining of its first response if nothing changes in between. requests is the fewest requests that operation takes at 25 changes each; it takes more when a request stops at its 45-second budget. All three are 0 when there is nothing to combine.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
| profileId | query | no | Profile id or 64-bit Steam id whose inventory to preview. Administrators only; anyone else naming another profile gets 404. Omit it for your own inventory. |
| stackUntradableAndUnmarketable | query | no | Also count stacks that cannot currently be traded or sold. Defaults to false. One of: |
Request
curl "https://api.scmm.app/api/inventory/combine-all/plan?stackUntradableAndUnmarketable=true" \
-H "x-api-key: YOUR_KEY_HERE"Response
- items*
numberItems held in more than one stack. Each would end in a single stack.
- stacks*
numberStacks that would be moved into another stack of the same item, one change each.
- requests*
numberThe fewest
PUT /api/inventory/combine-allrequests the combine takes. Each request makes a limited number of changes and also stops when its time budget runs out, so it can take more requests than this, never fewer. - purchaseRecordsReplaced*
numberHow many of the stacks that would be moved carry a purchase price or acquisition you recorded. Combining deletes those records: the combined units keep only the purchase record of the stack they are moved into.
Status of an on-demand inventory import
/api/inventory/import-status/{steamId}The poll target for an import queued by POST /api/inventory/calculate. It reports whether the import has produced a value, is still running, or finished without one — the third case is a real answer rather than a failure, and it is what a private or empty Steam inventory returns. Takes a 64-bit Steam id.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
| steamId | path | yes | 64-bit Steam id. |
Request
curl "https://api.scmm.app/api/inventory/import-status/<steamId>"Response
- status*
enumpendingwhile the first import is queued or running,readyonce an import has completed (the inventory may be empty),unavailablewhen an import finished without producing one. It does not say why. - importState*
enum | nullwaitingwhile the import is queued,activewhile it runs, and null when nothing is pending. How long a queued import waits depends on the queue, so only an active one is worth timing. - importing*
booleanWhether an import is queued or running right now, including a refresh of an inventory that is already
ready. - importRunningForMs*
number | nullHow long the active import has been running, in milliseconds, or null when none is. A duration rather than a start time, so it can be measured against the caller's own clock.
- lastUpdatedInventoryOn*
string | nullWhen the last import completed, ISO-8601, or null if none has.
- lastImportError*
string | nullWhy the most recent import attempt did not complete, or null. Meant to be shown, not parsed: the wording can change.
Queue an inventory import from Steam
/api/inventory/import/{steamId}Auth requiredQueues a refresh of the profile’s Steam inventory and returns at once. Poll GET /api/inventory/import-status/{steamId} until importing is false; a newer lastUpdatedInventoryOn means the import completed. Requires authentication. Throttled to once per hour per profile; force=true skips that hourly window but is honored only for the owner of the Steam id (or an admin) — other callers stay throttled. Even forced, one profile is queued at most once a minute, and a request made while an import for that profile is already queued or running answers queued: false with reason: "already-running" rather than adding a second one.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
| steamId | path | yes | 64-bit Steam id. |
| force | query | no | Owner/admin only: skip the 1-hour sync throttle and queue a fetch from Steam now. |
Request
curl -X POST "https://api.scmm.app/api/inventory/import/<steamId>?force=false" \
-H "x-api-key: YOUR_KEY_HERE"Response
- reason
enumWhy nothing was queued, present only when
queuedisfalse.already-running: an import for this profile is already queued or running, so poll for that one.too-soon: a forced import started less than a minute ago.fresh: the inventory was imported within the last hour andforcewas not honored for this caller.recently-attempted: an import was attempted within the last hour and did not complete. - queued*
booleantruewhen an import was queued for this profile. PollGET /api/inventory/import-status/{steamId}untilimportingisfalse; a newerlastUpdatedInventoryOnthere means the import completed.
Update purchase price or source for one item
/api/inventory/item/{itemId}Auth requiredRequires authentication, and answers 401 unless the item belongs to you (or you are an administrator). Absent fields are left unchanged; an explicit null clears one. Choosing a free acquisition source (gambling, gift, game drop) always clears the price.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
| itemId | path | yes | Steam asset id of the inventory item, as returned in itemId. |
Request body
- buyPrice
number | null - currency
string | null - acquiredBy
number
Request
curl -X PUT "https://api.scmm.app/api/inventory/item/<itemId>" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_KEY_HERE" \
-d '{"buyPrice":0}'Combine stacks of one item into another stack
/api/inventory/item/{itemId}/combineAuth requiredRequires authentication and your own Steam Web API key. Moves the given quantity of each source stack into the destination stack on Steam, one source at a time in body order, and returns the item’s stacks afterwards. A source that is not in your inventory is skipped. One request makes at most 25 changes and starts none after 45 seconds; unreached lists the source asset ids it did not reach, so send exactly those again, with the same quantities, until it is empty. Each change Steam confirms is saved even if a later source fails. Answers 400 when Steam refuses the change (its reason is in message), 401 when Steam rejects the key, 409 when another stack change is running for your inventory, 429 when Steam is rate-limiting the key, and 502 when Steam did not confirm a change; after a 502, queue a fresh import with POST /api/inventory/import/{steamId}?force=true and poll GET /api/inventory/import-status/{steamId} until importing is false before retrying, because the change may have happened. This request is not safe to retry automatically: a repeated request repeats the change, so turn off automatic retries for it in your HTTP client. Instead, after a timeout or a 502, import the inventory and read the stacks again before sending anything. Allow at least 60 seconds per request.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
| itemId | path | yes | Steam asset id of the destination stack. |
| steam-api-key | header | yes | Your own Steam Web API key, from https://steamcommunity.com/dev/apikey. It is used for this one request to Steam and is not stored. |
Request body
- *
map<string, integer>Each key is a source stack’s asset id (1 to 20 digits), not the destination; each value is the whole number of units to move from it, at least 1 and no more than that stack holds.
Request
curl -X PUT "https://api.scmm.app/api/inventory/item/<itemId>/combine" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_KEY_HERE" \
-H "steam-api-key: YOUR_STEAM_API_KEY" \
-d '{"<key>":1}'Response
- descriptionId*
string | nullThe item the stacks share, or null for an asset whose item could not be identified.
array<object>Every stack of the item in your inventory, largest first.
- remaining*
numberHow many source stacks were not reached: the length of
unreached. 0 when every source was attempted. - unreached*
array<string>Source asset ids this request did not reach, in the order it read them from the body. Send exactly these again, with the same quantities, until the list is empty.
Split a stack into new stacks
/api/inventory/item/{itemId}/splitAuth requiredRequires authentication and your own Steam Web API key. Moves quantity units out of the stack on Steam, into one new stack when stackNewItems is true (the default) or into single items when it is false, and returns the item’s stacks afterwards. quantity must be less than the stack holds. A split into single items makes at most 25 changes per request and starts none after 45 seconds; remaining says how many units are left, so repeat the request with that quantity until it is 0. Answers 400 when Steam refuses the change (its reason is in message), 401 when Steam rejects the key, 409 when another stack change is running for your inventory, 429 when Steam is rate-limiting the key, and 502 when Steam did not confirm a change; after a 502, queue a fresh import with POST /api/inventory/import/{steamId}?force=true and poll GET /api/inventory/import-status/{steamId} until importing is false before retrying, because the change may have happened. This request is not safe to retry automatically: a repeated request repeats the change, so turn off automatic retries for it in your HTTP client. Instead, after a timeout or a 502, import the inventory and read the stacks again before sending anything. Allow at least 60 seconds per request.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
| itemId | path | yes | Steam asset id of the stack to split. |
| steam-api-key | header | yes | Your own Steam Web API key, from https://steamcommunity.com/dev/apikey. It is used for this one request to Steam and is not stored. |
Request body
- quantity*
integerUnits to move out of the stack.
- stackNewItems
booleanWhether the moved units form one stack (true) or single items (false).
Request
curl -X PUT "https://api.scmm.app/api/inventory/item/<itemId>/split" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_KEY_HERE" \
-H "steam-api-key: YOUR_STEAM_API_KEY" \
-d '{"quantity":1}'Response
- descriptionId*
string | nullThe item the stacks share, or null for an asset whose item could not be identified.
array<object>Every stack of the item in your inventory, largest first.
- remaining*
numberUnits still to split. Repeat the request with this quantity until it is 0; always 0 when the units stack.
List your stacks of one inventory item
/api/inventory/item/{itemId}/stacksAuth requiredRequires authentication. Returns every stack of the same item in your own inventory, largest first, with its asset id, quantity and trade lock. Answers 404 for an asset id that is not in your inventory.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
| itemId | path | yes | Steam asset id of any one stack of the item, as returned in assetId. |
| profileId | query | no | Profile id or 64-bit Steam id whose stacks to list. Administrators only; anyone else naming another profile gets 404. Omit it for your own inventory. |
Request
curl "https://api.scmm.app/api/inventory/item/<itemId>/stacks" \
-H "x-api-key: YOUR_KEY_HERE"Response
- descriptionId*
string | nullThe item the stacks share, or null for an asset whose item could not be identified.
array<object>Every stack of the item in your inventory, largest first.
Highest-valued inventories, paginated and sortable
/api/inventory/leaderboardServes the top 500 inventories for the requested sort, not every inventory tracked. total is therefore capped at 500 and totalPages with it; pages beyond the cap return no entries. For the true, uncapped count of valued inventories use inventoriesTracked on GET /api/inventory/leaderboard/stats.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
| page | query | no | 1-based page index. Defaults to 1. Pages past the 500-row cap return no entries. |
| pageSize | query | no | Rows per page. Defaults to 50, max 100. |
| sort | query | no | Sort key. Defaults to value.One of: |
| dir | query | no | Sort direction. Defaults to desc.One of: |
Request
curl "https://api.scmm.app/api/inventory/leaderboard?page=1"Response
array<object>- page*
number - pageSize*
number - total*
numberRows the board serves, capped at 500. The uncapped number of valued inventories is
inventoriesTrackedonGET /api/inventory/leaderboard/stats. - totalPages*
numbertotaldivided bypageSize, rounded up, so it is capped withtotal. - currency*
stringAlways
USD:totalValueis not converted.
Inventory totals across every valued profile
/api/inventory/leaderboard/statsUncapped on purpose — this is the counterpart to the leaderboard's 500-row cap, and the only place the true number of valued inventories is published.
Request
curl "https://api.scmm.app/api/inventory/leaderboard/stats"Response
- inventoriesTracked*
numberEvery inventory with a market value, uncapped.
- totalItems*
numberItems across those inventories.
- totalMarketValue*
numberTheir combined market value, in USD hundredths.
- currency*
stringAlways
USD.
Item ids in the authenticated user’s own inventory
/api/inventory/owned/item-idsAuth requiredLightweight companion to the inventory list — hydrates the "Owned" badge across the app. Distinct ids only, no quantities and no ordering. Scoped to the resolved app, so a Rust session never reports a CS2 item.
Request
curl "https://api.scmm.app/api/inventory/owned/item-ids" \
-H "x-api-key: YOUR_KEY_HERE"Response
- *
array<string>