Validate a MultiversX pair, request a swap quote, and verify the response fields needed before signing.
Prerequisites
| Requirement | Value |
|---|
| Base URL | https://swap.xoxno.com |
| Auth | None |
| Rate limit | 100 requests per second per IP |
| Amount format | Integer strings in the token’s smallest unit |
1. Validate The Pair
Call /api/v1/pair-config before quoting so your client has decimals and minimum input.
cURL
TypeScript
Python
Rust
curl "https://swap.xoxno.com/api/v1/pair-config?\
from=WEGLD-bd4d79&\
to=USDC-c76f1f"
const pairRes = await fetch(
"https://swap.xoxno.com/api/v1/pair-config?from=WEGLD-bd4d79&to=USDC-c76f1f"
);
if (!pairRes.ok) throw new Error(`pair check failed: ${pairRes.status}`);
const pair = await pairRes.json();
if (!pair.supported) throw new Error(pair.error);
console.log(pair.decimalsIn, pair.decimalsOut, pair.minAmountIn);
import requests
res = requests.get(
"https://swap.xoxno.com/api/v1/pair-config",
params={"from": "WEGLD-bd4d79", "to": "USDC-c76f1f"},
timeout=10,
)
res.raise_for_status()
pair = res.json()
if not pair["supported"]:
raise RuntimeError(pair["error"])
print(pair["decimalsIn"], pair["decimalsOut"], pair["minAmountIn"])
// Run inside an async function with reqwest and serde_json.
let pair: serde_json::Value = reqwest::Client::new()
.get("https://swap.xoxno.com/api/v1/pair-config")
.query(&[("from", "WEGLD-bd4d79"), ("to", "USDC-c76f1f")])
.send()
.await?
.error_for_status()?
.json()
.await?;
if pair["supported"] != true {
return Err(format!("pair unsupported: {}", pair["error"]).into());
}
println!(
"{} {} {}",
pair["decimalsIn"], pair["decimalsOut"], pair["minAmountIn"]
);
Expected response:
{
"supported": true,
"decimalsIn": 18,
"decimalsOut": 6,
"minAmountIn": "1000000000"
}
2. Request A Quote
Quote 1 WEGLD to USDC. 1000000000000000000 is 1 WEGLD at 18 decimals.
cURL
TypeScript
Python
Rust
curl "https://swap.xoxno.com/api/v1/quote?\
from=WEGLD-bd4d79&\
to=USDC-c76f1f&\
amountIn=1000000000000000000&\
slippage=0.005"
const params = new URLSearchParams({
from: "WEGLD-bd4d79",
to: "USDC-c76f1f",
amountIn: "1000000000000000000",
slippage: "0.005",
});
const quoteRes = await fetch(`https://swap.xoxno.com/api/v1/quote?${params}`);
if (!quoteRes.ok) throw new Error(`quote failed: ${quoteRes.status}`);
const quote = await quoteRes.json();
console.log(quote.amountOut, quote.amountOutMin, quote.priceImpact);
import requests
res = requests.get(
"https://swap.xoxno.com/api/v1/quote",
params={
"from": "WEGLD-bd4d79",
"to": "USDC-c76f1f",
"amountIn": "1000000000000000000",
"slippage": "0.005",
},
timeout=10,
)
res.raise_for_status()
quote = res.json()
print(quote["amountOut"], quote["amountOutMin"], quote["priceImpact"])
// Run inside an async function with reqwest and serde_json.
let quote: serde_json::Value = reqwest::Client::new()
.get("https://swap.xoxno.com/api/v1/quote")
.query(&[
("from", "WEGLD-bd4d79"),
("to", "USDC-c76f1f"),
("amountIn", "1000000000000000000"),
("slippage", "0.005"),
])
.send()
.await?
.error_for_status()?
.json()
.await?;
println!(
"{} {} {}",
quote["amountOut"], quote["amountOutMin"], quote["priceImpact"]
);
Inspect these fields:
| Field | Use |
|---|
amountOut | Smallest-unit output estimate. |
amountOutMin | Slippage-protected minimum output. |
amountOutShort | Display amount for the output token. |
priceImpact | Decimal price impact estimate. |
3. Request Transaction Data
Pass sender only when the user is ready to sign.
curl "https://swap.xoxno.com/api/v1/quote?\
from=WEGLD-bd4d79&\
to=USDC-c76f1f&\
amountIn=1000000000000000000&\
slippage=0.005&\
sender=erd1..."
The response can include:
| Field | Meaning |
|---|
transaction | Full MultiversX transaction object for wallet signing. |
txData | Encoded contract call data when a full transaction object is not returned. |
Do not reuse txData across quote requests. It encodes route and slippage state from that request.
Verify
You have a valid quickstart result when:
/api/v1/pair-config returns supported: true.
amountIn is greater than or equal to minAmountIn.
/api/v1/quote returns non-zero amountOut.
amountOutMin matches the slippage shown to the user.
- If
transaction is present, transaction.sender matches the connected wallet.
Common Failure
| Symptom | Cause | Fix |
|---|
Quote returns 400 | Both amountIn and amountOut were sent, or neither was sent. | Send exactly one amount field. |
| Pair is unsupported | Token is unknown or no route exists. | Stop before quoting and show error from pair config. |
| Signed transaction fails for ESDT input | Client used txData as the full data field. | Use the full transaction object, or wrap txData in the ESDT transfer prefix. |
Next Steps