> ## Documentation Index
> Fetch the complete documentation index at: https://docs.uatu.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Integrate the API

> A working swap integration, from quote to execution.

Base URL is `https://api.uatu.dev`.

Quoting requires an API key, so create one in the [console](/console) first. The
catalogue endpoints are open.

## The flow

<Steps>
  <Step title="Request for a quote">
    `POST /quotes` with the pair, the amount and who receives the output.
  </Step>

  <Step title="Read the steps">
    The response carries a `steps` array: an ordered list of ready-to-send
    transactions, typically a Permit2 approval followed by the swap.
  </Step>

  <Step title="Send each step in order">
    Sign and broadcast with your own wallet, waiting for each to confirm.
  </Step>
</Steps>

## Write the integration

<Tabs>
  <Tab title="viem">
    ```ts theme={null}
    import { createWalletClient, createPublicClient, http } from "viem";
    import { mainnet } from "viem/chains";
    import { privateKeyToAccount } from "viem/accounts";

    const UATU = "https://api.uatu.dev";

    const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
    const wallet = createWalletClient({ account, chain: mainnet, transport: http() });
    const publicClient = createPublicClient({ chain: mainnet, transport: http() });

    // 1. quote
    const res = await fetch(`${UATU}/quotes`, {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${process.env.UATU_API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        originChainId: 1,
        destinationChainId: 1,
        tokenIn: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",  // WETH
        tokenOut: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
        amount: "1",
        recipientAddress: account.address,
        slippageBps: 50, // optional, 0.5%
      }),
    });

    const body = await res.json();
    if (!res.ok) throw new Error(body.message);
    const quote = body.data;

    // 2. check the floor and the clock before spending gas
    console.log(`out ${quote.amountOutFloat} USDC via ${quote.route.name}`);
    console.log(`min ${quote.amountOutMinimum} (raw units)`);

    if (Math.floor(Date.now() / 1000) >= Number(quote.deadline)) {
      throw new Error("quote expired, request a new one");
    }

    // 3. send the steps in order
    for (const step of quote.steps) {
      const hash = await wallet.sendTransaction({
        to: step.to as `0x${string}`,
        data: step.data as `0x${string}`,
        value: step.value ? BigInt(step.value) : 0n,
      });
      await publicClient.waitForTransactionReceipt({ hash });
      console.log(`${step.message}: ${hash}`);
    }
    ```
  </Tab>

  <Tab title="ethers.js">
    ```ts theme={null}
    import { JsonRpcProvider, Wallet } from "ethers";

    const UATU = "https://api.uatu.dev";

    const provider = new JsonRpcProvider(process.env.RPC_URL);
    const wallet = new Wallet(process.env.PRIVATE_KEY!, provider);

    // 1. quote
    const res = await fetch(`${UATU}/quotes`, {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${process.env.UATU_API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        originChainId: 1,
        destinationChainId: 1,
        tokenIn: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",  // WETH
        tokenOut: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
        amount: "1",
        recipientAddress: wallet.address,
        slippageBps: 50, // optional, 0.5%
      }),
    });

    const body = await res.json();
    if (!res.ok) throw new Error(body.message);
    const quote = body.data;

    // 2. check the floor and the clock before spending gas
    console.log(`out ${quote.amountOutFloat} USDC via ${quote.route.name}`);
    console.log(`min ${quote.amountOutMinimum} (raw units)`);

    if (Math.floor(Date.now() / 1000) >= Number(quote.deadline)) {
      throw new Error("quote expired, request a new one");
    }

    // 3. send the steps in order
    for (const step of quote.steps) {
      const tx = await wallet.sendTransaction({
        to: step.to,
        data: step.data,
        value: step.value ? BigInt(step.value) : 0n,
      });
      await tx.wait();
      console.log(`${step.message}: ${tx.hash}`);
    }
    ```
  </Tab>
</Tabs>

## Get a read-only quote

`POST /quotes/routes` takes the same body, with matching `originChainId` and
`destinationChainId`, and returns the best acceptable quote per DEX, ordered by
output amount. Nothing is persisted and no transaction steps are returned. Use it
while a user is still choosing, then call `POST /quotes` for a fresh executable quote.

```sh theme={null}
curl -X POST https://api.uatu.dev/quotes/routes \
  -H "Authorization: Bearer ${UATU_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "originChainId": 1, "destinationChainId": 1,
    "tokenIn": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
    "tokenOut": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
    "amount": "1",
    "recipientAddress": "0xYourAddress"
  }'
```

A real response, trimmed to one route:

```json theme={null}
{
  "code": 200,
  "message": "DEX quotes fetched successfully",
  "data": [
    {
      "amountIn": "1000000000000000000",
      "amountOut": "2493777615",
      "amountOutMinimum": "2481308726",
      "slippageBps": 50,
      "deadline": 1787624479,
      "route": { "name": "CowSwap", "dex": "cowswap", "fees": "42207128027132" }
    }
  ]
}
```

## Common pitfalls

<AccordionGroup>
  <Accordion title="Amounts come in two forms" icon="calculator">
    `amount` on the **request** is a decimal string in display units, so `"1"` means
    one WETH. Amounts on the **response** are integer strings in the token's smallest
    unit: `amountOut` of `"2493777615"` is 2493.777615 USDC at 6 decimals. Use
    `amountOutFloat` for display and the raw integers for anything on-chain.
  </Accordion>

  <Accordion title="Quotes expire" icon="clock">
    `deadline` is a Unix timestamp five minutes out. Check it before broadcasting,
    especially if a user has been staring at a confirmation screen.
  </Accordion>

  <Accordion title="Steps are ordered and must all land" icon="list-ol">
    A swap usually needs its Permit2 approval mined before the swap itself. Wait
    for each receipt rather than firing them together.
  </Accordion>

  <Accordion title="amountOutMinimum is enforced on-chain" icon="shield">
    It is encoded into the calldata, so a fill worse than that floor reverts
    rather than filling badly. A reverted swap that cost gas is usually a moved
    market, not a bad request. Re-quote and retry.
  </Accordion>

  <Accordion title="Native assets use value" icon="coins">
    When the input token is the chain's native asset, the step carries `value`. Send
    it, or the swap reverts.
  </Accordion>
</AccordionGroup>

<Card title="Error handling" icon="triangle-exclamation" href="/guides/errors">
  Every failure shape, with real responses.
</Card>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.