> ## 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.

# API Integration

> Integrate LI.FI Composer via the REST API with same-chain deposits, cross-chain flows, and error handling.

<Note>
  **倾向于显式编写多步 flow？** 参见 [Composer API](/composer/composer-api/overview)，它记录了显式的 Flow 编写 API。
</Note>

本指南带你直接通过 LI.FI REST API 集成 Composer。这种方式让你对请求/响应流程拥有完全控制，非常适合后端服务、自定义前端，或任何你希望自行管理交易的环境。

<Note>
  **已经在使用 LI.FI SDK 或 Widget？** Composer 会自动生效。请改为参见 [SDK 指南](/composer/lifi-api/guides/sdk-integration)或 [Widget 指南](/composer/lifi-api/guides/widget-integration)。
</Note>

***

## Authentication

LI.FI API 是开放的，无需 API key。你可以立即开始发起请求。

* **`integrator`**（可选查询参数）：一个在分析与链上事件中标识你应用的字符串。省略时默认为 `"lifi-api"`。必须为字母数字，可含连字符、下划线或点，最长 23 个字符。
* **`x-lifi-api-key`**（可选头）：当你在 [LI.FI 合作伙伴门户](https://portal.li.fi/)中创建集成时会自动生成一个 API key。附上它可获得更高的速率限制。没有 key 时，适用未认证限制：`/quote` 与 `/advanced/routes` 每两小时 75 次请求，`/advanced/stepTransaction` 每两小时 50 次请求，其他端点每分钟 100 次请求。有 API key 时，所有端点默认为每分钟 100 次请求。

完整细节参见 [Authentication](/api-reference/authentication)。

***

## Overview

Composer 不需要专用端点。将 `toToken` 设置为受支持的协议代币地址，LI.FI 便会从标准端点返回一条 Composer 路由。

集成流程：

1. **请求报价**，通过 `GET /v1/quote` 或 `POST /v1/advanced/routes`
2. **设置代币授权**，即授权 LI.FI Diamond 合约花费你的代币
3. **发送交易**，使用报价响应中的 `transactionRequest`
4. **跟踪状态**，对跨链转移轮询 `GET /v1/status`

***

## Request a Composer Quote

### Using `GET /quote` (Recommended)

获取 Composer 交易的最简单方式。返回单个最优路由，并包含交易数据。

<CodeGroup>
  ```bash curl theme={"system"}
  curl -X GET 'https://li.quest/v1/quote?fromChain=8453&toChain=8453&fromToken=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913&toToken=0x7BfA7C4f149E7415b73bdeDfe609237e29CBF34A&fromAddress=0xYOUR_WALLET_ADDRESS&toAddress=0xYOUR_WALLET_ADDRESS&fromAmount=1000000'
  ```

  ```ts TypeScript theme={"system"}
  import axios from 'axios';

  const getQuote = async (params: {
    fromChain: number;
    toChain: number;
    fromToken: string;
    toToken: string;
    fromAmount: string;
    fromAddress: string;
    slippage?: number;
    integrator?: string;
  }) => {
    const result = await axios.get('https://li.quest/v1/quote', {
      params: {
        ...params,
        toAddress: params.fromAddress,
      },
    });
    return result.data;
  };

  const quote = await getQuote({
    fromChain: 8453,                                              // Base
    toChain: 8453,                                                // Base (same-chain)
    fromToken: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',     // USDC on Base
    toToken: '0x7BfA7C4f149E7415b73bdeDfe609237e29CBF34A',       // Morpho vault token
    fromAmount: '1000000',                                        // 1 USDC (6 decimals)
    fromAddress: '0xYOUR_WALLET_ADDRESS',
    slippage: 0.005,                                              // 0.5% slippage tolerance
    integrator: 'your-app-name',
  });
  ```

  ```python Python theme={"system"}
  import requests

  response = requests.get('https://li.quest/v1/quote', params={
      'fromChain': 8453,
      'toChain': 8453,
      'fromToken': '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
      'toToken': '0x7BfA7C4f149E7415b73bdeDfe609237e29CBF34A',
      'fromAmount': '1000000',
      'fromAddress': '0xYOUR_WALLET_ADDRESS',
      'toAddress': '0xYOUR_WALLET_ADDRESS',
      'slippage': 0.005,
      'integrator': 'your-app-name',
  })

  quote = response.json()
  ```
</CodeGroup>

### Slippage

`slippage` 参数是一个小数值，表示可接受的最大价格差异。例如，`0.005` 表示 0.5%。若省略，API 默认为 `0.005`。跨链路由涉及更多步骤，因此对跨链 flow 可考虑 `0.01`（1%）或更高。

| Value   | Meaning  |
| ------- | -------- |
| `0.005` | 0.5%（默认） |
| `0.01`  | 1%       |
| `0.03`  | 3%       |

### Using `POST /advanced/routes`

返回多个路由选项。当你想向用户呈现选择，或需要对路由选择有更多控制时很有用。

<CodeGroup>
  ```ts TypeScript theme={"system"}
  const getRoutes = async (params: {
    fromChainId: number;
    toChainId: number;
    fromTokenAddress: string;
    toTokenAddress: string;
    fromAmount: string;
    fromAddress: string;
  }) => {
    const result = await axios.post('https://li.quest/v1/advanced/routes', {
      ...params,
      toAddress: params.fromAddress,
    });
    return result.data;
  };

  const routesResponse = await getRoutes({
    fromChainId: 8453,
    toChainId: 8453,
    fromTokenAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
    toTokenAddress: '0x7BfA7C4f149E7415b73bdeDfe609237e29CBF34A',
    fromAmount: '1000000',
    fromAddress: '0xYOUR_WALLET_ADDRESS',
  });

  // Select the best route
  const route = routesResponse.routes[0];
  ```
</CodeGroup>

<Note>
  使用 `/advanced/routes` 时，交易数据**不**包含在响应中。你必须调用 `POST /v1/advanced/stepTransaction` 来为每个步骤获取 `transactionRequest`。使用 `/quote` 时，交易数据直接包含在内。
</Note>

#### Getting transaction data for a route step

```ts TypeScript theme={"system"}
const getStepTransaction = async (step: any) => {
  const result = await axios.post('https://li.quest/v1/advanced/stepTransaction', step);
  return result.data;
};

const route = routesResponse.routes[0];
const stepWithTx = await getStepTransaction(route.steps[0]);
// stepWithTx.transactionRequest now contains the ready-to-sign transaction
```

如需详细对比，参见 [Difference between Quote and Route](/introduction/user-flows-and-examples/difference-between-quote-and-route)。

***

## Quote Response Structure

Composer 报价响应包含路由细节、预估输出以及一笔可直接签名的交易。以下是关键字段：

<Expandable title="Example response (annotated)">
  ```json theme={"system"}
  {
    "id": "0x...",
    "type": "lifi",
    "tool": "composer",
    "toolDetails": {
      "key": "composer",
      "name": "Composer",
      "logoURI": "https://..."
    },
    "action": {
      "fromToken": {
        "address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
        "symbol": "USDC",
        "decimals": 6,
        "chainId": 8453
      },
      "toToken": {
        "address": "0x7BfA7C4f149E7415b73bdeDfe609237e29CBF34A",
        "symbol": "sparkUSDC",
        "decimals": 18,
        "chainId": 8453
      },
      "fromAmount": "1000000",
      "fromChainId": 8453,
      "toChainId": 8453,
      "slippage": 0.005
    },
    "estimate": {
      "toAmount": "946832715862427",
      "toAmountMin": "942098552283115",
      "approvalAddress": "0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE",
      "executionDuration": 0,
      "feeCosts": [...],
      "gasCosts": [...]
    },
    "integrator": "lifi-api",
    "transactionRequest": {
      "to": "0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE",
      "data": "0x...",
      "value": "0x0",
      "gasLimit": "0x5f45bc",
      "gasPrice": "0x1b0875",
      "chainId": 8453,
      "from": "0xYOUR_WALLET_ADDRESS"
    },
    "includedSteps": [
      {
        "type": "protocol",
        "tool": "feeCollection",
        "toolDetails": { "key": "feeCollection", "name": "Integrator Fee" },
        "action": {...},
        "estimate": {...}
      },
      {
        "type": "protocol",
        "tool": "composer",
        "toolDetails": { "key": "composer", "name": "Composer" },
        "action": {...},
        "estimate": {...}
      }
    ]
  }
  ```
</Expandable>

### Key fields

| Field                                 | Description                                                                                                                  |
| ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `tool`                                | 同链 Composer 路由为 `"composer"`。对于跨链路由，这是桥接的名称（例如 `"stargateV2"`）。检查 `includedSteps` 中是否有 `tool: "composer"` 以确认路由中含有 Composer。 |
| `action.fromToken` / `action.toToken` | 带有 `address`、`symbol`、`decimals` 与 `chainId` 的代币对象。                                                                          |
| `action.slippage`                     | 应用于此报价的滑点容差。                                                                                                                 |
| `estimate.toAmount`                   | 以 `toToken` 最小单位计的预估输出。                                                                                                      |
| `estimate.toAmountMin`                | 计入滑点后的最小输出。                                                                                                                  |
| `estimate.approvalAddress`            | 需要授权其花费代币的合约地址（见下文）。                                                                                                         |
| `estimate.executionDuration`          | 以秒计的预估执行时间。                                                                                                                  |
| `transactionRequest`                  | 可直接签名的 EVM 交易。字段（`value`、`gasLimit`、`gasPrice`）为**十六进制编码字符串**。                                                               |
| `estimate.feeCosts`                   | 费用条目数组。每条 Composer 路由都包含一个 `feeCollection` 步骤，收取一小笔百分比费用。检查此数组以向用户呈现费用详情。                                                    |
| `includedSteps`                       | 路由将执行的有序步骤列表。通常包含一个 `feeCollection` 步骤，其后是 `composer` 步骤。                                                                    |

<Note>
  **十六进制编码值：** `transactionRequest` 的 `value`、`gasLimit` 与 `gasPrice` 字段为十六进制字符串（例如 `"0x5f45bc"`）。`chainId` 字段是普通数字。手动构建交易时（例如在 Python 中），用 `int(value, 16)` 解析十六进制字段。
</Note>

### Contract addresses

`estimate.approvalAddress` 与 `transactionRequest.to` 都指向 **LI.FI Diamond 合约**，这是一份部署在所有受支持链上的、经过验证和审计的智能合约。

| Chain          | LI.FI Diamond Address                                                                                                   |
| -------------- | ----------------------------------------------------------------------------------------------------------------------- |
| All EVM chains | [`0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE`](https://etherscan.io/address/0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE) |

Composer 链上 VM（执行编译后字节码者）是一份由 Diamond 在内部调用的独立合约。如需审计报告与合约验证，参见 [Security and Audits](/introduction/learn-more/security-and-audits)。

<Tip>
  报价反映当前市场状况，可能会过期。如果用户查看某个报价超过 30 秒，请在签名前重新获取，以取得最新的定价与模拟结果。
</Tip>

### Morpho vault naming

Morpho vault 以其\*\*策展人（curator）\*\*命名，而非以 Morpho 本身命名。例如，地址 `0x7BfA7C4f149E7415b73bdeDfe609237e29CBF34A` 返回 `symbol: "sparkUSDC"`，因为它是一个由 Spark 策展的 Morpho vault。这是预期行为：Morpho 提供 vault 基础设施，而像 Spark 这样的策展人在其上创建策略。

***

## Set Token Allowance

执行之前，LI.FI Diamond 合约需要获得授权以花费你的代币。授权地址在报价响应的 `estimate.approvalAddress` 中返回。

<Note>
  如果 `fromToken` 是原生代币（例如 ETH），跳过此步骤。原生代币无需授权。
</Note>

<Note>
  本指南面向后端/服务端签名，因此假定 `walletClient` 是用本地账户创建的（例如通过 `privateKeyToAccount`），这使 `walletClient.account` 始终有定义。如果你驱动的是浏览器注入的钱包，请用 `walletClient.getAddresses()`（或 `requestAddresses()`）而非 `walletClient.account` 来解析地址。
</Note>

<CodeGroup>
  ```ts TypeScript theme={"system"}
  import { erc20Abi, zeroAddress, type Address } from 'viem';
  import type { Account, Chain, PublicClient, Transport, WalletClient } from 'viem';

  const ensureAllowance = async (
    publicClient: PublicClient,
    walletClient: WalletClient<Transport, Chain | undefined, Account>,
    tokenAddress: Address,
    approvalAddress: Address,
    amount: bigint
  ) => {
    if (tokenAddress === zeroAddress) return; // Native token

    const currentAllowance = await publicClient.readContract({
      address: tokenAddress,
      abi: erc20Abi,
      functionName: 'allowance',
      args: [walletClient.account.address, approvalAddress],
    });

    if (currentAllowance < amount) {
      const hash = await walletClient.writeContract({
        address: tokenAddress,
        abi: erc20Abi,
        functionName: 'approve',
        args: [approvalAddress, amount],
        account: walletClient.account,
        chain: walletClient.chain,
      });
      await publicClient.waitForTransactionReceipt({ hash });
    }
  };

  await ensureAllowance(
    publicClient,
    walletClient,
    quote.action.fromToken.address as Address,
    quote.estimate.approvalAddress as Address,
    BigInt(quote.action.fromAmount)
  );
  ```

  ```python Python theme={"system"}
  from web3 import Web3

  ERC20_ABI = [
      {
          "name": "approve",
          "type": "function",
          "inputs": [
              {"name": "spender", "type": "address"},
              {"name": "amount", "type": "uint256"}
          ],
          "outputs": [{"name": "", "type": "bool"}]
      },
      {
          "name": "allowance",
          "type": "function",
          "inputs": [
              {"name": "owner", "type": "address"},
              {"name": "spender", "type": "address"}
          ],
          "outputs": [{"name": "", "type": "uint256"}]
      }
  ]

  def ensure_allowance(w3, account, token_address, approval_address, amount):
      token = w3.eth.contract(address=token_address, abi=ERC20_ABI)
      current = token.functions.allowance(account.address, approval_address).call()

      if current < int(amount):
          tx = token.functions.approve(approval_address, int(amount)).build_transaction({
              'from': account.address,
              'nonce': w3.eth.get_transaction_count(account.address),
          })
          signed = account.sign_transaction(tx)
          tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
          w3.eth.wait_for_transaction_receipt(tx_hash)

  ensure_allowance(
      w3,
      account,
      quote['action']['fromToken']['address'],
      quote['estimate']['approvalAddress'],
      quote['action']['fromAmount']
  )
  ```
</CodeGroup>

<Warning>
  如果发送了授权交易，请在执行前重新获取报价。`transactionRequest` 包含 gas 预估，可能在授权确认时已过期。用相同参数再次调用 `GET /v1/quote`，并使用新的 `transactionRequest`。
</Warning>

***

## Send the Transaction

提交报价响应中的 `transactionRequest`。这是一笔标准的 EVM 交易。

<CodeGroup>
  ```ts TypeScript theme={"system"}
  import { type Address, type Hex } from 'viem';

  const hash = await walletClient.sendTransaction({
    account: walletClient.account,
    to: quote.transactionRequest.to as Address,
    data: quote.transactionRequest.data as Hex,
    value: BigInt(quote.transactionRequest.value),
    gas: BigInt(quote.transactionRequest.gasLimit),
    gasPrice: BigInt(quote.transactionRequest.gasPrice),
    chain: walletClient.chain,
  });
  console.log('Transaction hash:', hash);

  const receipt = await publicClient.waitForTransactionReceipt({ hash });
  console.log('Confirmed in block:', receipt.blockNumber);
  ```

  ```python Python theme={"system"}
  tx = {
      'to': quote['transactionRequest']['to'],
      'data': quote['transactionRequest']['data'],
      'value': int(quote['transactionRequest']['value'], 16),
      'gas': int(quote['transactionRequest']['gasLimit'], 16),
      'gasPrice': int(quote['transactionRequest']['gasPrice'], 16),
      'nonce': w3.eth.get_transaction_count(account.address),
      'chainId': int(quote['transactionRequest']['chainId']),
  }

  signed = account.sign_transaction(tx)
  tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
  receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
  print(f"Confirmed: {receipt['transactionHash'].to_0x_hex()}")
  ```
</CodeGroup>

***

## Track Status

对于**同链** Composer 交易，一旦交易确认，操作即完成。

对于**跨链** Composer flow，轮询 `/status` 端点直到转移完成：

<CodeGroup>
  ```ts TypeScript theme={"system"}
  const getStatus = async (txHash: string, fromChain: number, toChain: number) => {
    const result = await axios.get('https://li.quest/v1/status', {
      params: { txHash, fromChain, toChain },
    });
    return result.data;
  };

  const pollStatus = async (txHash: string, fromChain: number, toChain: number) => {
    let status;
    do {
      status = await getStatus(txHash, fromChain, toChain);
      console.log(`Status: ${status.status} (${status.substatus || ''})`);

      if (status.status !== 'DONE' && status.status !== 'FAILED') {
        await new Promise((r) => setTimeout(r, 5000));
      }
    } while (status.status !== 'DONE' && status.status !== 'FAILED');

    return status;
  };

  // Only needed for cross-chain
  if (quote.action.fromChainId !== quote.action.toChainId) {
    const finalStatus = await pollStatus(
      tx.hash,
      quote.action.fromChainId,
      quote.action.toChainId
    );
    console.log('Final:', finalStatus.status);
  }
  ```
</CodeGroup>

如需包含 substatus 值在内的完整状态参考，参见 [Transaction Status Tracking](/introduction/user-flows-and-examples/status-tracking)。

***

## Error Handling

使用 Composer 时的常见错误：

| Error                    | Cause              | Resolution                                                |
| ------------------------ | ------------------ | --------------------------------------------------------- |
| `No routes found`        | vault 代币不受支持或流动性不足 | 核实 vault 代币地址正确，且该协议[受支持](/composer/protocols-and-chains) |
| `Simulation failed`      | Composer 执行在链上会失败  | 检查代币余额、授权，以及该 vault 是否正在接受存入                              |
| `Insufficient allowance` | 代币授权未设置或过低         | 用正确的 `approvalAddress` 与金额调用 `approve()`                  |

如需完整错误参考，参见 [Error Codes](/api-reference/error-codes)。

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Cross-Chain Patterns" icon="bridge" href="/composer/lifi-api/guides/cross-chain-compose">
    高级跨链 Composer flow 与模式
  </Card>

  <Card title="Withdrawals Guide" icon="clock" href="/composer/lifi-api/guides/withdrawals">
    实现同链与跨链取出
  </Card>

  <Card title="Vault Deposit Recipes" icon="book" href="/composer/lifi-api/recipes/vault-deposits">
    Morpho、Aave、Euler 等的可复制粘贴 recipe
  </Card>

  <Card title="SDK Integration" icon="cube" href="/composer/lifi-api/guides/sdk-integration">
    带有钩子、事件与自动重试的托管式执行
  </Card>

  <Card title="Supported Protocols" icon="list" href="/composer/protocols-and-chains">
    受支持协议与能力的完整列表
  </Card>
</CardGroup>
