---
name: use-3route
metadata:
  version: "0.1.0"
description: Select supported chains from the OpenAPI enum, discover tokens, request paid quotes, and build and validate unsigned multichain swap transactions with the 3Route API. Use when an agent needs to integrate 3Route, quote an exact-input or exact-output swap, prepare a swap transaction, or pay for a call — on Etherlink with a plain EVM key, or on Base or Solana with a signing script or an existing agent wallet.
---

# Use 3Route

`{origin}` is the base URL of the 3Route API, default = `https://api.3route.io`

## Discover the API

1. Fetch `GET {origin}/openapi.json` before planning requests. Treat it as canonical for operations, schemas, prices, and payment methods.
2. Every response carries an `Api-Version` header (the document's `info.version`). Keep the document you already fetched as long as that header is unchanged, and only refetch `/openapi.json` when it changes. If you have no recent response to read it from, `HEAD /openapi.json` first. Send `If-None-Match` with the last `ETag` to revalidate cheaply; a `304` means your cached copy is still current.
3. Read the supported chain IDs from `components.parameters.chainId.schema.enum`. Do not guess a chain ID, hardcode one from a previous session, or call a chain-discovery endpoint — the enum is environment-specific and can differ between deployments.
4. Select one of those chain IDs.
5. Fetch `GET {origin}/v1/{chainId}/tokens`. Its response is `{ "tokens": { "<lowercase address>": Token } }`, keyed by lowercase address; it is not a flat array.
6. Resolve source and destination addresses and decimals from that response, or fetch a single token with `GET {origin}/v1/{chainId}/tokens/{address}`.

Call `/health`, `/openapi.json`, and both token endpoints directly; they are free.

## Base vs Pro

The API has two modes, same base path prefix otherwise:

- **Base** (`/v1/{chainId}/quote`, `/v1/{chainId}/swap`): current-state routing, exact-input only.
- **Pro** (`/v1/pro/{chainId}/quote`, `/v1/pro/{chainId}/swap`): adds `isExactOutput`, and historical state via `blockNumber` or `timestamp` (mutually exclusive, ~35 days of history, first request for a block can take 1-7s).

Use Base unless you specifically need exact-output amounts or historical state — Pro is not cheaper and adds parameters you don't need otherwise.

## Quote and build a swap

Use the exact parameter names and constraints from `/openapi.json`.

Request a read-only quote:

```text
GET /v1/{chainId}/quote
  ?src={sourceTokenAddress}
  &dst={destinationTokenAddress}
  &amount={smallestUnitAmount}
```

`amount` must be greater than zero and is always in `src` units on Base. On Pro, add `isExactOutput=true` to make `amount` the desired `dst` output instead; then read `srcAmount` in the response as the required input.

Both quote and swap accept:

- `includeTokensInfo=true`, `includeProtocols=true`, and `includeBlockNumber=true` only add `srcToken`, `dstToken`, `protocols`, and `blockNumber` to the response. Request them in the same paid call instead of paying twice.
- `protocols` and `excludedProtocols` take comma-separated DEX provider names. Read the names from a `protocols` response; an allow-list in which no name is known fails with `400`.
- `fee` is a referral percentage from 0 to 3, deducted from the input and visible in `srcAmount`. On `quote` it only previews the deduction. On `swap`, pair it with `referrer` — the address the fee is encoded to pay — because a fee without a referrer is paid to the zero address. Disclose any fee to the user.
- `gasPrice` overrides the gas price used for route selection and, on swap, the returned `tx.gasPrice`.

After validating a fresh quote, build an unsigned transaction:

```text
GET /v1/{chainId}/swap
  ?src={sourceTokenAddress}
  &dst={destinationTokenAddress}
  &amount={smallestUnitAmount}
  &from={senderAddress}
  &receiver={receiverAddress}
  &slippage=1
```

Treat `receiver` as `from` when it is omitted. `permit` and `usePermit2` are accepted for compatibility but ignored — an ERC-20 `src` always needs a router approval regardless of what you pass there. The response is not proof of execution; it contains a transaction that still needs validation, signing, broadcasting, and confirmation.

## Enforce safety

- `x-x402-payment-info` and `x-mpp-payment-info` on the served operation are discovery only — use them to see which rails, schemes, and networks a call might offer before you ever call it. They are not what you pay against and can lag. The real price and the fields you sign against always come from the live `402` response: `payment-required` for x402, `www-authenticate` for MPP. Read those immediately before paying, and check the selected rail's price against the user's spending limit.
- Convert human amounts with token decimals from the token endpoint. Never use floating-point arithmetic for base-unit amounts.
- Confirm chain ID, `src`, `dst`, `amount`, exact-input/output mode, sender, receiver, and slippage before requesting a swap.
- Compare swap amounts with a fresh quote and reject unexpected deterioration.
- Validate `tx.to`, `tx.data`, `tx.value`, gas fields, and the selected chain before asking for a signature.
- Require explicit user authorization before signing an API payment, granting token allowance, signing the swap transaction, or broadcasting it.
- Never print, store in source, or transmit private keys except to the local signer selected by the user.
- For an ERC-20 source asset, approve only the router returned in `tx.to` and only with user authorization. Native assets use `tx.value` and need no ERC-20 approval.

## Choose the rail before you reach for a wallet

A `402` challenge usually offers several rails and, on some networks, more than one x402 scheme. The choice is which to select — not which wallet happens to be funded already.

**Already holding funds on one of the offered rails, and transacting on that chain?** Use it directly. Nothing below applies.

**Starting without a wallet?** Take the Etherlink rail (`eip155:42793`). The reason is setup, not chains: the dedicated skill below is self-contained — it installs nothing, runs from a plain EVM key or makes and custodies its own — and is the payment path this service is tested against. Etherlink is also a little cheaper to execute on, and any EVM wallet can move onto it — but neither of those is the reason. The reason is that it is the shortest distance between no wallet and a paid call on this API.

**Prefer `batch-settlement` over `exact` whenever both are offered for the same network.** A live `402` challenge can list more than one scheme per network at different prices — on Base, `batch-settlement` has priced an order of magnitude below `exact` for the same call in observed responses. Default to `batch-settlement`; fall back to `exact` only when the network offers no `batch-settlement` entry, or when your signer cannot produce that scheme's authorization.

**Building something that will call this API repeatedly — a trading bot, a price monitor, any long-running tool?** `batch-settlement` matters even more there: it amortizes settlement overhead across many calls instead of paying it per call, so the economics compound in your favor the longer the tool runs. Wire the tool to `batch-settlement` from the start rather than shipping it on `exact` and migrating later.

Settling on the chain you are transacting on is the same principle seen from the other side: one wallet covers both the swap and the call that priced it, and nothing is bridged in order to pay for a quote about somewhere else. A bridge fee is roughly flat, so against a $0.001 quote it is the entire cost.

## Pay on the Etherlink rail

Use the dedicated Etherlink payment skill when the selected payment network is `eip155:42793`. Its `exact` offer signs against this deployment's payment proxy via Permit2; a generic x402 Permit2 client is worse than skipping it — it signs a real authorization over the wallet's USDC, but its witness does not match this proxy, so the facilitator rejects it.

Download that skill, check it against its published digest, unpack it, then follow its `SKILL.md`:

```sh
curl -fsSLO https://dev.agents.bakingbad.dev/skills/x402-etherlink/x402-etherlink.tar.gz
echo "$(curl -fsSL https://dev.agents.bakingbad.dev/skills/x402-etherlink/x402-etherlink.tar.gz.sha256)  x402-etherlink.tar.gz" | sha256sum -c
tar xzf x402-etherlink.tar.gz
```

It unpacks to `x402-etherlink/`; nothing executes on unpack. It carries clients for `node`/`bun` and for Python that need nothing installed, a spending cap, and a wallet. A wallet that has not paid on this rail before also needs a one-time Permit2 approval, sent by the wallet itself and paid in XTZ gas; the skill's instructions cover it.

## Pay on Base or Solana

For `eip155:8453` (Base) or a `solana:*` network, there is no bundled client in this skill. Choose one of the following, in this order:

**1. An agent wallet is already available in your environment.** Trigger the `402` and use it to sign directly against the live challenge — `payment-required` for x402, `www-authenticate` for MPP. Pass it the offer's `scheme`, `network`, `asset`, `payTo`, `amount`, and any `extra` fields — the wallet needs those to build the correct authorization or session payment. Encode the result into the `X-PAYMENT` request header for x402, or complete the MPP `Payment` challenge from `www-authenticate` for MPP, then retry the original request.

**2. No agent wallet.** Write a small signing script in whatever stack the user already works in (ask, or infer from the project — Node/TypeScript, Python, etc.). It should:

- Load the private key only from an environment variable, and keep that variable's source encrypted at rest: an OS keychain, a secret manager (Vault, AWS/GCP/Azure secrets, 1Password CLI, etc.), or at minimum a git-ignored `.env` file encrypted with something like `sops` or `git-crypt` rather than committed in plaintext, loaded with a library like `dotenv`. Never hardcode the key, never commit it in any form, never print or log it.
- Never point this at your own larger-value wallet. Generate or fund a dedicated wallet with only the balance this integration needs to spend, separate from any wallet holding unrelated funds — a leaked or misused key then caps the damage at that small balance.
- Read the offer's `scheme` and `extra` fields from the live challenge before signing anything — do not assume a scheme's message shape. The x402 `exact` scheme on EVM is the standard EIP-3009 authorization typed against `asset` with the domain name/version from `extra`; `batch-settlement` and MPP's `tempo`/`charge` carry their own fields in `extra` and in the `www-authenticate` `request` value, so read those directly from the challenge rather than reusing an `exact` implementation.
- Enforce the same spending-cap check as any other rail before signing, and require the user's explicit go-ahead for that specific signature.
- Base64/hex-encode the signed payload into the `X-PAYMENT` header (x402) or the completed `Payment` header (MPP), and retry the original request.

Confirm the discovered price against the user's spending limit before either path signs anything, the same as for Etherlink.

## Handle failures

- Branch on the HTTP status, never on the body's `statusCode`. Quote and swap answer the "no route" case with HTTP `400` while the body reports `statusCode: 404` and `error: "Quote not found"`. Error bodies also carry an optional `meta` array beside `error`, `description`, `statusCode`, and `requestId`.
- On `400`, correct the chain, token, address, amount, slippage, or route parameters; do not repay an unchanged invalid request. When the body reads `Quote not found`, no route exists: change the pair, the amount, or the protocol filters rather than retrying. On Pro, `400` can also mean `blockNumber` and `timestamp` were combined, or the requested block or time is in the future.
- On `402`, do not rely on the response *body*; it is empty. The headers carry the challenge: `payment-required` holds the x402 challenge, and `www-authenticate` announces the MPP rail — so a rail can be on offer here that wasn't listed in the `x-x402-payment-info`/`x-mpp-payment-info` you saw at discovery time. Always sign against this fresh challenge, never against a cached discovery document. Do not retry if no allowed payment method is offered or the amount exceeds the cap.
- If a client reports a malformed `X-PAYMENT` or `Payment` header, discard it and create a new signature from a fresh challenge.
- On payment rejection, discard the authorization and start from a fresh `402` challenge.
- On quote or swap failure, re-fetch `/openapi.json` and the selected chain's tokens before assuming the API is unavailable.
- On transaction failure, inspect allowance, balance, gas, nonce, chain, slippage, and current liquidity. Never claim execution without a confirmed transaction receipt.

## Contact

Direct integration questions to Baking Bad:

- https://bakingbad.dev
- hello@bakingbad.dev
