INTEGRATION_GUIDE_EN
Base URL:
https://api.crosscurve.fiSwagger UI: https://api.crosscurve.fi/api-docs/ General Documentation: https://docs.crosscurve.fi
Quick Start
Minimum Integration Flow
Example: Swap CRV (Ethereum) → CRV (Arbitrum)
Example for understanding the flow. Verify current addresses via
/tokenlist.
import { ethers } from 'ethers';
const API_BASE = 'https://api.crosscurve.fi';
// Initialize provider and signer (example for browser with MetaMask)
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
// 1. Find route
const routeResponse = await fetch(`${API_BASE}/routing/scan`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
params: {
chainIdIn: 1, // Ethereum
chainIdOut: 42161, // Arbitrum
tokenIn: '0xD533a949740bb3306d119CC777fa900bA034cd52', // CRV on Ethereum
tokenOut: '0x11cDb42B0EB46D95f990BeDD4695A6e3fA034978', // CRV on Arbitrum
amountIn: '1000000000000000000000' // 1000 CRV (18 decimals)
},
slippage: 1 // 1%
})
});
const routes = await routeResponse.json();
if (!routes.length) {
throw new Error('No routes available for this pair');
}
const selectedRoute = routes[0]; // first route from list
console.log(`Expected output: ${selectedRoute.amountOut}`);
console.log(`Price impact: ${selectedRoute.priceImpact}%`);
console.log(`Fee: ${selectedRoute.totalFee.percent}%`);
// 2. Get estimate
const estimateResponse = await fetch(`${API_BASE}/estimate`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(selectedRoute)
});
const estimate = await estimateResponse.json();
// 3. Build transaction
// buildCalldata: true — returns ready calldata for sendTransaction
const txResponse = await fetch(`${API_BASE}/tx/create`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
from: '0xYourWalletAddress', // With correct checksum!
recipient: '0xRecipientAddress', // Can match from
routing: selectedRoute,
estimate: estimate,
buildCalldata: true // Get ready calldata
})
});
const txData = await txResponse.json();
// txData: { to, value, data } — ready for sendTransaction
// 4. Approve tokens (check allowance to avoid unnecessary TX)
const tokenContract = new ethers.Contract(
'0xD533a949740bb3306d119CC777fa900bA034cd52', // CRV token
['function approve(address spender, uint256 amount) returns (bool)',
'function allowance(address owner, address spender) view returns (uint256)'],
signer
);
const ownerAddress = await signer.getAddress();
const allowance = await tokenContract.allowance(ownerAddress, txData.to);
if (allowance.lt('1000000000000000000000')) { // if allowance < amountIn
await tokenContract.approve(txData.to, ethers.constants.MaxUint256);
console.log('Token approved');
}
// 5. Send transaction to blockchain
const tx = await signer.sendTransaction({
to: txData.to,
data: txData.data,
value: txData.value || '0'
});
console.log(`TX sent: ${tx.hash}`);
const receipt = await tx.wait();
console.log(`TX confirmed in block: ${receipt.blockNumber}`);
// 6. Get requestId
// Option A: via API (wait for indexing ~3 sec)
await new Promise(r => setTimeout(r, 3000));
const searchResponse = await fetch(`${API_BASE}/search?search=${tx.hash}`);
const searchResult = await searchResponse.json();
let requestId = searchResult.result[0]?.requestId;
// Option B: from transaction events (faster, no waiting)
if (!requestId) {
const COMPLEX_OP_TOPIC = '0x830adbcf80ee865e0f0883ad52e813fdbf061b0216b724694a2b4e06708d243c';
const log = receipt.logs.find(l => l.topics[0] === COMPLEX_OP_TOPIC);
if (log) {
// Decode event to get nextRequestId
const iface = new ethers.utils.Interface([
'event ComplexOpProcessed(uint64 indexed currentChainId, bytes32 indexed currentRequestId, uint64 nextChainId, bytes32 nextRequestId, uint8 result, uint8 lastOp)'
]);
const decoded = iface.parseLog(log);
requestId = decoded.args.nextRequestId;
}
}
console.log(`RequestId: ${requestId}`);
// 7. Track status (polling every 5 sec)
let status;
for (let i = 0; i < 60; i++) { // max 5 minutes
const statusResponse = await fetch(`${API_BASE}/transaction/${requestId}`);
status = await statusResponse.json();
console.log(`Status: ${status.status}`);
if (status.status === 'completed') {
console.log('Swap completed!');
break;
}
if (status.inconsistency) {
console.log('Refund required, see /inconsistency');
break;
}
if (status.destination?.emergency) {
console.log('Recovery required, see /tx/create/emergency');
break;
}
await new Promise(r => setTimeout(r, 5000)); // wait 5 sec
}Important: Addresses must be in checksum format (EIP-55). Use
ethers.utils.getAddress(address)for conversion.
Test Examples
Ethereum (1)
Arbitrum (42161)
CRV
CRV
Optimism (10)
Arbitrum (42161)
USDC
USDC
Arbitrum (42161)
Polygon (137)
USDT
USDT
Get token addresses from
/tokenlist.
If No Route Found
If /routing/scan returns an empty array []:
Check that tokens have the
can_swaptagTry changing the amount (too small/large)
Try a different token pair
Route requires liquidity in supported pools
cURL Examples for Quick Testing
Test the API without writing code:
Integration Architecture
Process Diagram
Cross-Chain Swap Stages
Discovery
Get reference data
GET /networks, GET /tokenlist
Routing
Find available routes
POST /routing/scan
Estimation
Calculate fees and signature
POST /estimate
Transaction
Build calldata
POST /tx/create
Approval
Allow token spending
token.approve() (ERC-20)
Execution
Send transaction
signer.sendTransaction()
Lookup
Get requestId
GET /search?search={txHash}
Tracking
Track status
GET /transaction/{requestId}
Supported Networks
Get current list via GET /networks. Examples:
Ethereum
1
ethereum
Arbitrum
42161
arbitrum
Optimism
10
optimism
Polygon
137
polygon
BSC
56
bsc
20+ EVM networks supported. See
/networksfor current list.
Reference Data
GET /networks
Get list of supported blockchain networks.
Query Parameters:
type
number
Filter: 0 - mainnet, 1 - testnet
Example Request:
Example Response:
Important: Keys are network names (
ethereum), not chainId.
GET /tokenlist
Get list of tokens.
Example Request:
Example Response:
Important: Keys are network names. For swaps, check that token has
can_swaptag.
Main Token Tags:
can_swap
Available for cross-chain swap
stable
Stablecoin
native
Native network token (ETH, BNB...)
wrapped_native
Wrapped version (WETH, WBNB...)
curve_lp
Curve LP token
GET /prices/{token}
Get token price in USD.
Path Parameters:
token
string
Token address (checksum)
Important: Use token address, not symbol. Symbols (USDC, CRV) are not supported. Recommended to use
/prices/{token}/{chainId}for unambiguity.
Example:
GET /prices/{token}/{chainId}
Get token price in specific network.
Example:
Example Response: 0.999827 (number, price in USD)
POST /prices
Batch get prices for multiple tokens.
Request Body:
Response:
Executing Cross-Chain Swaps
POST /routing/scan
Find available routes for swap.
Request Body:
Parameters:
params.chainIdIn
number
Yes
Source chain ID
params.chainIdOut
number
Yes
Target chain ID
params.tokenIn
string
Yes
Source token address
params.tokenOut
string
Yes
Target token address
params.amountIn
string
Yes
Amount in smallest units
slippage
number
Yes
Allowed slippage (%)
Response:
Empty array
[]— no route found. See "If No Route Found" in Quick Start.
POST /estimate
Get operation estimate with signature for execution.
Request Body: Route object from /routing/scan
Response:
POST /tx/create
Build transaction data for blockchain submission.
Request Body:
Parameters:
from
string
Yes
Sender address
recipient
string
Yes
Recipient address
routing
object
Yes
Route from /routing/scan
estimate
object
Yes
Estimate from /estimate
permit
object
No
EIP-2612 permit signature
buildCalldata
boolean
No
Build calldata
Response (with buildCalldata: true): — recommended
Ready for sendTransaction({ to, data, value }).
Response (without buildCalldata):
Requires call via ethers.Contract.
Token Approval
Before executing a swap, you must allow the CrossCurve contract to use your tokens.
Where to get spenderAddress? Use
txData.tofrom/tx/createresponse — this is the contract address that will spend your tokens.
Standard Approve (ERC-20)
Permit (EIP-2612) - Approve via Signature
If token supports EIP-2612 (permit: true field in tokenlist), you can use a signature instead of approve transaction.
Transaction Tracking
GET /transaction/{requestId}
Get cross-chain transaction status.
Parameters:
requestId
string
Unique operation ID
Response:
Possible Statuses:
in progress
Operation in progress
completed
Successfully completed
failed
Execution error
reverted
Reverted (requires inconsistency)
canceled
Canceled
Status Handling Algorithm:
GET /search
Search transactions by hash or requestId.
Parameters:
search
string
Yes
Transaction hash or requestId
limit
number
No
Results limit
offset
number
No
Offset
Example:
GET /history
User transaction history.
Parameters:
address
string
Yes
Wallet address
Example:
Error Handling
Scenarios
inconsistency: false, emergency: false
Operation completed
inconsistency: true
Call /inconsistency for refund
emergency: true
Call /tx/create/emergency for recovery
GET /inconsistency/{requestId}
Get parameters for refund on inconsistency.
Example:
POST /inconsistency
Create refund transaction.
Flow:
Call
GET /inconsistency/{requestId}— get parameters (tokenIn, tokenOut, chainIdIn, chainIdOut, amountIn)Sign refund data with user wallet (EIP-712 or personal_sign)
Pass signature and original route to this endpoint
Request Body:
Parameters:
requestId
string
Yes
Operation ID with inconsistency
signature
string
Yes
User signature (65 bytes hex)
routing
object
Yes
Original route from /routing/scan
permit
object
No
EIP-2612 permit (if token supports)
POST /tx/create/emergency
Emergency recovery of locked funds.
When to use: When
destination.emergency: truein transaction status — funds are locked on destination chain and require manual recovery.
Request Body:
Parameters:
requestId
string
Yes
Locked operation ID
signature
string
Yes
User signature (65 bytes hex)
Response: Returns transaction data for fund recovery.
Creating Signature for Emergency/Inconsistency
For /tx/create/emergency and /inconsistency endpoints, a signature confirming wallet ownership is required.
Common API Errors
Can't find receiveRequest
requestId not found
Verify requestId
Can't find paymentTx
Transaction not found
Verify requestId
Routing signature not valid
Route expired or changed
Repeat /routing/scan + /estimate
Already completed
Transaction completed
No action required
Not an emergency
Emergency conditions not met
Wait or check status
Uncorrect user address
Signature not from owner
Sign with wallet from from
invalid signature string
Invalid signature format
Verify 65-byte hex signature
API Reference
Endpoint List
Reference Data
GET
/networks
List of networks
GET
/tokenlist
List of tokens
GET
/validators
Validator status
GET
/ready
Service readiness
GET
/prices/{token}
Token price
GET
/prices/{token}/{chainId}
Price in network
POST
/prices
Batch prices
Routing and Swap
POST
/routing/scan
Find routes
POST
/estimate
Operation estimate
POST
/tx/create
Create transaction
Monitoring
GET
/transaction/{requestId}
Transaction status
GET
/search
Search transactions
GET
/history
User history
GET
/transactions
Transaction list
Error Handling
GET
/inconsistency/{requestId}
Refund parameters
POST
/inconsistency
Refund transaction
POST
/tx/create/emergency
Emergency recovery
Supply and Statistics
Values are dynamic, examples current at time of testing.
GET
/supply/eywa/ts
Total Supply EYWA
number
GET
/supply/eywa/ms
Max Supply EYWA
number
GET
/supply/eywa/cmc
Data for CoinMarketCap
number
GET
/supply/eywa/cg
Data for CoinGecko
{"result":"..."}
GET
/points/multipliers
Points multipliers
object
NFT Operations
GET
/nft/rarity
NFT rarity
tokens (query, string) ⚠️
POST
/nft/estimate
NFT operation estimate
wallet, tokenIds (array of numbers)
POST
/nft/tx
Create NFT transaction
wallet, tokenIds, estimate
POST
/nft/emergency
NFT emergency operation
requestId, signature
⚠️ Known bug:
GET /nft/raritydoes not parsetokensquery parameter. Endpoint temporarily unavailable.
NFT Operations Flow:
Code Examples
Main flow in Quick Start section.
TypeScript: Types and Polling
JavaScript: Getting Networks and Tokens
Python: Finding Route
Route Operation Codes
A
Add liquidity
S
Swap
R
Remove liquidity
LM
Lock/Mint
BU
Burn/Unlock
BM
Burn/Mint
Uw
Unwrap (unwrap native token)
W
Wrap (wrap native token)
M
Emergency Mint
U
Emergency Unlock
Rate Limits and Best Practices
Rate Limits
Public rate limits are not documented. For stable operation:
/networks, /tokenlist
Cache locally
/routing/scan
On user request
/estimate
After route selection
/transaction/{id}
Polling with interval
/prices
Cache when needed
Best Practices
Cache
/networksand/tokenlist— data changes rarelyChecksum addresses — EIP-55 format recommended for compatibility
Check
can_swapbefore calling/routing/scanCheck
deadlinefrom/estimatebefore sendingPolling — 5-10 sec interval, handle
inconsistencyandemergencySave requestId — store after sending transaction for tracking and recovery
Slippage — use appropriate values (0.5-1% for stables, 1-3% for volatile)
Use correct wallet for recovery signatures — must match
fromof original transactionAccount for token decimals — not all tokens have 18 decimals
Limitations
Minimum amount
Depends on token pair and liquidity
Maximum amount
Limited by pool liquidity
Slippage
Specified in percent when calling /routing/scan
Execution time
Depends on networks and oracle network load
Contract Addresses
Contract addresses available via /networks:
Portal
Entry point for cross-chain operations
portal
Synthesis
Synthetic token contract
synthesis
Router
Swap router
router
Fee Structure
Fee information is returned in /routing/scan response:
dex
DEX/pool fee
In each route step
bridge
Bridge fee
In bridgeIn/bridgeOut steps
aggregation
Aggregation fee
Total CrossCurve fee
total
Total fee
totalFee in route
FAQ
Glossary
Portal
Entry point contract for cross-chain operations
Synthesis
Contract for minting/burning synthetic tokens
Router
Swap routing contract
RequestId
Unique identifier for cross-chain operation
Inconsistency
State requiring fund refund
Emergency
State requiring fund recovery
can_swap
Token tag indicating cross-chain swap capability
Synth
Synthetic token representing asset from another network
bridgeIn
Token lock operation on source chain
bridgeOut
Token unlock operation on destination chain
Oracle
CrossCurve validator network
Slippage
Allowed deviation from expected price
Changelog
API change history. Follow updates in Swagger UI.
2025-12
Documentation created: Quick Start, API Reference, code examples
—
For current API changes, see Swagger UI
Support
Swagger UI: https://api.crosscurve.fi/api-docs/
Documentation: https://docs.crosscurve.fi

