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

# Routes API

> Integrate Routes via the V3 quote API plus a single Portal contract call. Production-ready, language-agnostic, server-to-server.

The Routes V3 API is a unified interface to Eco's stablecoin settlement network, a production-grade, server-to-server integration path that gives you full control to program custom money-movement logic and configure the speed, cost, and security parameters that match your use case. Three steps: get a quote, publish and fund the intent onchain using the `encodedRoute` from the quote, poll for fulfillment.

For the full OpenAPI surface, see the [API Reference](/api-reference/introduction).

## 0. Prerequisites

* Source-chain RPC and a funded wallet
* HTTP client (curl, fetch, axios)
* Web3 library (viem, ethers)

No authentication is required. Pass an identifier as `dAppID` in the request body for attribution.

## 1. Get a quote

The V3 quote API returns the best quote ready for onchain execution. It returns the `encodedRoute` you'll pass straight to the Portal, you don't construct the intent struct yourself.

```bash theme={null}
curl -X POST https://quotes.eco.com/api/v3/quotes/single \
  -H "Content-Type: application/json" \
  -d '{
    "dAppID": "your-app",
    "quoteRequest": {
      "sourceChainID": 10,
      "destinationChainID": 8453,
      "sourceToken": "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
      "destinationToken": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "sourceAmount": "1000000",
      "funder": "0xYourWalletAddress",
      "recipient": "0xRecipientAddress"
    }
  }'
```

Available quote endpoints:

| Endpoint                       | Use for                                              |
| ------------------------------ | ---------------------------------------------------- |
| `POST /api/v3/quotes/single`   | Best single quote, ready for execution               |
| `POST /api/v3/quotes/exactIn`  | Specify input amount, get multiple competing quotes  |
| `POST /api/v3/quotes/exactOut` | Specify output amount, get quotes for required input |

Response shape:

```typescript theme={null}
{
  data: {
    quoteResponse: {
      intentExecutionType: "SELF_PUBLISH",
      sourceChainID: number,
      destinationChainID: number,
      sourceToken: string,
      destinationToken: string,
      sourceAmount: string,            // bigint as string (reward you'll lock)
      destinationAmount: string,       // bigint as string (recipient receives)
      funder: string,
      recipient: string,
      fees: [{ name, description, token, amount }],
      deadline: number,                // unix seconds
      estimatedFulfillTimeSec: number,
      encodedRoute: string,            // ABI-encoded, pass straight to Portal
    },
    contracts: {
      sourcePortal: string,            // Portal address on source chain
      destinationPortal: string,
      prover: string,
    }
  }
}
```

## 2. Approve the reward token

Standard ERC-20 approve to `contracts.sourcePortal` for the reward amount (`quoteResponse.sourceAmount`).

```typescript theme={null}
import { erc20Abi } from 'viem';

const portal = quote.data.contracts.sourcePortal;
const rewardToken = quote.data.quoteResponse.sourceToken;
const rewardAmount = BigInt(quote.data.quoteResponse.sourceAmount);

const allowance = await publicClient.readContract({
  address: rewardToken,
  abi: erc20Abi,
  functionName: 'allowance',
  args: [user, portal],
});

if (allowance < rewardAmount) {
  await walletClient.writeContract({
    address: rewardToken,
    abi: erc20Abi,
    functionName: 'approve',
    args: [portal, rewardAmount],
  });
}
```

## 3. Publish and fund

Build the reward struct from the quote and call `publishAndFund` on the source Portal.

```typescript theme={null}
const reward = {
  deadline: BigInt(quote.data.quoteResponse.deadline),
  creator: user,
  prover: quote.data.contracts.prover,
  nativeAmount: 0n,
  tokens: [{ token: rewardToken, amount: rewardAmount }],
};

const tx = await walletClient.writeContract({
  address: portal,
  abi: portalAbi,
  functionName: 'publishAndFund',
  args: [
    BigInt(quote.data.quoteResponse.destinationChainID),
    quote.data.quoteResponse.encodedRoute,
    reward,
    false, // allowPartial
  ],
});

const receipt = await publicClient.waitForTransactionReceipt({ hash: tx });
// Read the IntentPublished event from receipt.logs to extract intentHash
```

## 4. Track fulfillment

```bash theme={null}
curl -X POST https://quotes.eco.com/api/v3/intents/intentStatus \
  -H "Content-Type: application/json" \
  -d '{ "intentHash": "0x..." }'
```

Status returns:

```typescript theme={null}
{
  data: {
    intentHash: string,
    status: {
      status: "Pending" | "Completed",
      subStatus: "WaitingToFulfill" | "WaitingForRefund" | "Fulfilled" | "Refunded",
      subStatusMessage: string
    },
    intentCreated: { chainId, transactionHash, blockExplorerUrl },
    fulfillment?: { chainId, transactionHash, blockExplorerUrl },
    refund?: { chainId, transactionHash, blockExplorerUrl }
  }
}
```

Typical fulfillment: **20–40 seconds**, depending on source-chain finality.

## 5. Refunds (if expired)

If the intent expires unfulfilled, call `refund(routeHash, reward)` on the source Portal to reclaim the reward tokens. Refunds are also driven by an independent permissionless service.

## Custom intents with destination calls

If you need arbitrary contract calls on the destination chain (bridge AND deposit, for example), build the intent's `route.calls` array yourself and call `publishAndFund` with a hand-built route, see [Destination calls](/routes/capabilities/destination-calls).
