Skip to main content
There is no dedicated /assets endpoint. The list of assets listed on Gains is the pairs array of the chain-specific trading backend, and everything needed to describe an asset (asset class, leverage bounds, spread, listing status) comes from the same payload. You do not need the whole payload for this. /trading-variables/<keys> returns only the keys you ask for.

Endpoint

Sizes measured on Arbitrum in August 2026. No authentication is required. Rate limits apply, so cache the result rather than fetching it per user action.

Networks

Same path on every trading backend:
  • Arbitrum: https://backend-arbitrum.gains.trade
  • Base: https://backend-base.gains.trade
  • Polygon: https://backend-polygon.gains.trade
  • MegaETH: https://backend-megaeth.gains.trade
  • Arbitrum Sepolia (testnet): https://backend-sepolia.gains.trade
Each network serves its own list. Pair indexes have matched across networks so far, but the set of tradeable assets does not: treat each network’s own payload as authoritative instead of reusing another network’s list.
Only the keys returned by GET /trading-variables-keys are selectable. An unrecognized key is silently ignored, and a request where every key is unrecognized returns the full payload. GET /trading-variables/isForexOpen returns 2.7 MB, not one boolean.

Response

Every numeric field is fixed-precision. pairs and groups serialize theirs as strings, pairInfos.maxLeverages as numbers, so parse both sides with Number(): pairs[].groupIndex indexes groups, and pairs[].feeIndex indexes the fees array (request the fees key if you need fee parameters).

Pair index

The pair index is the array position. It is not a field on the object. Every other surface keys off it: pairIndex on trades and orders, /api/holding-rates/{collateralIndex}/{pairIndex}, and the closes[pairIndex] array of the price feed. Read the index before you sort or filter, and never renumber the array. The array is append-only. Delisted assets keep their slot forever, so the raw list is a history of everything ever listed, not the current offering.

Filtering out delisted assets

An asset is currently tradeable when its effective max leverage is at least its group min leverage. This is the same rule the SDK applies in getMarketLeverageRestrictions:
  1. effectiveMax = maxLeverages[pairIndex] === 0 ? group.maxLeverage : maxLeverages[pairIndex]
  2. the asset is delisted when effectiveMax < group.minLeverage
Delisting is expressed by setting the pair override far below the group minimum, so a delisted asset stays in the array with a maxLeverages entry such as 1 (0.001x). In August 2026 this filter kept 180 of the 490 entries served by the Arbitrum backend.

Example

The same list from the shell:
transformGlobalTradingVariables from @gainsnetwork/sdk does the precision conversion and index assignment for you, and returns pairs[].pairIndex already populated. Use it when you already depend on the SDK.

Ticker suffixes

A from value can carry a numeric suffix, such as GOOGL_1. That happens when an asset is listed again in a new slot while its original slot stays in the array as delisted. Strip the suffix for display, and keep the raw value when matching against backend data.

Asset classes

groups[].name is the asset class: crypto, altcoins, crypto-degen, forex, forex-minor, forex-exotic, stocks-1 to stocks-3, indices, commodities-1 and commodities-2. Numbered suffixes are risk buckets with their own leverage and fee parameters, not separate asset classes. Strip the suffix to get the user-facing class.

Market hours

Assets outside crypto only trade while their market is open. The flags isForexOpen, isStocksOpen, isIndicesOpen, and isCommoditiesOpen are part of the full payload and are not selectable keys, so read them from GET /trading-variables.

Keeping the list fresh

Listings change rarely, but the payload is refreshed continuously and carries lastRefreshed and refreshId. Cache the derived asset list and refresh it on the tradingVariables WebSocket event described in Backend, or poll every few minutes.