Skip to Content
Symmio Trading-SDK — the SDK surface for builders on Arbitrum
CorePoolsgetListingMarkets

getListingMarkets

Fetch a page of the permissionless-listing market catalog — the data behind a pools list. Every parameter is optional: with none set the backend returns its default first page of 20 rows.

import { getListingMarkets, ListingMarketStatus } from "@symmio/trading-core"; const page = await getListingMarkets(config, { marketStatus: ListingMarketStatus.LISTED, sortBy: "tvl", orderBy: "desc", limit: 50, });

The catalog spans every listing the backend knows about, at every lifecycle stage — including markets that are still awaiting a deposit, under review, rejected, or delisted. Pass marketStatus: ListingMarketStatus.LISTED to see only tradable ones. Rows come back newest-listed first unless sortBy is set.

The two halves of the signature are exported as GetListingMarketsParameters (the parameters object, every field optional) and GetListingMarketsReturnType (an alias of ListingMarketPage), so you can name them in your own wrappers:

import type { GetListingMarketsParameters, GetListingMarketsReturnType } from "@symmio/trading-core"; function listedOnly(parameters: GetListingMarketsParameters): Promise<GetListingMarketsReturnType> { return getListingMarkets(config, { ...parameters, marketStatus: ListingMarketStatus.LISTED }); }

This is a REST read against the listing backend, not a contract call. The backend is resolved from the config before the request, so a target without Pools fails immediately and without any network traffic — see resolveListingService.

Parameters

chainIdnumberoptional

Target chain id. Defaults to the config’s defaultChainId. Selects which chain’s listing backend is used, and is folded into the query key.

searchstringoptional

Free-text search, matched by the backend against contract address, ticker, and token name. Named search rather than query because the TanStack options bag on the matching query factory already owns query; it is sent as query on the wire.

chainIdsreadonly ListingDepositChainId[]optional

Restrict to tokens deposited on these chains. An empty array is sent as no filter, matching the backend’s behavior for an absent parameter. The SDK serializes this as repeated keys (chain_ids=56&chain_ids=8453), which is the only form the backend honors.

marketStatusListingMarketStatusoptional

Restrict to one lifecycle status. Exactly one — the backend takes a single status, not a set.

limitnumberdefault service 20optional

Page size, 1100. Omitted entirely when unset, so the backend applies its own default of 20.

offsetnumberdefault service 0optional

Row offset. Combine with total from the response to page.

sortByListingMarketSortFieldoptional

Server-side sort key, as a wire literal in snake_case rather than the SDK’s camelCase field names. See Sort keys.

orderBy"asc" | "desc"default "desc"optional

Sort direction, applied to sortBy. Service default "desc". Its effect without a sortBy is not specified by the backend — pair it with an explicit sort key.

filtersListingMarketFiltersoptional

Inclusive numeric range filters, applied server-side. Bounds are at 18 decimals, not human units — see Filters.

Unset parameters are omitted from the request rather than sent empty, which is what lets the backend apply its own defaults.

Sort keys

sortBy mirrors the backend’s sort_by enum verbatim. Translating it into the SDK’s camelCase would break silently the moment the backend adds a key, so the wire literal is the public type:

sortBySorts by
"liquidity"liquidity
"tvl"tvl
"market_cap"marketCap
"vol24h"vol24h
"open_interest"openInterest
"reward_24h"reward24h
"apr"apr
"apr_1h"aprByWindow.h1
"apr_6h"aprByWindow.h6
"apr_24h"aprByWindow.h24
"apr_30d"aprByWindow.d30
"tvl_driven_apy_1h"tvlDrivenApy.h1
"tvl_driven_apy_6h"tvlDrivenApy.h6
"tvl_driven_apy_24h"tvlDrivenApy.h24
"tvl_driven_apy_30d"tvlDrivenApy.d30
"tvl_driven_apy"tvlDrivenApy.lifetime
"price_driven_apy_1h"priceDrivenApy.h1
"price_driven_apy_6h"priceDrivenApy.h6
"price_driven_apy_24h"priceDrivenApy.h24
"price_driven_apy_30d"priceDrivenApy.d30
"price_driven_apy"priceDrivenApy.lifetime
"listing_time"listingTime

"tvl_driven_apy" and "price_driven_apy" are the two odd keys: they are bare, but there is no bare response field to match them — the backend only reports those series per window plus a lifetime column. They are documented here as sorting by the lifetime column (tvl_driven_apy_lifetime / price_driven_apy_lifetime). That mapping is an unconfirmed vendor assumption, not something the backend’s schema states. If the ordering matters to your UI, sort by an explicit window key instead.

Filters

filters is a bag of inclusive [min, max] bounds; every key is optional and either end may be omitted for a one-sided bound. Each becomes a {field}__ge / {field}__le query parameter.

Bounds use the same 18-decimal scale as the response, not the human-readable figure. A one-million-USD market-cap floor is 1_000_000n * 10n ** 18n. Passing 1_000_000 is a bound of 0.000000000001 USD, which matches essentially everything and looks like a filter that does nothing. listingTime is the one exception — it takes Unix seconds.

Money and rate keys (ListingValueRange, min / max as bigint at 18 decimals):

marketCapListingValueRangeoptional

Token market capitalization, USD.

vol24hListingValueRangeoptional

Trailing 24-hour volume, USD.

tvlListingValueRangeoptional

Total value locked, USD.

liquidityListingValueRangeoptional

Available notional, USD.

openInterestListingValueRangeoptional

Open notional, USD.

reward24hListingValueRangeoptional

Trailing 24-hour LP rewards, USD.

aprListingValueRangeoptional

Headline APR bounds, at the field’s own scale (1e18 = 1%).

apr1hListingValueRangeoptional

APR over the trailing hour.

apr6hListingValueRangeoptional

APR over the trailing 6 hours.

apr24hListingValueRangeoptional

APR over the trailing 24 hours.

apr30dListingValueRangeoptional

APR over the trailing 30 days.

tvlDrivenApy1hListingValueRangeoptional

TVL-driven APY over the trailing hour.

tvlDrivenApy6hListingValueRangeoptional

TVL-driven APY over the trailing 6 hours.

tvlDrivenApy24hListingValueRangeoptional

TVL-driven APY over the trailing 24 hours.

tvlDrivenApy30dListingValueRangeoptional

TVL-driven APY over the trailing 30 days.

tvlDrivenApyListingValueRangeoptional

TVL-driven APY over the market’s lifetime.

priceDrivenApy1hListingValueRangeoptional

Price-driven APY over the trailing hour.

priceDrivenApy6hListingValueRangeoptional

Price-driven APY over the trailing 6 hours.

priceDrivenApy24hListingValueRangeoptional

Price-driven APY over the trailing 24 hours.

priceDrivenApy30dListingValueRangeoptional

Price-driven APY over the trailing 30 days.

priceDrivenApyListingValueRangeoptional

Price-driven APY over the market’s lifetime.

The timestamp key (ListingTimeRange, min / max as number in Unix seconds):

listingTimeListingTimeRangeoptional

Listing timestamp bounds, Unix seconds. Not 18-decimal scaled and not milliseconds.

Returns

totalnumber

Total rows matching the query across all pages — what you page against.

limitnumber

Page size the backend actually applied.

offsetnumber

Row offset of this page.

itemsListingMarket[]

The rows themselves. See ListingMarket.

Every envelope field is defaulted on the way through — counts to 0, items to an empty array — because the backend declares them as defaulted rather than required.

Examples

The default first page

const page = await getListingMarkets(config); page.total; // every listing the backend knows about page.items.length; // at most 20 — the backend's default page size

Tradable markets, deepest pools first

import { getListingMarkets, ListingMarketStatus } from "@symmio/trading-core"; const page = await getListingMarkets(config, { marketStatus: ListingMarketStatus.LISTED, sortBy: "tvl", orderBy: "desc", limit: 25, offset: pageIndex * 25, });

A filter with an 18-decimal bound

Market cap of at least $1M, and a headline APR of at least 10% (10 * 1e18, because a rate is already a percentage):

import { getListingMarkets, LISTING_VALUE_DECIMALS, ListingMarketStatus } from "@symmio/trading-core"; const ONE = 10n ** BigInt(LISTING_VALUE_DECIMALS); const page = await getListingMarkets(config, { marketStatus: ListingMarketStatus.LISTED, filters: { marketCap: { min: 1_000_000n * ONE }, apr: { min: 10n * ONE }, }, sortBy: "apr", });

Solana-deposited tokens only

chainIds filters on the chain the token was deposited from, not the chain the market trades on:

import { getListingMarkets, ListingDepositChainId } from "@symmio/trading-core"; const page = await getListingMarkets(config, { chainIds: [ListingDepositChainId.SOLANA], search: "bonk", }); // Rows on this chain carry a base58 `contractAddress`, not a 0x address.

Query options

import { getListingMarketsQueryOptions } from "@symmio/trading-core"; import { useQuery } from "@tanstack/react-query"; useQuery(getListingMarketsQueryOptions(config, { sortBy: "tvl", limit: 50 }));

GetListingMarketsOptions is the action’s parameters plus a query bag of TanStack overrides — which is exactly why the free-text parameter is called search. The factory folds config.getChainConfigKey(chainId) into the key, so a runtime config override pointed at a different listing deployment refetches instead of serving the previous one’s cache. getListingMarketsQueryKey builds the same key for cache matching and invalidation.

The rest of the factory’s types are exported too: GetListingMarketsData is what the query resolves to (the same ListingMarketPage), GetListingMarketsQueryKey is the key getListingMarketsQueryKey returns, and GetListingMarketsQueryOptions is the options bag the factory produces.

Because search, filtering, sorting and paging are all server-side, each distinct combination is its own cache entry — change one and the hook refetches rather than re-slicing a page you already hold.

Throws

  • LISTING_NOT_CONFIGURED — a SymmError (kind: "config") when the chain has no listing backend configured. Gate with supportsListingService to hide Pools instead of erroring.
  • FETCH_LISTING_MARKETS_FAILED — the request itself failed. Any axios failure — including a transport error with no response, which arrives with status: 0 and statusText: "Unknown" — becomes a SymmApiError carrying status, statusText, responseData, url and method. A non-axios throw becomes a plain SymmError (kind: "api"), with the original error as its cause when it was an Error.
Last updated on