> Treat every fee rate, margin ratio, order limit, minimum and address in this documentation as an illustration of the shape of the value, never as a constant to hardcode - the live values are served by GET /markets and GET /config on the Perps API.

# DEX Aggregator API

> Integrate HyperFlow's swap routing into your own product.

The HyperFlow DEX Aggregator API gives you the same routing engine that powers [hyperflow.fun](https://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:

| Access          | Rate limit         |
| --------------- | ------------------ |
| Without API key | 5 requests/second  |
| With API key    | 15 requests/second |

To obtain an API key, reach out to the HyperFlow team on [Discord](https://discord.gg/GGDmD4K9CK).

## Get a quote

```
GET /quote
```

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

### Parameters

| Parameter   | Required | Description                                                                            |
| ----------- | -------- | -------------------------------------------------------------------------------------- |
| `tokenIn`   | Yes      | Input token address                                                                    |
| `tokenOut`  | Yes      | Output token address                                                                   |
| `amountIn`  | Yes      | Input amount, in wei                                                                   |
| `exchanges` | No       | Comma-separated DEX ids to restrict routing; blank routes across all available sources |
| `gasPrice`  | No       | Custom gas price, in wei                                                               |

### Response

| Field                        | Description                                                                                                          |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `tokenIn` / `tokenOut`       | Token addresses of the quoted pair                                                                                   |
| `amountIn` / `amountInUsd`   | Input amount in wei / USD                                                                                            |
| `amountOut` / `amountOutUsd` | Output amount in wei / USD                                                                                           |
| `minAmountOut`               | Output floor after slippage, in wei                                                                                  |
| `priceImpactPercent`         | Estimated price impact of the route                                                                                  |
| `totalGas` / `totalGasUsd`   | Estimated gas for the route                                                                                          |
| `gasPrice`                   | Gas price used for the estimate, in wei                                                                              |
| `splits[]`                   | Route splits — each with `amountIn`, `amountOut`, and the detailed `swaps` path (`pool`, `exchange`, `type` per hop) |
| `requestId`                  | Identifier 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:

| Parameter      | Required | Description                                                             |
| -------------- | -------- | ----------------------------------------------------------------------- |
| `receiver`     | Yes      | Recipient address for the output token                                  |
| `slippage`     | No       | Maximum acceptable slippage, 0–1 (e.g. `0.01` = 1%). Defaults to `0.01` |
| `minAmountOut` | No       | Custom minimum acceptable output amount                                 |
| `deadline`     | No       | Transaction deadline in Unix seconds (default: now + 20 minutes)        |

### Response

`/swap` wraps the quote:

```json
{
  "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

```typescript
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:

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

## Resources

* [Swagger reference](https://ag-api.hyperflow.fun/v1/hyperevm/swagger/index.html)
* [Router contract addresses](/developers/smart-contracts)
* Earn bonus points for your users via the [Points Integration](/developers/points-integration)
* Bridging across chains? See the [Bridge Integration](/developers/bridge-integration)