LayerHopDocsLaunch app (opens in a new tab)

Chains, tokens, prices and balances

Build chain and token pickers from every chain and token LayerHop routes, and show USD prices and wallet balances — endpoints, parameters, caching and SDK calls.

LayerHop serves the asset data a swap UI needs through five public endpoints: GET /v1/chains (the 70 chains its providers route), GET /v1/tokens and GET /v1/tokens/lookup (token search and metadata), GET /v1/prices (USD prices) and GET /v1/balances (a wallet's holdings). The LayerHop swap app uses the same calls.

Which endpoints are there?#

Endpoint Returns Server cache SDK
GET /v1/chains Every routable chain, popular first Registry refreshed every 6 h lh.chains()
GET /v1/tokens One chain's tokens, searchable and paged Token lists refreshed hourly lh.tokens({ chain, q, limit, cursor })
GET /v1/tokens/lookup One token by address or mint, even if unlisted 1 h lh.lookupToken(chain, address)
GET /v1/prices USD prices for up to 100 tokens 60 s lh.prices(ids)
GET /v1/balances A wallet's non-zero balances with USD values 20 s per address and chain lh.balances(address, chains?)

All five count toward your rate limit. Responses from /chains and /tokens are also cacheable by browsers and CDNs for 5 minutes.

How do I list chains?#

GET /v1/chains returns every chain at least one provider can quote from or to. The registry merges the chain lists of Relay, LI.FI, deBridge, KyberSwap, Mayan, 0x and Jupiter, refreshes every 6 hours, and falls back to a built-in snapshot when providers are unreachable. Popular chains (popular: true) come first, then the rest alphabetically.

TypeScript
const chains = await lh.chains();
const bera = chains.find((c) => c.slug === "berachain");
// { id: 80094, slug: "berachain", name: "Berachain", vm: "evm", nativeSymbol: "BERA", nativeDecimals: 18,
//   logoURI: "https://…", explorerTx: "https://berascan.com/tx/", explorerAddress: "https://berascan.com/address/",
//   providers: ["kyberswap", "lifi", "relay", "zerox"], popular: true }
Field Meaning
id EVM chain id, or 7565164 for Solana
slug Stable name such as base, hyperevm, robinhood
vm evm or svm
nativeSymbol, nativeDecimals The gas coin
explorerTx, explorerAddress Prefixes; append a hash or an address
providers Providers that route from or to the chain
popular Shown first in pickers

Use the id or the slug anywhere a chain is expected. Supported chains & tokens lists the current snapshot.

How do I search tokens?#

GET /v1/tokens lists and searches one chain's tokens. It merges LI.FI's token list (with prices), Jupiter's verified list on Solana and LayerHop's curated tokens.

Param Required Meaning
chain Yes Chain id or slug
q No Symbol or name, or an exact address / mint
limit No 1–200, default 50
cursor No nextCursor from the previous page
TypeScript
const { tokens, nextCursor } = await lh.tokens({ chain: "berachain", q: "HONEY", limit: 20 });

Results rank exact symbol matches first, then popular tokens (native coin, stablecoins, wrapped native, majors), then verified ones, then by liquidity. Page with cursor: nextCursor until nextCursor is null.

How do I handle a token that is on no list?#

A pasted address that no list knows can still be traded. Read it with GET /v1/tokens/lookup:

TypeScript
const token = await lh.lookupToken("base", "0x…");
if (!token.verified) showWarning(`${token.symbol} is not on any token list. Check the address.`);

Unknown EVM tokens are read on chain (symbol, name, decimals). Unknown Solana mints get their decimals from the mint account and their name from Jupiter. Both come back with verified: false, and with priceUsd when a price source knows the token.

Can I quote any token?#

Yes. GET /v1/quote accepts any chain from /v1/chains and any token address or mint. Symbols work as shortcuts for the curated tokens (USDC) and for each chain's native coin (ETH, BERA, SOL):

TypeScript
const { best } = await lh.quote({
  srcChain: "base", srcToken: "USDC", amount: "10000000",   // 10 USDC
  dstChain: "berachain", dstToken: "BERA",
  sender: evmAddress, recipient: evmAddress,
});

Each provider decides support from its own chain list, so quotes contains every provider that serves the pair. A symbol that is not on the curated list returns UNSUPPORTED_TOKEN; pass the address instead.

How do I get USD prices?#

GET /v1/prices takes ids, a comma-separated list of up to 100 chainId:address entries. Prices come from LI.FI for EVM chains and Jupiter for Solana, cached for 60 seconds. The response is keyed by the ids exactly as you sent them; ids without a price are left out.

TypeScript
const prices = await lh.prices([
  "8453:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
  { chainId: 7565164, address: "So11111111111111111111111111111111111111112" },
]);
// { "8453:0x8335…2913": <usd>, "7565164:So11…112": <usd> }: keys as sent, values are USD numbers

How do I read a wallet's balances?#

GET /v1/balances returns a wallet's non-zero balances with token metadata, priceUsd and valueUsd, highest value first, plus totalUsd.

Param Required Meaning
address Yes An EVM address or a Solana address
chains No Comma-separated ids or slugs. Default: the popular chains of the address's VM
TypeScript
const { balances, totalUsd, errors } = await lh.balances("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", ["base", "arbitrum", "berachain"]);
  • EVM chains report the native coin plus the top 200 popular and verified tokens of each chain (one Multicall3 read per chain). Solana reports SOL and every token account.
  • A chain that fails or times out is listed in errors; the other chains are still returned.
  • Results are cached for 20 seconds per address and chain. Amounts are integer strings in base units.

Last updated