Documentation Index
Fetch the complete documentation index at: https://eco.com/docs/llms.txt
Use this file to discover all available pages before exploring further.
The Routes V3 API gives you a production-grade, server-to-server integration path. Three steps: get a quote, publish + fund the intent on-chain using the encodedRoute from the quote, poll for fulfillment.
For the full OpenAPI surface, see the API Reference.
0. Prerequisites
- Source-chain RPC + 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 on-chain 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:
| 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:
{
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 + 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.
Read next