Monero to USDC swap API
Quote, open and track XMR ⇄ USDC swaps on Arbitrum One from your backend, bot or AI agent: a public HTTPS API and a remote MCP server, with no API key, no account and no KYC. Swapper never holds funds.
https://xmrtousdc.xyz/api/v1
https://xmrtousdc.xyz/mcp
A quote in one call
A quote needs no key and creates nothing. Pass direction (x2u sells XMR, u2x buys XMR) and amount, what the user sends, as a decimal string (digits and one dot):
curl -sS https://xmrtousdc.xyz/api/v1/agent/swap/quote \
-H "content-type: application/json" \
-d '{"direction":"x2u","amount":"0.8","to":"0xYOUR_ARBITRUM_ADDRESS"}'
What to read in the response:
data.quoteId,data.expiresAtanddata.expiresInSec: the order must be created within the 300-second acceptance window, or you quote again.data.terms.receive.estimate: the estimated output with every fee inside.guaranteed: false: the provider publishes no minimum receive amount (receive.minimumis null), so the final amount is set when the swap runs.data.terms.fees.integratorFee: Swapper's fee (currently 1%), already inside the rate.data.terms.minimumSwapUsd,minimumSendEstimateandbelowProviderMinimum: the provider's minimum; create refuses a quote below it.data.prerequisites(USDC senders): native USDC plus ETH for gas on Arbitrum One, before any order exists.
Know what the user wants to receive? Send receiveAmount instead of amount, with direction: "u2x", and Swapper finds the USDC to send:
curl -sS https://xmrtousdc.xyz/api/v1/agent/swap/quote \
-H "content-type: application/json" \
-d '{"direction":"u2x","receiveAmount":"1","to":"YOUR_MONERO_ADDRESS"}'
Open the order and track it
Create the order from the quote alone, with an idempotency-key header: a new random UUID per order, reused only to retry that same create. No confirmation step is required.
KEY=$(uuidgen) # a new random key per order; reuse it only to retry this create
curl -sS https://xmrtousdc.xyz/api/v1/agent/swap/create \
-H "content-type: application/json" \
-H "idempotency-key: $KEY" \
-d '{"quoteId":"QUOTE_ID"}'
The response carries data.order.orderId, data.destination (the payout address recorded with the order), data.payable, data.deposit (one-time address, exact amount, expiry) and, while payable is true, data.deposit.payment: a wallet-ready transfer (a monero: URI, or an EIP-681 link plus an unsigned ERC-20 transaction). Send it once, unchanged, only if data.destination is the user's own address. Then long-poll the status until terminal is true:
curl -sS "https://xmrtousdc.xyz/api/v1/agent/swap/status/ORDER_ID?waitSec=25&sinceState=waiting_for_funding"
Core endpoints
| Method | Path | Purpose |
|---|---|---|
| GET | /api/v1/agent/quickstart | Discovery, trust metadata, example calls (always reachable). |
| GET | /api/v1/agent/capabilities | Directions, live chains, defaults, validation rules, limits, funding pointer. |
| POST | /api/v1/agent/swap/quote | Estimate a swap: {direction, amount | receiveAmount, to?, chain?}, or {requoteOf} to re-quote; returns quoteId + terms (an estimate, not guaranteed; no published minimum), valid 300 s. |
| POST | /api/v1/agent/swap/create | {quoteId} (+ to if the quote had none) and a required idempotency-key; no confirmation step is required. Returns payable, deposit (payment only while payable), destination, origin, trackUrl. |
| GET | /api/v1/agent/swap/status/{orderId} | Live order state, payable, evidence, attention and next; ?waitSec=0..25&sinceState= long-polls for the next change. |
| GET | /api/v1/agent/swap/orders | Find my swaps: ?idempotencyKey= (the create key) or ?sessionId= (addresses redacted). |
| GET | /api/v1/chains | Chain list incl. minSwapUsd per chain (the provider minimum recent quotes reported; null when none is known). |
Every endpoint, error code and order state, with a full JavaScript loop and a system prompt for your agent: REST API reference.
Connect an AI agent over MCP
Agents in MCP clients get the same flow as tools (get_quote, create_swap, get_swap_status, get_funding_options, list_swaps, plan_swap, get_capabilities, create_support_ticket), with no key and no OAuth:
| Client | Setup |
|---|---|
| Claude Code | claude mcp add --transport http swapper https://xmrtousdc.xyz/mcp |
| Claude (claude.ai and Claude Desktop) | Customize -> Connectors -> + Add -> Add custom connector -> https://xmrtousdc.xyz/mcp (Authentication: No sign in) |
| ChatGPT | chatgpt.com/plugins -> + -> Add custom MCP server -> Server URL https://xmrtousdc.xyz/mcp, No authentication -> Create as a plugin |
| Cursor | ~/.cursor/mcp.json: { "mcpServers": { "swapper": { "url": "https://xmrtousdc.xyz/mcp" } } } |
| VS Code | .vscode/mcp.json: { "servers": { "swapper": { "type": "http", "url": "https://xmrtousdc.xyz/mcp" } } } |
| Codex CLI | codex mcp add swapper --url https://xmrtousdc.xyz/mcp |
| Gemini CLI | gemini mcp add --transport http swapper https://xmrtousdc.xyz/mcp |
| Devin Desktop (formerly Windsurf) | mcp_config.json: { "mcpServers": { "swapper": { "serverUrl": "https://xmrtousdc.xyz/mcp" } } } |
| Stdio-only clients (mcp-remote) | { "command": "npx", "args": ["-y", "mcp-remote", "https://xmrtousdc.xyz/mcp"] } |
Step-by-step setup for each client, the prompts, an example conversation and the safety model: Monero MCP server.
Rules for a safe integration
- Amounts are decimal strings with digits and one dot (
"0.5", never"0,5"or"0.5 XMR"). Never invent or guess addresses or amounts. - Each quote opens at most one order. A new order needs a new quote and a new idempotency key; a retry reuses both.
- Fund only while
payableis true, exactly once, and read the status before showing a deposit again. Paying from an agent's wallet: Agent wallets. - Honor
429andRetry-After; long-poll status instead of polling fast. - Never ask for seed phrases or private keys: Swapper never needs them.
Machine-readable docs
- OpenAPI 3.1 (base
https://xmrtousdc.xyz/api/v1) and llms-full.txt, everything an LLM needs to run a swap, in one file. - Quickstart JSON and capabilities: directions, live chains, limits, validation rules.
- MCP server card (registry name
xyz.xmrtousdc/monero-swap). - autonomous-agent.mjs: a runnable agent (Node 20+, no dependencies) that quotes, creates and checks the payment, and stops before signing unless you plug in a wallet adapter.
Questions
Do I need an API key or an account?
No. The API and the MCP server are public: no key, no account, no KYC. Requests are rate limited per IP; on HTTP 429, wait for Retry-After and retry the same call.
Does the API hold or move funds?
No. Creating an order only returns deposit instructions; nothing moves until a wallet signs the deposit (the user's own, or an agent's wallet acting for the user). Swapper never holds your funds. Each order gets a one-time deposit address from the swap provider, which holds the deposit only while the swap executes, then pays out (or refunds).
Can an AI agent run a swap on its own?
Yes. No step waits for a person: an agent may quote, create and fund an order on its own. Funds move only when the sender's wallet signs, only while the order is payable and, over MCP, after Swapper's paymentCheck confirms the transfer is exactly the deposit.
REST or MCP?
Both run the same flow against the same orders. MCP suits agents in MCP clients (Claude, ChatGPT, Cursor and others); REST suits backends, bots and scripts. An order created over one can be found and tracked over the other.
What does it cost to use the API?
Calls are free. Swapper earns an integrator fee that is already included in the quoted rate (currently 1%; every quote states it in terms.fees.integratorFee). Nothing is added on top of the quote apart from the network fee for sending the deposit.
Which networks and assets are supported?
Monero (XMR) on the Monero network and native USDC on Arbitrum One (chain ID 42161, contract 0xaf88d065e77c8cC2239327C5EDb3A432268e5831), in both directions. GET /api/v1/agent/capabilities lists the live chains, defaults and validation rules.
Is the API available everywhere?
No. Requests from restricted regions, currently including the United States, receive HTTP 451 (geo_blocked) on trading endpoints; discovery endpoints such as the quickstart stay reachable.
Integration help: agent@xmrtousdc.xyz. Swapping by hand instead? Monero to USDC · USDC to Monero.