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

# Integrate the Routes API

> Discover supported assets, request and verify a quote, fund the transfer, and track delivery with the Eco API v1.

Use the Eco API v1 at `https://api.eco.com` to quote a transfer, inspect its route, and obtain a funding transaction. This guide follows an exact-input USDC transfer from Base to OP Mainnet. Quote availability depends on the chain, token pair, amount, and available liquidity.

## Prerequisites

* A server-side API key enabled for v1. [Contact Eco](mailto:contact@eco.com) to request access.
* A source-chain wallet with USDC and enough ETH for approval and funding transactions
* An OP Mainnet recipient address and source-chain RPC access
* Node.js 22.18 or later and `viem` for the example below
* The current [supported chains and tokens](/resources/supported-chains-tokens)

Keep your API key on the server. Set `ECO_API_KEY`, `ECO_FUNDER`, and `ECO_RECIPIENT` in your environment; never include the key in browser or mobile code.

## Discover chains and tokens

Read [`GET /v1/chains`](/api-reference/v1/chains) for supported chains, Portal addresses, and each chain's `quoteSigner`. Read [`GET /v1/tokens`](/api-reference/v1/tokens) for token addresses, decimals, and supported gasless standards. Cache discovery responses with a refresh policy so that configuration changes reach your integration.

A listed token or chain does not guarantee a quote for every request.

## Request a quote

Install the dependency with `npm install viem`. Save the example as `request-quote.ts`, set the environment variables above, and run `node request-quote.ts` with Node.js 22.18 or later.

The example uses native `fetch`, checks HTTP errors, and prints the API response without funding it. Replace the environment values with addresses you intend to use.

```typescript theme={null}
import process from 'node:process';
import { getAddress } from 'viem';

async function main(): Promise<void> {
  const apiKey = process.env.ECO_API_KEY;
  const funder = process.env.ECO_FUNDER;
  const recipient = process.env.ECO_RECIPIENT;
  if (!apiKey || !funder || !recipient) {
    throw new Error('Set ECO_API_KEY, ECO_FUNDER, and ECO_RECIPIENT');
  }

  async function request(path: string, body?: unknown): Promise<unknown> {
    const response = await fetch(`https://api.eco.com${path}`, {
      method: body === undefined ? 'GET' : 'POST',
      headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey! },
      body: body === undefined ? undefined : JSON.stringify(body),
      signal: AbortSignal.timeout(30_000),
    });
    const text = await response.text();
    if (!response.ok) throw new Error(`HTTP ${response.status}: ${text}`);
    return JSON.parse(text);
  }

  console.log(await request('/v1/chains'));
  console.log(await request('/v1/tokens?chainId=8453'));
  console.log(await request('/v1/tokens?chainId=10'));

  const quote = await request('/v1/quotes', {
    type: 'exact-in',
    source: {
      chainId: 8453,
      token: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
      amount: '1000000', // 1 USDC, in base units
      funder: getAddress(funder),
    },
    destination: {
      chainId: 10,
      token: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85',
      recipient: getAddress(recipient),
    },
    slippage: 0.005, // 0.5%, expressed as a decimal fraction
    dappId: 'usdc-transfer-example',
  });
  console.log(quote);
}

main().catch((error: unknown) => {
  console.error(error instanceof Error ? error.message : error);
  process.exitCode = 1;
});
```

A successful request returns `200` with a signed quote. The [quote reference](/api-reference/v1/quotes) includes full success and error examples.

| Field | What to check |
| - | - |
| `source` and `destination` | Requested chains, tokens, funder, and recipient |
| `destination.amountOut` | Expected output amount |
| `destination.minAmountOut` | Quoted minimum output; verify the route enforces your required outcome |
| `fees[]` | Fee amounts, denominations, and whether each fee is an estimate |
| `steps[].intents[]` | Intents involved in the route and their roles |
| `execution.transaction` | Transaction to fund the intent |
| `execution.vault` | Address used in gasless funding authorizations |
| `expiresAt` | Quote expiry in Unix seconds |
| `signature` | Signature over the quote ID, intent hash set, and expiry |

Use `exact-out` to specify `destination.amount`, or `custom` to supply destination calls. See the [quote reference](/api-reference/v1/quotes) for the required fields for each type.

## Verify before funding

[Verify the quote signature](/api-reference/quote-verification) against the source chain's `quoteSigner`. Reject expired quotes. Signature verification alone does not verify every JSON field or the funding transaction: recompute intent hashes from the decoded intent data and check the transaction and delivery route against your request.

The [reference script](/api-reference/agent-integration#reference-script) implements these checks for supported EVM and Solana route shapes and reports when it cannot verify the recipient.

## Fund the quote

<Tabs>
  <Tab title="Onchain funding">
    For an EVM source, verify that the transaction targets the expected Portal. Check the source token allowance, approve the required amount if needed, and wait for a successful approval receipt. Estimate gas, recheck quote expiry, then send the returned `execution.transaction` from `source.funder`. Check that the funding receipt succeeded.

    For a Solana source, `execution.transaction.type` is `svm` and the response carries `feePayer` and `instructions`. The [reference script](/api-reference/agent-integration#reference-script) shows both transaction formats.
  </Tab>

  <Tab title="Gasless authorization">
    A key enabled for v1 and mapped to a partner is required for submit endpoints. Confirm that the source token supports the selected authorization method.

    | Endpoint | Required binding |
    | - | - |
    | [Permit3](/api-reference/v1/submit-permit3) | Each `permit3.permits[].account` is `execution.vault` |
    | [Permit2](/api-reference/v1/submit-permit2) | `permit2.spender` is `execution.vault`; the token must already be approved to Permit2 |
    | [ERC-3009](/api-reference/v1/submit-erc-3009) | `authorization.to` is `execution.vault` |

    The documented response is `202` with a gasless job. Retrying the identical signed payload returns the existing job with `200`. Persist the payload and job ID; job acceptance or `published` is not delivery confirmation.
  </Tab>
</Tabs>

## Track delivery

Use [`GET /v1/intents/status`](/api-reference/v1/intent-status) to track the delivery intent. For a direct transfer, this is the quote's `intentHash`. For routes with multiple intents, inspect the roles in `steps[].intents[]`; the funded source intent may complete before the recipient is paid. See [Intent types](/resources/intent-types).

| Status | Interpretation |
| - | - |
| `pending` | Fulfillment has not been reported. |
| `filled`, `settled` | The tracked intent was fulfilled. Confirm you are tracking the delivery intent. |
| `refundable`, `expired` | Inspect the refund path; neither state confirms funds were returned. |
| `refunded` | A refund has been reported. |
| `failed` | Inspect the failure and associated transactions before retrying. |
| `unknown` | No status is available for that identifier. |

Use bounded polling and preserve identifiers if your client times out. A client timeout does not cancel a funded intent.

## Troubleshooting

* `400`: correct the request fields reported in the error.
* `401` or `403`: verify key access. A submit error saying the request could not be attributed to an authorized key requires Eco to check the partner mapping.
* `422 chain-not-supported`: select a supported chain.
* `502 solver-error`: the service did not return a usable quote. Check the pair and amount, then retry with a bounded delay.
* Network errors or an uncertain submit result: inspect the existing job or transaction before authorizing another payment.

No requests-per-second quota is published. Handle `429` with backoff and honor `Retry-After` when present. See [Errors and retries](/api-reference/errors).

## Next steps

* [Run the reference implementation](/api-reference/agent-integration#reference-script)
* [Add destination calls](/routes/capabilities/destination-calls)
* [Use keyless price discovery](/api-reference/public-quote)
