> ## Documentation Index
> Fetch the complete documentation index at: https://docs.li.fi/llms.txt
> Use this file to discover all available pages before exploring further.

# Deposit with a server-planned route

> Compile a token pair into a deposit with sdk.route: the server plans up to two hops, swap included, and returns the same compile result as a Flow.

## Scenario

A user holds 1,000 USDT on Ethereum and wants Aave USDC (`aEthUSDC`). No single routing edge turns USDT into aEthUSDC, so the route takes two hops: swap USDT to USDC, then deposit the USDC into Aave.

`sdk.route` (`POST /compose/route`) plans those hops for you. You pass the token pair, an amount and a signer; the server builds the route, compiles it and returns the same `ComposeCompileResult` as `builder.compile()`. It plans up to two hops on one chain, and a [`lifi.swap`](https://docs.li.fi/composer/composer-api/ops/lifi-swap) can only be the first hop. The other hops are [`lifi.zap`](https://docs.li.fi/composer/composer-api/ops/lifi-zap) catalog edges: a protocol deposit or withdrawal, a wrap or unwrap. For a longer route, a route you choose yourself, or guards on intermediate outputs, author a Flow as in [Swap and deposit](https://docs.li.fi/composer/composer-api/recipes/swap-and-deposit.md).

## Full example

Install the SDK and viem with `npm install @lifi/composer-sdk @lifi/compose-spec viem` and set `LIFI_API_KEY`; see [Before you start](https://docs.li.fi/composer/composer-api/overview.md#before-you-start). The example also signs with a private key: set `PRIVATE_KEY` on your server and never ship it to a browser.

```ts theme={"system"}
import {
  createComposeSdk,
  routeAmount,
  terminalOutputs,
} from '@lifi/composer-sdk';
import { createPublicClient, createWalletClient, http, type Hex } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { mainnet } from 'viem/chains';

// Ethereum mainnet (chainId 1).
const USDT = '0xdAC17F958D2ee523a2206206994597C13D831ec7';
// Aave V3 aEthUSDC receipt token
const A_ETH_USDC = '0x98C23E9d8f34FEFb1B7BD6a91B7FF122F4e16F5c';

const account = privateKeyToAccount(process.env.PRIVATE_KEY as Hex);
const wallet = createWalletClient({ account, chain: mainnet, transport: http() });
const client = createPublicClient({ chain: mainnet, transport: http() });

const sdk = createComposeSdk({
  baseUrl: 'https://composer.li.quest',
  apiKey: process.env.LIFI_API_KEY!,
});

// Throws a ComposeError with kind 'no_route_error' when no route exists.
const result = await sdk.route({
  chainId: 1,
  fromToken: USDT,
  toToken: A_ETH_USDC,
  amount: routeAmount.exact(1_000_000_000n), // 1,000 USDT (6 decimals)
  signer: account.address,
  // Required when the route opens with a swap: receives the swap's unspent input.
  sweepTo: { $ref: 'context.sender' },
  slippageBps: 100, // 1% end-to-end floor on the final output
  checkOnChainAllowances: true, // skip the approval if the allowance already covers it
});

const delivered = terminalOutputs(result.outputs)['zap.amountOut'];
console.log('Expected aEthUSDC:', delivered?.amount.estimate?.value);
console.log('Floor aEthUSDC:', delivered?.amount.minimum?.value);

for (const action of result.actions ?? []) {
  if (action.kind !== 'transaction') continue;
  const tx = action.transactionRequest;
  const hash = await wallet.sendTransaction({
    to: tx.to as Hex,
    data: tx.data as Hex,
    value: BigInt(tx.value),
    ...(tx.gasLimit ? { gas: BigInt(tx.gasLimit) } : {}),
  });
  const receipt = await client.waitForTransactionReceipt({ hash });
  console.log(action.purpose, hash, receipt.status);
}
```

## Run it

Save the file as `server-planned-route.mts` and run `node server-planned-route.mts`.

> [!WARNING]
>
> It sends real transactions on Ethereum: the USDT approval (unless the allowance already covers it), then `execute`, in [`result.actions` order](https://docs.li.fi/composer/composer-api/concepts/execution-model#the-compile-response).

## What to check

* The node ids follow a fixed pattern: `hop0`, `hop1`, … and a last node named `zap`. The server does not return the Flow it built.
* `outputs['hop0.amountOut']` is the swap's USDC, with `role: 'consumed'` and `consumedBy: 'zap'`. Its floor comes from the swap quote.
* `outputs['zap.amountOut']` is the aEthUSDC the signer receives: `role: 'terminal'`, `delivery: { when: 'now' }`. `amount.estimate` is simulated; `amount.minimum` (`basis: 'guard'`) is 1% below it. Read this key at any route length.
* `epilogue.remainder` is the `sweepTo` address, which receives any leftover USDT or USDC.
* The `execute` transaction is atomic: if the aEthUSDC would fall below the floor, it reverts and the USDT stays with the signer.

## Request fields

The SDK serialises `bigint` amounts to decimal strings on the wire. [`sdk.route(request)`](https://docs.li.fi/composer/composer-api/reference/sdk-api) lists the TypeScript types.

| Field | Required | Meaning |
| - | - | - |
| `chainId` | yes | The chain both tokens live on. `GET /chains` lists the supported ones. |
| `fromToken` | yes | Token to spend. Use `0x0000000000000000000000000000000000000000` for the native gas coin. |
| `toToken` | yes | Token to receive: a position token, a wrapped token, or any other edge output. |
| `amount` | yes | In the token's smallest unit. `routeAmount.exact(amount)` (`{ type: 'EXACT', amount }`) spends that amount. `routeAmount.all(simAmount)` (`{ type: 'ALL', simAmount }`) spends the signer's whole balance at execution and quotes against `simAmount`, so pass a realistic estimate. `ALL` rejects a native `fromToken` with `validation_error`. On a swap-headed route, `ALL` fixes the swap input to the quoted amount: a smaller balance reverts, and a larger one leaves the surplus as `unspentIn` for `sweepTo`. [`routeTokenPair.ts`](https://github.com/lifinance/composer-sdk-examples/blob/main/examples/routeTokenPair.ts) shows both forms. |
| `signer` | yes | The address that funds the route and signs its transactions. |
| `sweepTo` | with a swap | Owner of everything the route leaves behind: an address or `{ $ref: 'context.sender' }`. Required when the route opens with a swap; otherwise it defaults to `signer`. |
| `slippageBps` | no | Tolerance on the simulated final output, 0 to 10000. Default `100` (1%). It is not applied hop by hop. When the route opens with a swap, it is also the swap's own tolerance. |
| `maxPriceImpactBps` | no | Reject the route when its priced impact exceeds this. Default `500`; `0` disables the check. |
| `allowAsyncRoutes` | no | Accept a route whose output arrives after the transaction settles (`delivery.when: 'future'`). Default `false`. Such a route carries no `slippageBps` floor. |
| `referrer` | no | Attribution tag forwarded to LI.FI as the quote's `integrator`. Must match `^[A-Za-z0-9._-]{1,23}$`; a blank value sends none. |
| `checkOnChainAllowances`, `simulationPolicy`, `simulateUserProgram` | no | As on a Flow compile. Under `simulationPolicy: 'allow-revert'`, a simulated revert returns `status: 'partial'` (HTTP 206) instead of an error. |

To check which pairs the catalog connects before calling the server, pass `await sdk.client.getZapPacks()` to `buildReachability`. It does not report swap-headed routes, so USDT to aEthUSDC shows as unreachable there; see the [SDK reference](https://docs.li.fi/composer/composer-api/reference/sdk-api.md).

## Errors

* **`no_route_error` (HTTP 404, SDK code `NOT_FOUND`):** no route within the hop limit. The details carry `maxHops` and `searchTruncated`. A plain token-to-token swap, such as USDC to UNI, fails this way: use [`lifi.swap`](https://docs.li.fi/composer/composer-api/ops/lifi-swap).
* **`validation_error` (HTTP 400) "sweepTo is required":** the pair needs a swap and the request has no `sweepTo`.

For other failures, see [Error codes](https://docs.li.fi/composer/composer-api/reference/error-codes.md).

## Related

* [Swap and deposit](https://docs.li.fi/composer/composer-api/recipes/swap-and-deposit.md): the same deposit with steps you pick.
* [`lifi.zap`](https://docs.li.fi/composer/composer-api/ops/lifi-zap): the catalog edges a route can use.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.