Skip to main content

Swap

Cross-chain swaps between any supported assets including Monero (XMR).

API Key Optional

API key is only required if you want to collect integrator fees. Without an API key, swaps work normally but no fees are collected.

Quick Start

# 1. Get a quote
curl -X POST https://api.wagyu.xyz/v1/quote \
-H "Content-Type: application/json" \
-H "X-API-KEY: wg_your_api_key" \
-d '{
"fromChainId": 42161,
"toChainId": 0,
"fromToken": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
"toToken": "XMR",
"fromAmount": "100000000"
}'

# 2. Create order
curl -X POST https://api.wagyu.xyz/v1/order \
-H "Content-Type: application/json" \
-H "X-API-KEY: wg_your_api_key" \
-d '{
"fromChainId": 42161,
"toChainId": 0,
"fromToken": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
"toToken": "XMR",
"fromAmount": "100000000",
"toAddress": "4AdUndXHHZ..."
}'

# 3. User sends funds to depositAddress

# 4. Poll status until completed
curl https://api.wagyu.xyz/v1/order/ABC123 \
-H "X-API-KEY: wg_your_api_key"

Endpoints

Get Supported Chains

Returns all supported chains and their configurations.

GET /v1/chains

Response:

{
"chains": [
{
"chainId": 42161,
"name": "Arbitrum",
"nativeToken": "ETH",
"minSwapUsd": 20
},
{
"chainId": 1151111081099710,
"name": "Solana",
"nativeToken": "SOL",
"minSwapUsd": 20
},
{
"chainId": 0,
"name": "Monero",
"nativeToken": "XMR",
"minSwapUsd": 25
}
]
}

XML Rates Feed

XML feed generated from Wagyu backend quote simulation.

GET /rates.xml

Response Headers:

HeaderValue
Content-Typeapplication/xml; charset=utf-8
Cache-Controlpublic, max-age=30

Current pair coverage:

  • USDTARBITRUM -> XMR
  • USDCARBITRUM -> XMR
  • ETHARBITRUM -> XMR
  • WBTCARBITRUM -> XMR
  • XMR -> USDTARBITRUM
  • XMR -> USDCARBITRUM
  • XMR -> ETHARBITRUM

Each <item> is one simulated quote sample and includes <from>, <to>, <in>, <out>, <amount>, <tofee>, <minamount>, <maxamount>, <exchange>, and optional <eta>.

Example Response:

<?xml version="1.0" encoding="UTF-8"?>
<rates>
<item>
<from>USDTARBITRUM</from>
<to>XMR</to>
<in>100</in>
<out>0.3054</out>
<amount>0.3054</amount>
<tofee>0 XMR</tofee>
<minamount>25 USDTARBITRUM</minamount>
<maxamount>100 USDTARBITRUM</maxamount>
<exchange>Wagyu</exchange>
<eta>6 min</eta>
</item>
</rates>

Get Quote

Get an estimated exchange rate and output amount.

POST /v1/quote

Headers:

HeaderRequiredDescription
Content-TypeYesapplication/json
X-API-KEYNoYour API key (for fee collection)

Request Body:

FieldTypeRequiredDescription
fromChainIdnumberYesSource chain ID (0 = Monero)
toChainIdnumberYesDestination chain ID (0 = Monero)
fromTokenstringYesToken address or "XMR"
toTokenstringYesToken address or "XMR"
fromAmountstringYesAmount in smallest units

Example Request:

curl -X POST https://api.wagyu.xyz/v1/quote \
-H "Content-Type: application/json" \
-d '{
"fromChainId": 42161,
"toChainId": 0,
"fromToken": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
"toToken": "XMR",
"fromAmount": "100000000"
}'

Response:

{
"fromAmount": "100000000",
"fromAmountUsd": "100.00",
"fromSymbol": "USDC",
"toAmount": "156250000000",
"toAmountUsd": "98.50",
"toSymbol": "XMR",
"estimatedTime": 300,
"minReceived": "0.1523"
}
note

If you include an API key with a configured fee, the response will also include an integratorFee field showing the fee that will be collected.


Create Order

Create a new swap order and get a deposit address.

POST /v1/order

Headers:

HeaderRequiredDescription
Content-TypeYesapplication/json
X-API-KEYNoYour API key (for fee collection)

Request Body:

FieldTypeRequiredDescription
fromChainIdnumberYesSource chain ID
toChainIdnumberYesDestination chain ID
fromTokenstringYesToken address or "XMR"
toTokenstringYesToken address or "XMR"
fromAmountstringYesAmount in smallest units
toAddressstringYesDestination address for output
sessionIdstringNoUUID v4 session ID for order history (generated if not provided)
twapConfigobjectNoCustom TWAP settings (XMR orders only)

twapConfig Object (XMR orders only):

FieldTypeDescription
disabledbooleanDisable TWAP, use market orders only (default: false)
chunkSizeUsdnumberChunk size in USD (min 250, default: 5000)
intervalMsnumberInterval between chunks in ms (1000-60000, default: 8000)

Example Request:

curl -X POST https://api.wagyu.xyz/v1/order \
-H "Content-Type: application/json" \
-d '{
"fromChainId": 42161,
"toChainId": 0,
"fromToken": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
"toToken": "XMR",
"fromAmount": "100000000",
"toAddress": "4AdUndXHHZ6ieMLmq4D2qSohBXCQSTGL5yzpPw5EfU8hTJEPHWPmZx7s6Hb2wTv3Se7S1VQqNsLstUHCMMGFKZKaCUBthxR"
}'

Example with custom TWAP (for XMR orders):

curl -X POST https://api.wagyu.xyz/v1/order \
-H "Content-Type: application/json" \
-d '{
"fromChainId": 42161,
"toChainId": 0,
"fromToken": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
"toToken": "XMR",
"fromAmount": "50000000000",
"toAddress": "4AdUndXHHZ...",
"twapConfig": {
"chunkSizeUsd": 20000,
"intervalMs": 10000
}
}'

Example disabling TWAP (market orders only):

curl -X POST https://api.wagyu.xyz/v1/order \
-H "Content-Type: application/json" \
-d '{
"fromChainId": 42161,
"toChainId": 0,
"fromToken": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
"toToken": "XMR",
"fromAmount": "50000000000",
"toAddress": "4AdUndXHHZ...",
"twapConfig": {
"disabled": true
}
}'

Response:

{
"orderId": "F9B6RT",
"depositAddress": "0xc2294EDad11418Fd1dEff00746F247112c12F5BB",
"depositChain": "Arbitrum",
"depositChainId": 42161,
"depositToken": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
"depositTokenSymbol": "USDC",
"depositAmount": "100000000",
"toAddress": "4AdUndXHHZ...",
"expectedOutput": "156250000000",
"expiresAt": "2026-01-19T14:00:00.000Z",
"status": "awaiting_deposit"
}
Important

Send exactly depositAmount of depositTokenSymbol to depositAddress on chain depositChainId.


Get Order Status

Check the status of an existing order.

GET /v1/order/:orderId

Query Parameters:

ParameterTypeRequiredDescription
verifystringNoDestination address for verification (see Security below)

Example Request:

curl https://api.wagyu.xyz/v1/order/F9B6RT

Example with verification:

curl "https://api.wagyu.xyz/v1/order/F9B6RT?verify=4AdUndXHHZ..."
Security

To prevent unauthorized access to order details, you can optionally provide the destination address as a verify query parameter. If the provided address doesn't match the order's destination address, the API returns a 403 error. This is useful when sharing order links - users must know the destination address to view the order.


Get Order History

Get all orders for a session.

GET /v1/orders?session=<SESSION_ID>

Query Parameters:

ParameterTypeRequiredDescription
sessionstringYesSession ID (UUID v4 returned when creating order)

Example Request:

curl "https://api.wagyu.xyz/v1/orders?session=550e8400-e29b-41d4-a716-446655440000"

Response:

{
"orders": [
{
"id": "F9B6RT",
"from_chain_id": 42161,
"from_token_symbol": "USDC",
"from_amount": "100000000",
"to_chain_id": 0,
"to_token_symbol": "XMR",
"to_amount_expected": "156250000000",
"to_address": "4AdUndXHHZ...",
"status": "completed",
"created_at": "2026-01-19T12:00:00.000Z",
"completed_at": "2026-01-19T12:05:23.000Z"
}
]
}
Session Management

The sessionId is returned when you create an order. Store it in localStorage to track all orders created from the same browser. If a user loses their session ID, they can still access individual orders using the verify parameter with their destination address.


Response (completed order):

{
"orderId": "F9B6RT",
"status": "completed",
"depositAddress": "0xc2294EDad11418...",
"depositChainId": 42161,
"depositTokenSymbol": "USDC",
"depositAmount": "100000000",
"depositTxHash": "0x4a8b2c...",
"toAddress": "4AdUndXHHZ...",
"expectedOutput": "156250000000",
"actualOutput": "155890000000",
"createdAt": "2026-01-19T12:00:00.000Z",
"completedAt": "2026-01-19T12:05:23.000Z"
}

Response (refunded order):

{
"orderId": "DX432K",
"status": "refunded",
"depositAddress": "bc1qy9epejgvcegjh6q2nsypzpeunnfe0vm0t9c07h",
"depositChainId": 20000000000001,
"depositTokenSymbol": "BTC",
"depositAmount": "24917839",
"depositTxHash": "cb16de60d94c6ecb0aa3...",
"errorMessage": "All bridge routes rejected your transaction. Please try again later or with a different amount.",
"refundTxHash": "7a3b8c9d2e1f...",
"createdAt": "2026-01-20T17:10:00.000Z"
}

Order Statuses:

StatusDescription
awaiting_depositWaiting for user to send funds
deposit_detectedDeposit seen, waiting for confirmations
deposit_confirmedDeposit confirmed, processing
executing_swapSwap in progress
completedSwap completed successfully
refundingSwap could not be completed, refund in progress
refundedFunds have been returned to the user
failedSwap failed (see errorMessage)
expiredNo deposit received within 2 hours
Refunding Orders

When a swap cannot be completed (e.g., all bridge routes rejected the transaction), the order enters refunding status and funds are automatically returned to the original sender. The errorMessage field contains the reason for the refund. Once complete, status changes to refunded and refundTxHash contains the refund transaction hash.


Integrator Fees (Optional)

If you're building an integration and want to earn fees, you can create an API key with a fee percentage.

note

API keys are only required for fee collection. Without an API key, swaps work normally with no fees.

How It Works

  1. Create an API key at wagyu.xyz/api
  2. Configure your fee percentage (0-5%) and payout addresses
  3. Include your API key in requests via X-API-KEY header
  4. Your fee is automatically deducted from deposits and sent to your address

Fee Configuration

SettingTypeDescription
fee_percentnumberFee percentage (0-5%)
fee_addressstringEVM address for fees (required)
fee_address_solstringSolana address for fees (required for Solana swaps)
fee_address_btcstringBitcoin address for fees (optional, for BTC swaps)
Address requirements

Provide all three fee addresses to collect fees on every chain:

  • fee_address (EVM) — required for EVM and XMR swaps
  • fee_address_sol (Solana) — required for Solana swaps
  • fee_address_btc (Bitcoin, optional) — required for Bitcoin swaps

If a fee address is missing for a chain, fees on that chain will be skipped.

Fee Collection by Chain

Source ChainFee Collected InSent To
EVM (Arbitrum, etc.)Deposited token (USDC, ETH, etc.)fee_address
SolanaDeposited token (SOL, SPL tokens)fee_address_sol
BitcoinBTC (before swap)fee_address_btc
Monero (XMR → Any)USDC on Hyperliquid (after conversion)fee_address

Fee Thresholds

Fees are only collected if the fee amount exceeds the transaction cost. For very small swaps, the fee may be skipped if it's not economically viable to send (the gas cost would exceed the fee value).

Quote Response with Fee

When you include an API key with a configured fee, the /v1/quote response includes fee details:

{
"fromAmount": "100000000",
"toAmount": "156250000000",
"integratorFee": {
"percent": 1,
"amount": "1000000",
"amountUsd": "1.00"
}
}

Tracking Your Fees

You can view your collected fees and statistics in the API Dashboard after connecting your wallet.


TWAP Execution (XMR Orders)

For large XMR orders, TWAP (Time-Weighted Average Price) execution is used to minimize slippage by splitting orders into smaller chunks executed over time on Hyperliquid's XMR1/USDC orderbook.

Why TWAP?

Large market orders can cause significant slippage due to limited orderbook depth. TWAP splits your order into smaller chunks executed over time, achieving a better average price.

Example: A $50,000 XMR buy executed all at once might get 2-3% slippage. With TWAP (10 chunks of $5k each, 8 seconds apart), you typically see <0.5% slippage.

Automatic TWAP Thresholds

TWAP is automatically enabled when order size exceeds:

DirectionThresholdDefault Chunk Size
XMR → Any (sell)> $5,0006 XMR (~$3,600 at $600/XMR)
Any → XMR (buy)> $25,000$5,000 USD

Orders below these thresholds use instant market orders.

Custom TWAP Configuration

You can customize TWAP behavior by including twapConfig in your order request:

{
"twapConfig": {
"disabled": false,
"chunkSizeUsd": 20000,
"intervalMs": 10000
}
}
SettingRangeDefaultDescription
disabledbooleanfalseSkip TWAP entirely, use market orders regardless of size
chunkSizeUsdmin 2505000Size of each chunk in USD
intervalMs1000-600008000Time between chunks in milliseconds

Chunk Size Examples

Chunk SizeBest ForTrade-off
$250Maximum price precision, thin liquidityLongest execution time
$1,000High precisionLonger execution time
$5,000Balanced (default)Good for most orders
$20,000Large orders, moderate liquidityFaster, slightly more slippage
$50,000+Very large orders, good liquidityFast execution, more slippage
tip

If you set chunk size larger than your order (e.g., $100k chunk for $10k order), the entire order executes in one market order.

Disabling TWAP

If you want immediate execution regardless of order size (accepting potential slippage), set disabled: true:

{
"twapConfig": {
"disabled": true
}
}

This forces a single market order for the full amount.

TWAP Status in Order Response

When TWAP is active, the order status response includes detailed progress:

{
"orderId": "ABC123",
"status": "executing_swap",
"twap": {
"enabled": true,
"status": "active",
"chunksCompleted": 3,
"chunksTotal": 10,
"filledQty": 15000,
"totalQty": 50000,
"chunkSizeUsd": 5000,
"intervalMs": 8000,
"estimatedTimeRemainingMs": 56000
}
}
FieldDescription
statuspending, active, completed, or failed
chunksCompletedNumber of chunks executed
chunksTotalTotal chunks planned
filledQtyUSD value already filled
totalQtyTotal USD value to fill
estimatedTimeRemainingMsEstimated time until completion

View the Orderbook

You can view the live XMR1/USDC orderbook to understand current liquidity:

app.wagyu.xyz/trade?market=XMR/USDC

XMR Orders Only

TWAP configuration only applies to orders involving XMR. For other swaps (e.g., ETH → USDC), this parameter is ignored.


Common Token Addresses

Arbitrum (42161)

TokenAddress
USDC0xaf88d065e77c8cC2239327C5EDb3A432268e5831
USDT0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9
ETH0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE

Solana (1151111081099710)

TokenAddress
SOL11111111111111111111111111111111
USDCEPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v

Monero (0)

TokenAddress
XMRXMR

Code Examples

JavaScript/Node.js

const API_KEY = 'wg_your_api_key';
const BASE_URL = 'https://api.wagyu.xyz';

async function createSwap(fromChainId, toChainId, fromToken, toToken, fromAmount, toAddress) {
const response = await fetch(`${BASE_URL}/v1/order`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-KEY': API_KEY,
},
body: JSON.stringify({
fromChainId,
toChainId,
fromToken,
toToken,
fromAmount,
toAddress,
}),
});

return response.json();
}

async function getOrderStatus(orderId) {
const response = await fetch(`${BASE_URL}/v1/order/${orderId}`, {
headers: { 'X-API-KEY': API_KEY },
});

return response.json();
}

// Example: Swap 100 USDC on Arbitrum to XMR
const order = await createSwap(
42161, // Arbitrum
0, // Monero
'0xaf88d065e77c8cC2239327C5EDb3A432268e5831', // USDC
'XMR',
'100000000', // 100 USDC (6 decimals)
'4AdUndXHHZ...' // XMR address
);

console.log('Deposit', order.depositAmount, order.depositTokenSymbol);
console.log('To:', order.depositAddress);

Python

import requests

API_KEY = 'wg_your_api_key'
BASE_URL = 'https://api.wagyu.xyz'

def create_swap(from_chain, to_chain, from_token, to_token, amount, to_address):
response = requests.post(
f'{BASE_URL}/v1/order',
headers={
'Content-Type': 'application/json',
'X-API-KEY': API_KEY,
},
json={
'fromChainId': from_chain,
'toChainId': to_chain,
'fromToken': from_token,
'toToken': to_token,
'fromAmount': amount,
'toAddress': to_address,
}
)
return response.json()

def get_order_status(order_id):
response = requests.get(
f'{BASE_URL}/v1/order/{order_id}',
headers={'X-API-KEY': API_KEY}
)
return response.json()

# Example: Swap 100 USDC on Arbitrum to XMR
order = create_swap(
42161, # Arbitrum
0, # Monero
'0xaf88d065e77c8cC2239327C5EDb3A432268e5831', # USDC
'XMR',
'100000000', # 100 USDC
'4AdUndXHHZ...' # XMR address
)

print(f"Send {order['depositAmount']} {order['depositTokenSymbol']} to {order['depositAddress']}")