Skip to navigation

DEX Aggregator API

The HyperFlow DEX Aggregator API gives you the same routing engine that powers hyperflow.fun: quote the best route across 30+ HyperEVM liquidity sources, then execute through the HyperFlow router contract.

Base URL: https://ag-api.hyperflow.fun/v1/hyperevm — all endpoints serve mainnet only; there is no public testnet environment.

Authentication & rate limits

Requests can be authenticated with an API key passed in the x-api-key header:

AccessRate limit
Without API key5 requests/second
With API key15 requests/second

To obtain an API key, reach out to the HyperFlow team on Discord.

Get a quote

GET /quote

Retrieves the optimal trading route and price quote between two tokens.

Parameters

ParameterRequiredDescription
tokenInYesInput token address
tokenOutYesOutput token address
amountInYesInput amount, in wei
exchangesNoComma-separated DEX ids to restrict routing; blank routes across all available sources
gasPriceNoCustom gas price, in wei

Response

FieldDescription
tokenIn / tokenOutToken addresses of the quoted pair
amountIn / amountInUsdInput amount in wei / USD
amountOut / amountOutUsdOutput amount in wei / USD
minAmountOutOutput floor after slippage, in wei
priceImpactPercentEstimated price impact of the route
totalGas / totalGasUsdEstimated gas for the route
gasPriceGas price used for the estimate, in wei
splits[]Route splits — each with amountIn, amountOut, and the detailed swaps path (pool, exchange, type per hop)
requestIdIdentifier of this quote

Get swap data

GET /swap

Generates the transaction data needed to execute the swap through the router contract.

Parameters

All Quote parameters, plus:

ParameterRequiredDescription
receiverYesRecipient address for the output token
slippageNoMaximum acceptable slippage, 0–1 (e.g. 0.01 = 1%). Defaults to 0.01
minAmountOutNoCustom minimum acceptable output amount
deadlineNoTransaction deadline in Unix seconds (default: now + 20 minutes)

Response

/swap wraps the quote:

{
"quote": { "...": "all /quote fields" },
"tx": {
"router": "0x980B9271A33c4B31214301fAE584B18dBB9731eC",
"data": "0xf970cf64…"
},
"requestId": "2b493058b2cf36f39de8d4c41589b9cc"
}

Approve tx.router for tokenIn (ERC-20 inputs), then send tx.data to tx.router — attaching value = amountIn for native-token input.

Code example

import {ethers} from 'ethers'; // ^6.13.4
import type {TransactionRequest} from 'ethers';
const routerApiUrl = 'https://ag-api.hyperflow.fun/v1/hyperevm';
const rpcUrl = 'network-RPC'; // Replace with your network RPC
const privateKey = 'your-private-key-here'; // Replace with your private key
const apiKey = process.env.HYPERFLOW_API_KEY; // Optional: raises the rate limit
const apiHeaders = apiKey ? {'x-api-key': apiKey} : undefined;
const wallet = new ethers.Wallet(privateKey);
const provider = new ethers.JsonRpcProvider(rpcUrl);
async function signAndSendTransaction(tx: TransactionRequest) {
const signer = wallet.connect(provider);
if (!tx.gasLimit) {
const estimatedGas = await signer.estimateGas(tx);
tx.gasLimit = estimatedGas * BigInt(120) / BigInt(100);
}
const txResponse = await signer.sendTransaction(tx);
console.log('Transaction Hash:', txResponse.hash);
const receipt = await txResponse.wait();
console.log('Transaction Mined:', receipt);
return receipt;
}
type Address = `0x${string}`;
export const EtherAddress = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
const erc20Abi = [
{
"constant": true,
"inputs": [{"name": "_owner", "type": "address"}, {"name": "_spender", "type": "address"}],
"name": "allowance",
"outputs": [{"name": "remaining", "type": "uint256"}],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [{"name": "_spender", "type": "address"}, {"name": "_value", "type": "uint256"}],
"name": "approve",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
}
];
async function approve(token: Address, spender: Address, amount: string | bigint) {
const contract = new ethers.Contract(token, erc20Abi, provider);
const allowance = await contract.allowance(wallet.address, spender);
if (allowance < BigInt(amount)) {
const data = contract.interface.encodeFunctionData('approve', [spender, amount]);
return signAndSendTransaction({to: token, data});
}
return Promise.resolve(true);
}
function serializeParameters(params: Record<string, any>) {
const searchParams = new URLSearchParams(
Object.fromEntries(Object.entries(params).filter(([_, v]) => v !== undefined && v !== null && v !== ''))
);
return searchParams.toString();
}
interface QuoteParameters {
tokenIn: Address;
tokenOut: Address;
amountIn: string | bigint;
exchanges?: string[];
}
// Retrieves the optimal trading route and price quote between two tokens
export async function quote(args: QuoteParameters) {
const params = {
...args,
amountIn: args.amountIn.toString(),
exchanges: args.exchanges?.join(','),
};
const quoteResponse = await fetch(`${routerApiUrl}/quote?${serializeParameters(params)}`, {headers: apiHeaders});
return quoteResponse.json();
}
interface SwapParameters extends QuoteParameters {
slippage?: number;
receiver?: Address;
}
// Generates the transaction data needed to execute the swap through the router
export async function swap(args: SwapParameters) {
const params = {
...args,
amountIn: args.amountIn.toString(),
exchanges: args.exchanges?.join(','),
slippage: args?.slippage?.toString(),
receiver: args.receiver || wallet.address,
};
const encodingResponse = await fetch(`${routerApiUrl}/swap?${serializeParameters(params)}`, {headers: apiHeaders});
const encodingResult = await encodingResponse.json();
const tokenInIsNative = args.tokenIn.toLowerCase() === EtherAddress.toLowerCase();
if (!tokenInIsNative) {
await approve(args.tokenIn, encodingResult.tx.router, args.amountIn);
}
return await signAndSendTransaction({
to: encodingResult.tx.router,
value: tokenInIsNative ? args.amountIn : undefined,
data: encodingResult.tx.data,
});
}

Errors

Errors are returned as {"error": "<message>"}. Note that the API returns HTTP 500 for ordinary client errors as well — don’t treat 500 as a retryable server failure without reading the body:

ResponseMeaning
500 {"error":"no path found"}No route exists for the pair/amount
500 with a field-validation messageA required parameter is missing (e.g. receiver)

Resources