Skip to main content
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.

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.
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:
EndpointUse for
POST /api/v3/quotes/singleBest single quote, ready for execution
POST /api/v3/quotes/exactInSpecify input amount, get multiple competing quotes
POST /api/v3/quotes/exactOutSpecify output amount, get quotes for required input
Response shape:
{
  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).
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.
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

curl -X POST https://quotes.eco.com/api/v3/intents/intentStatus \
  -H "Content-Type: application/json" \
  -d '{ "intentHash": "0x..." }'
Status returns:
{
  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.

API Reference

Every REST endpoint, request/response shapes.

Portal contract

The contract you’re calling.

Recipes

End-to-end task guides.