Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.o1.exchange/llms.txt

Use this file to discover all available pages before exploring further.

The DEX Aggregator API supports two integration shapes. They produce equivalent on-chain transactions; the difference is when the routing engine runs.

Two-step

/quote → human reviews price → /submit → broadcast.Best for swap UIs.

One-step

/execute → broadcast.Best for one-click flows and bots.
Use this flow when a user reviews the quoted price before they commit.
// 1. Quote
const quote = await fetch(`${API_URL}/quote`, {
  method: "POST",
  headers: { "x-api-key": API_KEY, "content-type": "application/json" },
  body: JSON.stringify({
    chainId: 8453,
    tokenIn: USDC,
    tokenOut: WETH,
    amountIn: "1000000000",
    slippageBps: 100,
  }),
}).then((r) => r.json());

// 2. Display to user
showQuote({
  output: formatUnits(BigInt(quote.routePlan.expectedAmountOut), 18),
  minOutput: formatUnits(BigInt(quote.routePlan.minAmountOut), 18),
  route: quote.routePlan.routes
    .map((r) => r.legs.map((l) => l.dex).join(" → "))
    .join(" | "),
  fee: `${(quote.routePlan.feeBps ?? 0) / 100}%`,
});

// 3. User clicks "Swap" → build tx
const submit = await fetch(`${API_URL}/submit`, {
  method: "POST",
  headers: { "x-api-key": API_KEY, "content-type": "application/json" },
  body: JSON.stringify({
    quoteId: quote.quoteId,
    user: walletAddress,
  }),
}).then((r) => r.json());

// 4. Send to wallet
const txHash = await walletClient.sendTransaction({
  to: submit.to as `0x${string}`,
  data: submit.data as `0x${string}`,
  value: BigInt(submit.value),
});

Pros

  • User confirms the price they see; no last-second surprise.
  • You can run validation between quote and submit (e.g. “is this trade > $X? require a confirm dialog”).
  • Clean separation between read (quote) and write (submit) for caching, analytics, and rate limiting.

Cons

  • Quotes have a TTL (~10 seconds). If the user takes too long, /submit returns 404 and you must re-quote. See Quote freshness.
  • Two API calls per swap.

One-step (instant swap)

Use this flow when there’s no preview step.
const exec = await fetch(`${API_URL}/execute`, {
  method: "POST",
  headers: { "x-api-key": API_KEY, "content-type": "application/json" },
  body: JSON.stringify({
    chainId: 8453,
    tokenIn: USDC,
    tokenOut: WETH,
    amountIn: "1000000000",
    slippageBps: 100,
    user: walletAddress,
  }),
}).then((r) => r.json());

const txHash = await walletClient.sendTransaction({
  to: exec.to as `0x${string}`,
  data: exec.data as `0x${string}`,
  value: BigInt(exec.value),
});

Pros

  • Single round trip.
  • No quoteId to track, no expiry to handle.

Cons

  • The user (or bot) doesn’t see the price before signing. If you still want to show it, log exec.routePlan.expectedAmountOut after the fact.
  • Less flexibility for caching and analytics, since each call rebuilds the full route plan server-side.

Choosing the right pattern

Use casePattern
Standard swap UI with confirm dialogTwo-step
One-click “swap now” buttonOne-step
Server-side market-maker / botOne-step
Limit-order style flow with delayed executionTwo-step (re-quote on each tick)
Mobile UI with poor connectivityOne-step (fewer round trips)
Even when you use /execute for the user-facing call, you can still hit /quote separately for live price display in the modal. Just be aware they consume separate rate-limit budget.

Always: handle expired quotes

Whichever pattern you pick, treat 404 quote not found or expired from /submit as recoverable: re-fetch /quote with the same parameters and retry. Don’t surface this as a user-facing error unless it happens repeatedly. See Quote freshness for the full pattern.