# SwapsPro (swaps.pro) — full > A non-custodial, browser-based cross-chain swap terminal and wallet toolkit, with a keyless public HTTP API that autonomous agents can trade through. No account, no signup, no custody: every action is signed by the holder's own wallet. SwapsPro swaps assets across chains, moves or sweeps a whole wallet's worth of ERC-20s in one confirmation, deploys payment-splitting contracts, and embeds any of that in someone else's site. Everything it does in a browser is also available over an HTTP API that needs no key. For agents specifically: quoting is free and unauthenticated, and every quote comes back as data you sign yourself — a ready-to-sign EVM transaction, a CoW order to sign and post, or a deposit address and memo. SwapsPro never takes custody and never holds keys. This is the expanded companion to https://www.swaps.pro/llms.txt. Both are generated from the same source as the documentation site, so they cannot disagree with it. ## Documentation ### Docs — https://www.swaps.pro/docs Three ways to integrate, in increasing order of how much you build: - **Widget** — paste an iframe. No keys, no backend. You get SwapsPro's swap card in your own colours. - **SDK** — `@swapspro/sdk`, a zero-dependency TypeScript client. You build the UI; it quotes and hands you a transaction to sign through any EIP-1193 wallet. - **HTTP API** — three CORS-open GET endpoints. Any language, any runtime, no key. This is the surface an autonomous agent uses. All three sit on the same routing, so the chains, the prices and the fees are identical whichever you pick. The quickstart is three requests and needs nothing but curl: curl "https://www.swaps.pro/api/sdk/v1/chains" curl "https://www.swaps.pro/api/sdk/v1/tokens?chainId=8453" curl "https://www.swaps.pro/api/sdk/v1/quote?sellChain=8453&sellToken=ETH&buyChain=8453&buyToken=USDC&amount=0.1&address=0xYourAddress" `@swapspro/sdk` is on npm (0.1.1); `@swapspro/widget`, the React wrapper around the embed, is not published yet and is built from `packages/widget`. The HTTP API both wrap is live and public today. ### SDK — https://www.swaps.pro/docs/sdk A headless TypeScript client over the same three endpoints. No runtime dependencies, no React, no wallet library of its own — it takes any EIP-1193 provider you already have. What it adds over calling the API directly: types for every request and response, typed errors that carry the API's `code`, and an execute helper that handles the ERC-20 approval, waits for it, and then sends the swap. It does not add behaviour the HTTP API lacks — the routing, the fees and the rate limits are the API's, not the SDK's. If you are not in a JavaScript runtime, use the API and lose nothing. On npm at 0.1.1: `npm i @swapspro/sdk`. Building it from `packages/sdk` (`npm run sdk:build`) produces the same thing. ### HTTP API — https://www.swaps.pro/docs/api Base URL: `https://www.swaps.pro/api/sdk/v1`. Three GET endpoints, CORS-open (`Access-Control-Allow-Origin: *`), no API key, no account, no signup. Every endpoint answers `OPTIONS` with a 204 preflight. Responses are always JSON. **GET /chains** — every chain SwapsPro can price. No parameters. `id` is the symbol the other endpoints accept; EVM chains also carry a numeric `chainId`. Cached `public, s-maxage=3600, stale-while-revalidate=86400`. **GET /tokens?chainId=…** — the curated token list for one chain (natives plus blue chips), not an index of every token on it. You can still quote any ERC-20 by passing its contract address. Accepts a numeric EVM chain id or a chain symbol; `chain` is an accepted alias. **GET /quote** — a firm quote, priced by the same route picker the app uses. Required: `sellChain`, `sellToken`, `buyChain`, `buyToken`, `amount`, `address`. Optional: `recipient` (required cross-chain), `slippage` (percent, 0 < s <= 50), `partner` (your integrator id, echoed and logged), `partnerFeeBps` (additive, capped at 100 bps). `amount` is in **human units** — `0.1`, not `100000000000000000`. Hex, exponents and negatives are rejected. The response always names the winning venue in `provider`, and carries exactly one execution shape: `tx` (+ `approval` for ERC-20 sells) for same-chain EVM, `order` for a CoW route, or `depositAddress` + `memo` for a THORChain-style route. `expiresAt` is always present. Errors are `{ "error": "...", "code": "..." }` with a matching status: `BAD_REQUEST` 400, `UNSUPPORTED_PAIR` 400, `UNKNOWN_CHAIN` 404, `UNKNOWN_TOKEN` 404, `NO_ROUTE` 404, `RATE_LIMITED` 429, `UPSTREAM_ERROR` 502. Rate limits: `/quote` uses a fixed 60-second window keyed on the first entry of `X-Forwarded-For`. 60 requests per minute per IP, BEST-EFFORT: counted in memory inside each serverless instance, so the effective ceiling is higher than the number and varies with how many instances are warm. Treat it as a courtesy brake, not a quota, and do not design around it. `/chains` and `/tokens` are not rate limited. There is no paid tier on this deployment: a limit counted per instance cannot be metered, so none is sold. /api/sdk/v1/access answers 503. ### GET /chains · API reference — https://www.swaps.pro/docs/api/chains # SwapsPro API — GET /chains Every chain SwapsPro can quote, with its CAIP-2 id and whether it can be sold from. Base URL: https://www.swaps.pro/api/sdk/v1. No API key. CORS open. JSON in and out. ## Parameters - none ## Example ```bash curl "https://www.swaps.pro/api/sdk/v1/chains" ``` ## 200 response ```json { "chains": [ { "id": "ETH", "name": "Ethereum", "nativeSymbol": "ETH", "caip2": "eip155:1", "type": "evm", "sellSupported": true, "chainId": 1 }, { "id": "BTC", "name": "Bitcoin", "nativeSymbol": "BTC", "caip2": "bip122:000000000019d6689c085ae165831e93", "type": "utxo", "sellSupported": true }, { "id": "BASE", "name": "Base", "nativeSymbol": "ETH", "caip2": "eip155:8453", "type": "evm", "sellSupported": true, "chainId": 8453 }, { "id": "BSC", "name": "BNB Smart Chain", "nativeSymbol": "BNB", "caip2": "eip155:56", "type": "evm", "sellSupported": true, "chainId": 56 }, { "id": "AVAX", "name": "Avalanche", "nativeSymbol": "AVAX", "caip2": "eip155:43114", "type": "evm", "sellSupported": true, "chainId": 43114 }, { "id": "ARB", "name": "Arbitrum", "nativeSymbol": "ETH", "caip2": "eip155:42161", "type": "evm", "sellSupported": true, "chainId": 42161 }, { "id": "RHD", "name": "Robinhood Chain", "nativeSymbol": "ETH", "caip2": "eip155:4663", "type": "evm", "sellSupported": true, "chainId": 4663 }, { "id": "BCH", "name": "Bitcoin Cash", "nativeSymbol": "BCH", "caip2": "bip122:000000000000000000651ef99cb9fcbe", "type": "utxo", "sellSupported": true }, { "id": "LTC", "name": "Litecoin", "nativeSymbol": "LTC", "caip2": "bip122:12a765e31ffd4059bada1e25190f6e98", "type": "utxo", "sellSupported": true }, { "id": "DOGE", "name": "Dogecoin", "nativeSymbol": "DOGE", "caip2": "bip122:1a91e3dace36e2be3bf030a65679fe82", "type": "utxo", "sellSupported": true }, { "id": "GAIA", "name": "Cosmos", "nativeSymbol": "ATOM", "caip2": "cosmos:cosmoshub-4", "type": "cosmos", "sellSupported": true }, { "id": "THOR", "name": "THORChain", "nativeSymbol": "RUNE", "caip2": "cosmos:thorchain-mainnet-v1", "type": "cosmos", "sellSupported": true }, { "id": "SOL", "name": "Solana", "nativeSymbol": "SOL", "caip2": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", "type": "svm", "sellSupported": false }, { "id": "HIVE", "name": "Hive", "nativeSymbol": "HIVE", "caip2": "hive:mainnet", "type": "hive", "sellSupported": true } ] } ``` ## Fields - `id` — SwapsPro chain symbol; accepted anywhere a chain is a parameter - `caip2` — CAIP-2 network id, e.g. eip155:8453 - `type` — evm · utxo · cosmos · hive · svm - `chainId` — numeric EIP-155 id; EVM chains only - `sellSupported` — false when the chain can only be a destination ## Errors Every error is `{ "error": string, "code": string }` with a matching HTTP status. ## Rules - Use `id` (e.g. BASE) or `chainId` (e.g. 8453) as the sellChain/buyChain value on /quote; both resolve. - A chain with `sellSupported: false` may appear as buyChain only. ### GET /tokens · API reference — https://www.swaps.pro/docs/api/tokens # SwapsPro API — GET /tokens The curated token list for one chain: natives first, then the ERC-20s SwapsPro resolves by symbol. Base URL: https://www.swaps.pro/api/sdk/v1. No API key. CORS open. JSON in and out. ## Parameters - `chainId` (query, number | symbol, required): Numeric EVM chain id or SwapsPro chain symbol (BASE, ETH, BTC…). `chain` is accepted as an alias. ## Example ```bash curl "https://www.swaps.pro/api/sdk/v1/tokens?chainId=8453" ``` ## 200 response ```json { "chain": "BASE", "chainId": 8453, "tokens": [ { "symbol": "ETH", "name": "Base", "caip": "eip155:8453/slip44:60", "chain": "BASE", "isToken": false, "decimals": 18 }, { "symbol": "USDC", "name": "USD Coin", "caip": "eip155:8453/erc20:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", "chain": "BASE", "isToken": true, "contract": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", "decimals": 6 }, { "symbol": "WETH", "name": "Wrapped Ether", "caip": "eip155:8453/erc20:0x4200000000000000000000000000000000000006", "chain": "BASE", "isToken": true, "contract": "0x4200000000000000000000000000000000000006", "decimals": 18 }, { "symbol": "cbBTC", "name": "Coinbase Wrapped BTC", "caip": "eip155:8453/erc20:0xcbb7c0000ab88b473b1f5afd9ef808440eed33bf", "chain": "BASE", "isToken": true, "contract": "0xcbb7c0000ab88b473b1f5afd9ef808440eed33bf", "decimals": 8 }, { "symbol": "cbETH", "name": "Coinbase Wrapped Staked ETH", "caip": "eip155:8453/erc20:0x2ae3f1ec7f1f5012cfeab0185bfc7aa3cf0dec22", "chain": "BASE", "isToken": true, "contract": "0x2ae3f1ec7f1f5012cfeab0185bfc7aa3cf0dec22", "decimals": 18 }, { "symbol": "DAI", "name": "Dai Stablecoin", "caip": "eip155:8453/erc20:0x50c5725949a6f0c72e6c4a641f24049a917db0cb", "chain": "BASE", "isToken": true, "contract": "0x50c5725949a6f0c72e6c4a641f24049a917db0cb", "decimals": 18 } ] } ``` ## Fields - `caip` — CAIP-19 asset id — the key /prices takes - `isToken` — false for the chain's native asset - `contract` — ERC-20 address, EVM token assets only - `mint` — SPL mint, Solana only - `decimals` — only when known statically ## Errors Every error is `{ "error": string, "code": string }` with a matching HTTP status. - 400 BAD_REQUEST: chainId is missing - 404 UNKNOWN_CHAIN: the chain is not one SwapsPro serves ## Rules - Symbols resolve case-insensitively on /quote; a contract address always wins over a symbol. - Amounts on /quote are HUMAN decimals ("0.1"), never base units — use `decimals` only to read balances, not to build the amount parameter. ### GET /prices · API reference — https://www.swaps.pro/docs/api/prices # SwapsPro API — GET /prices USD spot prices for up to 100 assets in one call, keyed by CAIP-19 id. Base URL: https://www.swaps.pro/api/sdk/v1. No API key. CORS open. JSON in and out. Rate limited: 60/min per IP (600 with a grant from /access). ## Parameters - `tokens` (query, CAIP-19 list, required): Comma-separated CAIP-19 asset ids, at most 100. Get them from /tokens (`caip`). ## Example ```bash curl "https://www.swaps.pro/api/sdk/v1/prices?tokens=eip155%3A8453%2Fslip44%3A60%2Ceip155%3A8453%2Ferc20%3A0x833589fcd6edb6e08f4c7c32d4f71b54bda02913" ``` ## 200 response ```json { "prices": [ { "caip": "eip155:8453/slip44:60", "usd": 2458.35662985502, "symbol": "ETH", "confidence": 0.99, "asOf": "2026-09-03T14:42:50.000Z" }, { "caip": "eip155:8453/erc20:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", "usd": 1.000011030039417, "symbol": "USDC", "confidence": 0.99, "asOf": "2026-09-03T14:42:50.000Z" } ], "unpriced": [], "requested": 2 } ``` ## Fields - `prices` — object keyed by CAIP-19 id → USD price - `unpriced` — ids the source had no price for - `requested` — how many ids were asked for ## Errors Every error is `{ "error": string, "code": string }` with a matching HTTP status. - 400 BAD_REQUEST: tokens is missing, or more than 100 were sent (TOO_MANY_TOKENS) - 429 RATE_LIMITED: more than 60 requests per minute from one IP - 502 PRICE_SOURCE_UNAVAILABLE: the price source did not answer ## Rules - Never treat `unpriced` or a 502 as a zero price. Show the asset as unpriced, and keep any total it belongs to marked incomplete. - Prices are USD floats, cached for a minute at the edge. Do not use them as execution prices; /quote is the execution price. ### GET /quote · API reference — https://www.swaps.pro/docs/api/quote # SwapsPro API — GET /quote One routed quote across every integrated venue, returned ready to sign: a transaction, a CoW order, or a deposit address. Base URL: https://www.swaps.pro/api/sdk/v1. No API key. CORS open. JSON in and out. Rate limited: 60/min per IP (600 with a grant from /access). ## Parameters - `sellChain` (query, chain, required): Chain symbol or numeric id, from /chains. - `sellToken` (query, symbol | address, required): Symbol from /tokens, or a contract address. - `buyChain` (query, chain, required): Chain symbol or numeric id. May differ from sellChain for a cross-chain route. - `buyToken` (query, symbol | address, required): Symbol from /tokens, or a contract address. - `amount` (query, decimal string, required): Human amount of sellToken to sell, e.g. "0.1". Never base units. - `address` (query, address, required): The wallet that will sign. The venue builds the transaction for this sender. - `recipient` (query, address, default: same as address): Where the bought asset lands, when it is not the signer. - `slippage` (query, percent, default: the venue's own floor): Maximum slippage in percent, 0 < s ≤ 50. Sets `minBuyAmount` on venues that accept it. - `partner` (query, string ≤ 64, optional): Your integrator id. Stamped on the quote and used for attribution. - `partnerFeeBps` (query, integer bps, default: 0): Fee you keep on top of SwapsPro's, in basis points, capped by tier. `partnerFee` in the response says what was actually collected. - `X-SwapsPro-Access` (header, token, optional): A grant from /access. Raises the ceiling from 60 to 600 requests per minute. Also accepted as Authorization: Bearer. ## Example ```bash curl "https://www.swaps.pro/api/sdk/v1/quote?sellChain=8453&sellToken=ETH&buyChain=8453&buyToken=USDC&amount=0.1&address=0x21c9a94AF76B59b171b32fD125A4edF0e9A2Ad3e&partner=docs-example" ``` ## 200 response ```json { "provider": "0x", "sellChain": "BASE", "buyChain": "BASE", "sellToken": { "caip": "eip155:8453/slip44:60", "symbol": "ETH" }, "buyToken": { "caip": "eip155:8453/erc20:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", "symbol": "USDC" }, "sellAmount": "0.1", "buyAmount": "244.524665", "minBuyAmount": "242.068365", "rate": 2445.24665, "tx": { "chainId": 8453, "to": "0x0000000000001ff3684f28c67538d4d072c22734", "data": "0x2213bc0b0000000000000000000000007747f8d2a76bd6345cc29622a946a929…", "value": "0x16345785d8a0000", "gasLimit": "0x13df23" }, "expiresAt": "2026-09-03T14:45:40.996Z", "partner": "docs-example", "partnerFee": { "requestedBps": 0, "collectedBps": 0, "collected": false, "note": "No partner fee was requested." } } ``` ## Fields - `provider` — which venue won: 0x, cow, lifi, thorchain, … - `buyAmount / minBuyAmount` — expected output and the enforced floor, human decimals - `rate` — buyAmount per 1 sellToken - `tx` — chainId, to, data, value, gasLimit — ready for eth_sendTransaction - `approval` — exact-amount ERC-20 approve to send first, when needed - `order` — CoW: typedData to sign, body and postUrl to submit - `depositAddress / memo` — THORChain-style: where to send and what to say - `expiresAt` — ISO time after which the quote must not be used - `partnerFee` — what was requested, what was collected, and why ## Errors Every error is `{ "error": string, "code": string }` with a matching HTTP status. - 400 BAD_REQUEST: a required parameter is missing, or amount/slippage are malformed - 404 UNKNOWN_TOKEN: a chain or token could not be resolved (UNKNOWN_CHAIN, UNKNOWN_TOKEN) - 429 RATE_LIMITED: more than 60 requests per minute from one IP without a grant - 502 UPSTREAM_ERROR: no venue could price it (NO_ROUTE, UNSUPPORTED_PAIR) or an upstream failed (UPSTREAM_ERROR) ## Rules - Read `minBuyAmount` as the guarantee and `buyAmount` as the estimate. Never promise a user more than the floor. - Execute exactly what came back: send `tx` as-is (value and gasLimit are 0x-hex), or sign `order.typedData` and POST `order.body` to `order.postUrl`, or deposit to `depositAddress` with `memo` verbatim. Do not rebuild calldata. - If `approval` is present, send that approve transaction first and wait for it to confirm. It is for the exact amount, never unlimited. - A quote expires at `expiresAt`. Re-quote after that instead of sending a stale transaction. - A 502 with NO_ROUTE is an answer, not an outage: the pair cannot be priced at that size right now. Try a smaller amount or a different pair; do not retry in a loop. ### GET /access · API reference — https://www.swaps.pro/docs/api/access # SwapsPro API — GET /access A 24-hour grant that lifts /quote from 60 to 600 requests per minute, paid over x402 or unlocked by a Pro Pass. Base URL: https://www.swaps.pro/api/sdk/v1. No API key. CORS open. JSON in and out. ## Parameters - `PAYMENT-SIGNATURE` (header, x402 v2 payload, optional): The signed payment answering the 402 challenge. `X-PAYMENT` is accepted for x402 v1. - `address` (query, address, optional): Pro Pass flow, step 1: the wallet holding the pass. Returns the message to sign. - `issued` (query, ISO time, optional): Pro Pass flow, step 2: the `issued` value from step 1, verbatim. - `signature` (query, 0x signature, optional): Pro Pass flow, step 2: EIP-191 personal_sign of the step-1 message. ## Example ```bash curl "https://www.swaps.pro/api/sdk/v1/access" ``` ## 200 response ```json { "token": "sp_acc_…", "header": "X-SwapsPro-Access", "subject": "0x21c9…Ad3e", "via": "x402", "limit": { "requestsPerMinute": 600, "previously": 60 }, "expiresAt": "2026-09-04T12:00:00.000Z", "ttlSeconds": 86400, "usage": "Send \"X-SwapsPro-Access: \" (or \"Authorization: Bearer \") on GET /api/sdk/v1/quote.", "note": "Quotes are free at 60 requests per minute with no credential at all — this token only raises the ceiling. It is a bearer token: everyone presenting it draws from the same bucket, so sharing it divides your headroom rather than multiplying it." } ``` ## Fields - `token` — the bearer grant - `header` — the header name to send it as - `limit.requestsPerMinute` — the new ceiling; `previously` is the free one - `expiresAt / ttlSeconds` — when the grant stops working ## Errors Every error is `{ "error": string, "code": string }` with a matching HTTP status. - 402: no payment presented and the facilitator is configured - 503 ACCESS_NOT_CONFIGURED: the x402 facilitator is not configured on this deployment ## Rules - Do not buy a grant until you have actually been rate limited (a 429 from /quote). At the free ceiling most agents never need one. - Keep the token server-side. Presenting it from many clients shares one bucket. - The route may answer 503 with `missingConfig` on a deployment without a facilitator; treat that as "no grants here", not as a retryable error. ### AI agents — https://www.swaps.pro/docs/agents Written for a program rather than a person. The whole path, in order: 1. **Discover** — `GET /api/sdk/v1/chains`, then `GET /api/sdk/v1/tokens?chainId=…`. Both are cached for an hour; cache them yourself and you will essentially never call them. 2. **Quote** — `GET /api/sdk/v1/quote`. Free, no key, no payment. Rate limit: 60 requests per minute per IP, BEST-EFFORT: counted in memory inside each serverless instance, so the effective ceiling is higher than the number and varies with how many instances are warm. Treat it as a courtesy brake, not a quota, and do not design around it. 3. **Recognise the shape.** A quote comes back in exactly one of three execution shapes and you must branch on which: - `tx` — a ready-to-sign EVM transaction (`chainId`, `to`, `data`, `value`, `gasLimit`, already 0x-hex). Plus `approval` when the sell asset is an ERC-20: grant `amountWei` of `token` to `spender` and wait for it to mine first. - `order` — a CoW Protocol order. Not a transaction: PUT the appData document to `appDataUrl`, sign `typedData` with `eth_signTypedData_v4`, POST the signed order to `postUrl`. Gasless and asynchronous; solvers fill it in a batch auction and it can expire unfilled. - `depositAddress` + `memo` — a THORChain-style deposit route. Send `sellAmount` of the sell asset to `depositAddress` with `memo` attached, from a wallet for the sell chain. 4. **Sign and broadcast** with your own key. SwapsPro never holds keys or funds and cannot move anything on your behalf. 5. **Track** — same-chain routes settle in the transaction receipt; a CoW order settles when the returned `orderUid` fills; a deposit route settles when the destination chain receives the output. What the agent must hold: a funded wallet on the sell chain, and enough native gas on that chain to send the approval and the swap. Quoting needs nothing. Rate limits and how to raise them: quoting is free, forever. 60 requests per minute per IP, BEST-EFFORT: counted in memory inside each serverless instance, so the effective ceiling is higher than the number and varies with how many instances are warm. Treat it as a courtesy brake, not a quota, and do not design around it. There is no paid tier on this deployment: a limit counted per instance cannot be metered, so none is sold. /api/sdk/v1/access answers 503. ### Widget — https://www.swaps.pro/docs/widget An iframe pointing at `https://www.swaps.pro/embed`. No API keys and no backend on your side: the visitor's own wallet connects inside the frame and signs there. Two levels of styling, and the difference is how the change travels. The query string carries `theme`, `accent` (`#RRGGBB`, URL-encoded), `radius` (0-32), `bg` (`solid`, a hex, or transparent), `width` (320-720), `font` and `chrome` (`card` or `none`, which drops the widget's own border, fill and shadow). The app's own `sell`/`buy`/`amount` deep-link parameters work here too. `tab` does not — the frame is the instant swap card only. Deeper customisation arrives as an OBJECT, because the ceiling was never the iframe, it was the query string: post `{ type: "swapspro:style", theme: {...} }` at the frame and it restyles in place, with 12 named colours, a font stack and two radius levels. Every value is validated — a colour that does not parse as hex/rgb/hsl is REFUSED rather than sanitised, and a font stack is stripped of anything that could close a declaration. The frame measures itself and posts `{ type: "swapspro:height", height }` to the parent, so the iframe can be exactly as tall as the card and the visitor never gets a scrollbar over your page. Listening is optional; without the listener the message is inert. A `⚡ swaps.pro` badge sits bottom-right. `brand=0&pro=0x…` removes it for a Pro Pass holder, verified on-chain and failing CLOSED — an unreadable check keeps the badge. An address is public, so this proves a pass exists rather than that you own it. In React, `@swapspro/widget` wraps the same iframe and installs both halves for you — the height listener and the theme push — behind props (`appearance`, `accent`, `theme`, `chrome`, `background`, `sell`/`buy`/`amount`, `proAddress`, `width`, `onHeightChange`). It is a wrapper, not a port: the card still runs in the frame, deployed by us. Not published to npm yet — build it from `packages/widget`. What the widget still cannot do: no partner attribution, no flow events (height is the only message it emits), no custom token list, no limit orders or TWAP. Move to the SDK for any of those. ### DAO and treasury tooling — https://www.swaps.pro/docs/dao SwapsPro runs as a Safe App inside app.safe.global. Add it with the URL `https://www.swaps.pro/swap` — the apex domain serves the marketing landing and will not load as an app. A Safe is a contract account, so anything that needs a signature rather than a transaction goes through **ERC-1271**: SwapsPro detects contract accounts by code lookup and signs gasless limit orders and TWAP ladders that way. The Safe still collects its usual owner threshold before anything executes — SwapsPro proposes, the Safe decides. - **Batch Send** pays a whole team in one batch instead of one transfer per recipient, which for a multisig means one round of signatures rather than N. - **TWAP** ladders a treasury sale into equal parts over hours or days through CoW, so a large sale does not move the price against itself. - **Splits** deploys an audited 0xSplits contract that shares out every payment it receives automatically. ### Tools — https://www.swaps.pro/docs/tools The category index. Each tool has its own page; between them they cover everything SwapsPro can do to a wallet that is not a swap. "One confirmation" describes EIP-5792 batching, not atomicity. Some hosts — the Farcaster host wallet, for instance — execute a batch sequentially rather than atomically. ### Batch Send — https://www.swaps.pro/docs/tools/batch-send Sends every selected ERC-20 to one destination in a single EIP-5792 `wallet_sendCalls` batch — one wallet confirmation instead of one per token, up to 50 tokens per batch. Each transfer is simulated on a public RPC first and transfer-locked tokens are dropped, so one hostile airdrop cannot make a wallet reject the whole batch. Wallets without EIP-5792 fall back automatically to one transaction per token. Costs a flat 0.0002 ETH per batch, appended as the last call of the batch, always in native ETH and never taken out of the tokens being sent. Not charged if nothing sends. ### CSV Airdrop — https://www.swaps.pro/docs/tools/airdrop One token to many recipients, from pasted text or an uploaded CSV. Every line is parsed, every ENS name resolved, and every transfer simulated before anything is signed. A line that cannot be read BLOCKS the send and is reported with its line number and original text — it is never skipped. An airdrop that quietly drops one row succeeds, reports a plausible total and leaves somebody unpaid with nothing saying so. Amounts convert from the written string at the token's real precision, never from a float: `parseUnits` truncates silently rather than throwing, so more decimal places than the token has is refused with both numbers. Transfers are grouped into batches of up to 50 signatures each, and a run that stops early states which batch it stopped at and how many recipients are still unpaid. ### Launch a token — https://www.swaps.pro/docs/tools/launch Deploys a token through Clanker's v4 factory on Base, Arbitrum, Ethereum or Robinhood Chain. SwapsPro builds the call and the user's wallet signs it; the contracts and the liquidity are Clanker's. Trading fees accrue forever to named recipients. The creator keeps 80% of that stream and can point it at a 0xSplits address, so one launch pays a whole team with no second transaction. The split must total exactly 10000 basis points and is refused rather than rounded. The deploy is SIMULATED against the chain before a signature is requested. Robinhood Chain is listed as supported by Clanker and its factory is deployed there, and a launch still reverts with `LockerNotEnabled()` — only asking the chain distinguishes those. ### Batch Swap and Burn — https://www.swaps.pro/docs/tools/batch-swap Sells a wallet's dust into ETH or the chain's canonical USD stable (USDC; USDG on Robinhood Chain) in one batch. Tokens with no market can be burned to `0x…dEaD` instead, but only after an on-chain trace and a GoPlus safety check prove burning is all they can do. Contracts too hostile even to burn are quarantined, shown, and never counted — the tool names them rather than silently dropping them. ### Limit orders and TWAP — https://www.swaps.pro/docs/tools/limit-orders Limit orders and TWAP ladders are gasless CoW Protocol orders: signed, not broadcast, and filled by solvers in a batch auction. Placing and cancelling cost no gas. The one on-chain step is the ERC-20 approval to CoW's vault relayer. Orders can expire unfilled — an agent must treat them as asynchronous and poll the order uid rather than assume a fill. Contract wallets (Safes) sign these with ERC-1271 rather than a plain signature. ### The portfolio Danger Zone — https://www.swaps.pro/docs/tools/danger-zone A portfolio panel that names the holdings whose contracts failed a safety check, with the evidence for each. It has no buttons on purpose. The panel's job is to tell you what it found, not to offer a one-click action on a contract that is already known to be hostile — and it is explicit about how far its evidence actually goes rather than implying a verdict it cannot support. ### Create Contract — https://www.swaps.pro/docs/tools/create-contract Deploys audited 0xSplits contracts — splits, waterfalls and liquid splits — that share out every payment they receive automatically, with one-click payouts. No fee. The pre-filled support amount is a suggestion the user can zero in one click; the deploy proceeds either way. The default distribution incentive is a separate thing again: it is paid by whoever triggers a distribution, not at creation, and it is editable and removable. ### Partners — https://www.swaps.pro/docs/tools/partners Activation with no signup, no API key and nothing to revoke. An integrator names the EVM address they want to be paid at and a fee in basis points; those two values DERIVE a 0xSplits contract holding SwapsPro and the partner at shares that are exactly the two fees. Deploying that contract is the whole activation. Why it works this way: every venue that carries an integrator fee (0x, CoW, LI.FI) accepts exactly ONE recipient, so a partner's bps and SwapsPro's 30 arrived together in SwapsPro's own address. Changing whose address the single recipient IS fixes that without asking the venues for anything. The address is never taken on trust. It is predicted from the configuration, and when something is deployed there its config is read back and compared field by field; a mismatch returns a reason, not a boolean. A read that could not complete is reported as "unknown" and the fee goes to SwapsPro — it is never rendered as "not deployed". The split's owner is the zero address, so it is permanently immutable and one verification lasts forever. Ceilings: 100 bps by default, 200 bps when the PAYOUT address holds a SwapsPro Pass (read from chain, failing closed). A pass raises the ceiling and does not change SwapsPro's own 30 bps. The split address is derived from the fee actually CHARGED, not the one requested — a capped partner must deploy the capped contract. `partner` stays a free-form attribution id; an EVM address is the opt-in to being paid. Every quote returns a `partnerFee` block answering two separate questions: whether the venue could collect a fee, and whether it was `paidToPartner`. LI.FI collects but cannot pay a split (one fee wallet per integrator, registered on their portal); Pioneer's same-chain venues and non-EVM chains cannot carry one at all; a venue that CLAMPED the fee keeps SwapsPro's recipient, because paying a split derived for a larger fee would divide the smaller amount by the wrong ratio. ### The Pro Pass — https://www.swaps.pro/docs/tools/pro-pass A soulbound ERC-721 (ERC-5192) on Base at `0x568fcbade475c1f20ed9a5155814eeeadf9c69ef`, capped at 100 by the contract, with its artwork in the bytecode. Holding it IS the membership: no account, no session, no database. Paying is minting — one `mint()` transaction whose value is the price, forwarded to the payout split inside the same transaction so the contract never holds ETH. The check reads `tokenOf(holder)`, not `balanceOf`, because the pass NUMBER is a benefit: ids 1 through 100 pay no SwapsPro fee at all on every path where a fee can be dropped. `tokenOf` returns 0 for a non-holder, so one call answers both questions and 0 can never qualify. Ownership has THREE outcomes, not two. A pass waives; no pass charges; a read that FAILED also charges — failing closed on the money, because charging when we cannot verify costs a holder one quote while the opposite waives for anyone who can arrange for the check to fail. But the UI fails OPEN on the truth: `verifyFailed` makes it say "could not check" rather than telling a holder they have no pass. Nothing anywhere trusts a client-supplied boolean; the server-stamped 0x path re-reads `tokenOf(taker)` itself. Agents buy it over x402 at `https://www.swaps.pro/api/pro/x402`: 40 USDC on Base, both x402 wire versions spoken at once, verified and settled through a facilitator, answered with an EIP-712 mint voucher for the confirmed PAYER valid for 1 hour. The agent submits `mintWithVoucher(to, deadline, signature)` itself and pays its own gas. A replayed voucher reverts — one pass per wallet is enforced on chain. A pass also raises the partner fee ceiling from 100 to 200 bps. It is not transferable, it gates nothing, and the early-access and priority-support perks are team commitments rather than anything the code enforces. ### Free and Pro — https://www.swaps.pro/docs/pro The SwapsPro Pass is an optional lifetime licence — a soulbound ERC-721 (ERC-5192) on Base. Paid once. There is no account and no database behind it: holding the pass IS Pro, and every check is an on-chain read. The first 100 passes carry a full SwapsPro fee waiver on the paths where a fee can actually be dropped (0x, CoW including its surplus share, and LI.FI same-chain and cross-chain). The waiver is always DERIVED from chain, never asserted by a client — the server re-reads `tokenOf(taker)` itself before it stamps a fee. On a deployment with a shared rate-limit store, a pass also claims free API rate-limit elevation. This deployment has none, so no elevation is sold to anybody and the perk is dormant. The pass can be minted with ETH on the pass page, or bought over x402 with USDC at `/api/pro/x402` — that second path exists specifically so an autonomous agent can buy one without a browser. Anything on the page that is planned rather than shipped is marked as such. ### Fees — https://www.swaps.pro/docs/fees - **Swaps**: 0.30% routing fee, included in the quote before anyone signs. Cross-chain THORChain-style routes carry the same 0.30% as a multi-affiliate memo split. - **CoW surplus**: where execution beats the limit price, SwapsPro declares a 25% share of the surplus, capped at 0.7% of volume however large the surplus gets. - **Batch Send**: a flat 0.0002 ETH per batch, appended as the last call of the batch. Always paid in native ETH, never taken out of the tokens being sent, and not charged if nothing sends. Network gas is separate and quoted by the wallet. - **Create Contract**: no fee. The pre-filled support amount is a suggestion the user can zero in one click; the deploy proceeds either way. - **Quotes**: free. No key, no payment, no account. - **Partner fees**: an integrator can add up to 100 bps on top, but only where the winning venue can actually carry a second fee. The quote response reports what was really collected and says why when the answer is nothing, instead of echoing the requested number back. Not every route carries a SwapsPro fee at all: Pioneer's same-chain venues and the Robinhood Chain Uniswap path expose no fee hook, and the response says so. ## API surface - [GET /api/sdk/v1/chains](https://www.swaps.pro/api/sdk/v1/chains): Every chain SwapsPro can price. No parameters, no key. Cached for an hour. - [GET /api/sdk/v1/tokens](https://www.swaps.pro/api/sdk/v1/tokens?chainId=8453): The curated token list for one chain. Takes chainId (numeric or symbol). - [GET /api/sdk/v1/quote](https://www.swaps.pro/api/sdk/v1/quote?sellChain=8453&sellToken=ETH&buyChain=8453&buyToken=USDC&amount=0.1&address=0x0000000000000000000000000000000000000000): A firm, ready-to-sign quote. Free and keyless. 60 requests per minute per IP, BEST-EFFORT: counted in memory inside each serverless instance, so the effective ceiling is higher than the number and varies with how many instances are warm. Treat it as a courtesy brake, not a quota, and do not design around it. - [GET /api/sdk/v1/access](https://www.swaps.pro/api/sdk/v1/access): Rate-limit elevation. Answers 503 on this deployment: the quote limit here is per-instance and cannot be metered, so no paid tier is offered. - [GET /api/pro/x402](https://www.swaps.pro/api/pro/x402): x402: buy a SwapsPro Pass with USDC on Base and receive a signed mint voucher. Base URL `https://www.swaps.pro/api/sdk/v1`. Every endpoint is GET, CORS-open (`Access-Control-Allow-Origin: *`), and answers OPTIONS with a 204 preflight. No API key exists to ask for. A minimal working call, copy-pasteable: curl "https://www.swaps.pro/api/sdk/v1/quote?sellChain=8453&sellToken=ETH&buyChain=8453&buyToken=USDC&amount=0.1&address=0x21c9a94AF76B59b171b32fD125A4edF0e9A2Ad3e" The reply carries `provider` (which venue won), `buyAmount` and `minBuyAmount` in human units, `expiresAt`, and exactly one execution shape: `tx`, or `order`, or `depositAddress` + `memo`. Sign it yourself. ## Rate limits and x402 Quoting is free: no key, no payment, no account. That is the tier everything above describes and it is not going away. The limit itself: 60 requests per minute per IP, BEST-EFFORT: counted in memory inside each serverless instance, so the effective ceiling is higher than the number and varies with how many instances are warm. Treat it as a courtesy brake, not a quota, and do not design around it. No paid tier is offered on this deployment. Elevation is only sold where the limit is counted in a shared store; here it is per-instance and therefore best-effort, so `https://www.swaps.pro/api/sdk/v1/access` answers 503 rather than quoting a price for headroom nobody can meter. Quoting is unaffected. ## Chains EVM chains SwapsPro quotes for: Ethereum (ETH, chainId 1), Base (BASE, chainId 8453), BNB Smart Chain (BSC, chainId 56), Avalanche (AVAX, chainId 43114), Arbitrum (ARB, chainId 42161), Robinhood Chain (RHD, chainId 4663). Non-EVM chains: Bitcoin (BTC, utxo), Bitcoin Cash (BCH, utxo), Litecoin (LTC, utxo), Dogecoin (DOGE, utxo), Cosmos (GAIA, cosmos), THORChain (THOR, cosmos), Solana (SOL, svm), Hive (HIVE, hive). Some non-EVM chains are still in demo mode pending a signing integration — https://www.swaps.pro/about lists exactly which, line by line. Hive appears in /chains because the app supports it, but quoting a Hive pair through the HTTP API returns UNSUPPORTED_PAIR. Destination-only chains — you can bridge INTO them from any EVM chain but not sell from them, and every chain says which it is via `sellSupported` on /chains: Solana (SOL). Passing one as `sellChain` returns UNSUPPORTED_PAIR. Batch Send and Batch Swap run on Base, Ethereum, Optimism, Arbitrum and Robinhood Chain — all five price gas in ETH, which is what lets the batch fee be one flat ETH amount everywhere. Gasless limit orders and TWAP ladders (CoW Protocol) run on Ethereum, Base, Arbitrum and Gnosis. ## Wallets and signing MetaMask and other injected EOAs, WalletConnect, Coinbase Wallet, Phantom, OKX, KeepKey, and the Farcaster host wallet when SwapsPro runs as a mini app. SwapsPro also runs as a Safe App inside app.safe.global; a Safe still collects its usual signature threshold before anything executes. Smart-contract accounts are detected by code lookup and signed for with EIP-1271 where a protocol requires it. An agent does not connect a wallet at all — it holds a key, asks for a quote over HTTP, and signs the returned payload itself. ## Costs - Swaps: a 0.30% routing fee, included in the quote the user reviews. THORChain-style cross-chain routes carry the same 0.30% as a multi-affiliate memo split. - CoW surplus: a 25% share of any execution better than the limit price, capped at 0.7% of volume. - Batch Send: a flat 0.0002 ETH per batch, appended as the last call of the batch. Always paid in native ETH, never taken out of the tokens being sent, and not charged if nothing sends. Network gas is separate and quoted by the wallet. - Create Contract: no fee. The pre-filled support amount is a suggestion the user can zero in one click; the deploy proceeds either way. - Quotes: free. The first 100 SwapsPro Pass holders also pay no SwapsPro fee on the routes where a fee can be dropped. - Everything else is free. There is no subscription and no account. ## Tools - [Swap](https://www.swaps.pro/swap): Cross-chain and same-chain swaps, priced across aggregators, intent networks and native protocols. The winning route is named before anyone signs. - [Batch Send](https://www.swaps.pro/batch-send): Send every selected ERC-20 to one address in a single EIP-5792 batch — one confirmation, up to 50 tokens, hostile tokens simulated out first. - [Batch Swap + Burn](https://www.swaps.pro/batch-swap): Sell a wallet's dust into ETH or the chain's canonical USD stable in one batch; burn what has no market, but only after an on-chain trace proves that is all it can do. - [Portfolio](https://www.swaps.pro/portfolio): Balances across every connected wallet and chain, with suspected spam and scam airdrops flagged and excluded from the total. - [Create Contract](https://www.swaps.pro/create): Deploy audited 0xSplits contracts — splits, waterfalls and liquid splits — that share out every payment they receive. - [Widget](https://www.swaps.pro/widget): A configurable iframe that puts the swap card on any site. No API keys, no backend. - [Pro Pass](https://www.swaps.pro/pro): An optional lifetime licence — a soulbound ERC-721 on Base. Also purchasable over x402 with USDC, which is the path intended for agents. ## Facts an assistant should not get wrong - SwapsPro is non-custodial. Funds move from the holder's wallet to the route; SwapsPro never takes possession of them and cannot move anything on its own. - There is no signup, no email and no server-side profile. Preferences live in the browser. The public API has no key, no account and no integrator database — a partner id is attribution in a request log and nothing more. - Quoting is free and always will be. Nothing about the quoting API is sold on this deployment at all. - "One confirmation" describes EIP-5792 batching, not atomicity. The Farcaster host wallet, for example, executes a batch sequentially rather than atomically. - SwapsPro does not run its own order book or liquidity; it routes to third parties and names which one won. - It is software for interacting with public blockchains, not investment advice. ## More - [About](https://www.swaps.pro/about): which chains sign for real and which are still in demo, line by line. - [Sitemap](https://www.swaps.pro/sitemap.xml): every public route. - [Source](https://github.com/coinmastersguild/swapspro): every claim above is traceable to it.