# How to Let Your AI Agent Swap Tokens with x402 Micropayments

A complete walkthrough for adding non-custodial token swaps to an autonomous
agent using [Tollbooth](https://api.tollboothswap.xyz), the x402 payment
protocol, and USDC micropayments. No API keys, no accounts, no custody - the
agent pays ~half a cent per call and signs its own transactions.

Works on 8 chains: Solana, Base, Ethereum, Arbitrum, Polygon, Optimism, BSC,
Avalanche.

## Why x402 instead of API keys

Traditional swap APIs require sign-ups, API keys and monthly plans - all
things an autonomous agent cannot do by itself. x402 uses the HTTP 402
status code: the server quotes a price in the response, the agent signs a
USDC payment authorization, retries the request, and the payment settles
on-chain. The whole loop is machine-to-machine with no human in it.

Tollbooth accepts tolls in USDC on **Base** or **Solana mainnet** - both
gasless for the payer (Base uses EIP-3009 signatures; Solana gas is sponsored
by the facilitator, so the wallet needs zero SOL).

## What you need

- Node 20+
- A payer wallet holding a few dollars of USDC on Base or Solana
- Packages: `npm i @x402/fetch @x402/evm viem` (Base payer) or
  `npm i @x402/fetch @x402/svm @solana/kit` (Solana payer)

## Step 1 - Resolve the token (free)

Agents usually start with a ticker, not an address. Resolution is free:

```
GET https://api.tollboothswap.xyz/v1/tokens/base/PEPE
```

Response: matches ranked by DEX liquidity, with `verified: true` for
canonical tokens from the curated list. If several contracts claim the same
ticker, the deepest pool ranks first and the response tells you to screen
unverified tokens before trading.

## Step 2 - Get a quote (free)

```
GET https://api.tollboothswap.xyz/v1/quote?chain=solana
    &inputToken=So11111111111111111111111111111111111111112
    &outputToken=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
    &amount=1000000000
```

`amount` is in base units (lamports/wei-style). The quoted `outAmount`
already includes Tollbooth's swap fee, so it is directly comparable with
other venues. Quotes are free - comparison-shop as much as you like.

## Step 3 - Screen the token (x402, $0.01)

Before buying any token the agent did not hard-code, run a safety check:

```
GET https://api.tollboothswap.xyz/v1/check/solana/<mint address>
```

Returns a verdict (`ok` / `warn` / `critical` / `unknown`), a 0-100 risk
score, and itemized findings: honeypot detection, sell tax, freezable mints,
Token-2022 transfer hooks, blacklists, hidden owners. Treat `critical` as
do-not-trade.

## Step 4 - Build the swap (x402, ~$0.005)

```ts
import { wrapFetchWithPayment, x402Client } from "@x402/fetch";
import { ExactEvmScheme } from "@x402/evm/exact/client";
import { toClientEvmSigner } from "@x402/evm";
import { privateKeyToAccount } from "viem/accounts";
import { createPublicClient, http } from "viem";
import { base } from "viem/chains";

const account = privateKeyToAccount(process.env.PAYER_KEY as `0x${string}`);
const client = new x402Client().register(
  "eip155:8453",
  new ExactEvmScheme(toClientEvmSigner(account, createPublicClient({ chain: base, transport: http() }))),
);
const payFetch = wrapFetchWithPayment(fetch, client);

const built = await (await payFetch("https://api.tollboothswap.xyz/v1/swap/build", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    chain: "solana",
    inputToken: "So11111111111111111111111111111111111111112",
    outputToken: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    amount: "1000000000",
    taker: "<the wallet that will sign the swap>",
    safeMode: true, // screens both tokens, refuses honeypots at no extra cost
  }),
})).json();
```

Paying from a Solana wallet instead:

```ts
import { wrapFetchWithPayment, x402Client } from "@x402/fetch";
import { registerExactSvmScheme } from "@x402/svm/exact/client";
import { createKeyPairSignerFromBytes } from "@solana/kit";

const signer = await createKeyPairSignerFromBytes(secretKeyBytes);
const client = registerExactSvmScheme(new x402Client(), { signer });
const payFetch = wrapFetchWithPayment(fetch, client);
```

`payFetch` handles the whole 402 negotiation automatically: it reads the
payment requirements from the response header, signs a USDC authorization,
and retries. One call from your point of view.

## Step 5 - Sign and submit

The response contains an **unsigned** transaction:

- **Solana**: `transaction.serializedTransaction` is a base64 versioned
  transaction. Sign with the taker keypair and submit it to any RPC. Submit
  before `lastValidBlockHeight` passes or rebuild.
- **EVM chains**: `transaction` is `{ to, data, value, gas }` calldata. If
  `allowanceSpender` is present, approve it for the sell token first.

Tollbooth never sees your keys and cannot move funds - it only builds
transactions. Every paid build also returns an HMAC-signed receipt you can
re-verify later at `GET /v1/receipts/:id` for audit trails.

## Using it from MCP (Claude, Cursor, etc.)

Tollbooth ships an MCP server exposing the same API as tools
(`resolve_token`, `get_quote`, `check_token`, `build_swap`,
`get_receipt`). Point your MCP config at it and set `TOLLBOOTH_PAYER_KEY`
to pay tolls automatically.

## Error handling cheat sheet

| Status | Meaning | What to do |
| --- | --- | --- |
| 400 | invalid parameters | read `issues` and `usage` in the body |
| 402 | payment required | let your x402 client pay and retry |
| 405 | wrong HTTP method | body includes the correct `usage` |
| 422 | safeMode refused a critical-risk token | do not trade it |
| 502 | upstream DEX router rejected | body has detail; adjust and retry |
| 503 | chain temporarily unavailable | retry later or use another chain |

Every error response embeds the corrective next step, so agents can recover
without reading docs.

## Links

- Runnable examples: https://github.com/soundsparkaudiolab/tollbooth-examples
- Service manifest: https://api.tollboothswap.xyz/.well-known/x402-service
- Agent usage guide: https://api.tollboothswap.xyz/skill.md
- x402 protocol: https://www.x402.org
- x402 Bazaar (discovery): https://docs.cdp.coinbase.com/x402/bazaar
