Skip to main content
Costs come back in two arrays, gasCosts and feeCosts. They answer different questions, they are denominated differently, and neither one maps cleanly onto “what the user pays on each chain”. This guide explains how to read both so you can show your users an accurate cost breakdown.

Where the cost arrays live

Both arrays hang off an estimate object, and estimate belongs to a step. Not every response hands you a step directly. A route is an envelope around its steps and has no estimate of its own. Reading route.estimate gives you undefined. The only cost figure a route carries at the top level is gasCostUSD, a single aggregate string.
Both arrays are optional. A step can come back with neither, or with an empty array, and that is a valid quote rather than a quoting failure. Guard every read before you index into one.

gasCosts or feeCosts?

The split is about who submits a transaction, not about what the money is for. A cost being for gas does not put it in gasCosts. A bridge that pays for destination-chain execution and bills the user for it reports that as a feeCosts entry, because the user never signs a destination transaction.

Reading a gas cost

price is in the smallest unit of the gas token per unit of gas, so wei per gas on EVM chains, not gwei. For EVM entries, amount is estimate * price, and limit is estimate plus a buffer. Other ecosystems may apply chain-specific units and rounding, so treat the returned amount as authoritative rather than reconstructing it. When constructing an EVM transaction from these fields, use limit, not estimate.

Gas cost types

GasCost.type is typed as one of four values, but only one of them is in production use.
Handle APPROVE, FEE, and SUM if they appear, so your integration stays forward-compatible, but don’t build a flow that depends on them. If you need the gas cost of an approval today, estimate it yourself against approvalAddress.

Which chain does a cost belong to?

token.chainId tells you the chain of the token a cost is denominated in. It does not tell you where the underlying work happens. For gasCosts the two coincide: gas is paid in the native token of the chain that consumes it, so token.chainId is the execution chain. For feeCosts they often differ. In this quote, 50 USDC on Ethereum is sent to cbBTC on Base:
The fee covers execution on Base, but it is charged in Ethereum USDC because that is the token the user is already sending. Reading chainId: 1 as “this is a source-chain cost” is the mistake to avoid.
Do not derive a per-chain cost breakdown from token.chainId. If your UI needs to say “you pay X on the source chain and Y on the destination chain”, you cannot build that reliably from the quote alone.

Where destination execution cost shows up

LI.FI does not guarantee a separate source-chain and destination-chain gas item. Depending on the tool, the cost of executing on the destination chain reaches you in one of three ways:
  • As a feeCosts entry, typically named something like Relayer Gas fee or Network fee, denominated in the source-chain token. This is the most common case.
  • As tool-specific data, for example a destinationGasConsumption value inside estimate.data. The shape varies by tool.
  • Priced into the output, with no separate line item. The quoted toAmount is already net of it.
Fee names are tool-specific free text and are not a stable enum. Relayer Gas fee, Relayer gas fee, and Network fee all exist across different tools. Display name and description to users, but never branch on them.

Does the user need native gas?

The answer depends on who broadcasts the source transaction, so start from the execution mode you integrated. Destination-chain native gas is normally not needed in either mode. LI.FI or the bridge executes on the destination side, and any cost reaches you through feeCosts or is priced into toAmount. Gasless availability is determined at quote time. It currently requires an EVM source chain and an EIP-7702 delegated account that LI.FI supports; not every chain, delegate, or account type is eligible. See Gasless Transactions for the current requirements and execution flow. If your integration self-submits, check the native balance on the source chain against gasCosts[].amount before letting a user sign. A user with enough USDC but no ETH will fail at submission, not at quoting. If you relay, that check does not apply to the user, and a gasCosts entry describes what the relayer spends rather than what the user must hold. See Permit and Permit2 Approval Flow for the signature the legacy relayed path expects. The destination case has one exception worth planning for: your user lands on a new chain with the bridged token and no native balance, so they can’t do anything next. That is a cold-start problem, not an execution problem, and LI.Fuel solves it.

LI.Fuel is not execution gas

fromAmountForGas converts part of the sent amount into the destination chain’s native token and delivers it to the user alongside the bridged asset. It exists so the user has gas for their next action. Keep the two separate when you build a cost breakdown:
  • Execution gas is what it costs to complete this transfer. It shows up in gasCosts and feeCosts.
  • LI.Fuel is an extra amount the user asked to receive as native token. It reduces toAmount, and it is not a cost of the transfer.
See Gas Fronting for the request parameter and its limitations.

The included flag

included decides whether a fee is already reflected in the quoted amounts.
  • included: true means the fee is already accounted for. The quoted toAmount is net of it. Show it in a breakdown, but do not add it again as a separate user payment.
  • included: false means the user pays it on top of fromAmount.
Adding an included: true fee back on top is the most common way integrations end up overstating cost to their users.

Don’t add the top-level and step-level arrays together

A lifi step carries its own estimate.feeCosts and estimate.gasCosts, and each entry in includedSteps carries its own. The top-level arrays are derived from the step-level ones, so summing both double counts. They are derived differently, which matters:
  • feeCosts at the top level is the concatenation of every included step’s fee costs. Same entries, same amounts.
  • gasCosts at the top level is a single estimate for the transaction that is actually submitted. It aggregates raw gas costs from included steps on the source chain and, for EVM transactions, adds estimated LI.FI contract overhead. It may therefore differ from—and often exceed—the sum of the source-chain per-step entries. Raw gas costs from destination-chain included steps are not added directly.
For the 50 USDC quote above: In this example the fee columns match and the gas columns do not, because the top-level figure covers the single transaction the user actually submits, including LI.FI contract overhead.
Use the top-level estimate arrays for anything you show the user or charge against. Treat includedSteps costs as a breakdown for debugging and display, never as additional amounts to sum.

Next Steps

Gas Fronting

Deliver destination-chain native token to your users with fromAmountForGas.

Fees and monetization

How integrator fees are configured and collected.

Quote API reference

The full response shape, including estimate, feeCosts, and gasCosts.

Route and quote differences

When to call /quote and when to call /advanced/routes.