INTEGRATION_GUIDE_EN

Base URL: https://api.crosscurve.fi Swagger UI: https://api.crosscurve.fi/api-docs/ General Documentation: https://docs.crosscurve.fi


Quick Start

Minimum Integration Flow

1

Discovery

GET /networks — Get list of networks and contract addresses

2

Token list

GET /tokenlist — Get list of tokens (filter: can_swap)

3

Routing

POST /routing/scan — Find swap route

4

Estimate

POST /estimate — Get estimate and signature

5

Build transaction

POST /tx/create — Build transaction

6

Approve token (if needed)

Allow contract to use tokens (if not already done)

7

Send transaction

Sign and send via ethers/web3

8

Get requestId

GET /search?search= — Get requestId by hash (wait ~3 sec)

9

Track status

GET /transaction/{id} — Track status until completed

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

Source Network
Target Network
Token In
Token Out

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_swap tag

  • Try 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

Stage
Description
API / Action

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:

Network
Chain ID
API Name

Ethereum

1

ethereum

Arbitrum

42161

arbitrum

Optimism

10

optimism

Polygon

137

polygon

BSC

56

bsc

20+ EVM networks supported. See /networks for current list.


Reference Data

GET /networks

Get list of supported blockchain networks.

Query Parameters:

Parameter
Type
Description

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_swap tag.

Main Token Tags:

Tag
Description

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:

Parameter
Type
Description

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:

Field
Type
Required
Description

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:

Field
Type
Required
Description

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.to from /tx/create response — 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:

Parameter
Type
Description

requestId

string

Unique operation ID

Response:

Possible Statuses:

Status
Description

in progress

Operation in progress

completed

Successfully completed

failed

Execution error

reverted

Reverted (requires inconsistency)

canceled

Canceled

Status Handling Algorithm:


Search transactions by hash or requestId.

Parameters:

Parameter
Type
Required
Description

search

string

Yes

Transaction hash or requestId

limit

number

No

Results limit

offset

number

No

Offset

Example:


GET /history

User transaction history.

Parameters:

Parameter
Type
Required
Description

address

string

Yes

Wallet address

Example:


Error Handling

Scenarios

Flag
Action

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:

  1. Call GET /inconsistency/{requestId} — get parameters (tokenIn, tokenOut, chainIdIn, chainIdOut, amountIn)

  2. Sign refund data with user wallet (EIP-712 or personal_sign)

  3. Pass signature and original route to this endpoint

Request Body:

Parameters:

Field
Type
Required
Description

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: true in transaction status — funds are locked on destination chain and require manual recovery.

Request Body:

Parameters:

Field
Type
Required
Description

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

Error
Cause
Solution

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

Method
Endpoint
Description

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

Method
Endpoint
Description

POST

/routing/scan

Find routes

POST

/estimate

Operation estimate

POST

/tx/create

Create transaction

Monitoring

Method
Endpoint
Description

GET

/transaction/{requestId}

Transaction status

GET

/search

Search transactions

GET

/history

User history

GET

/transactions

Transaction list

Error Handling

Method
Endpoint
Description

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.

Method
Endpoint
Description
Response Format

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

Method
Endpoint
Description
Required Parameters

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/rarity does not parse tokens query 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

Code
Description

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:

Endpoint
Usage Example

/networks, /tokenlist

Cache locally

/routing/scan

On user request

/estimate

After route selection

/transaction/{id}

Polling with interval

/prices

Cache when needed

Best Practices

  1. Cache /networks and /tokenlist — data changes rarely

  2. Checksum addresses — EIP-55 format recommended for compatibility

  3. Check can_swap before calling /routing/scan

  4. Check deadline from /estimate before sending

  5. Polling — 5-10 sec interval, handle inconsistency and emergency

  6. Save requestId — store after sending transaction for tracking and recovery

  7. Slippage — use appropriate values (0.5-1% for stables, 1-3% for volatile)

  8. Use correct wallet for recovery signatures — must match from of original transaction

  9. Account for token decimals — not all tokens have 18 decimals


Limitations

Parameter
Description

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:

Contract
Description
Field in /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:

Fee Type
Description
Response Field

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

General Questions

Q: Is an API key required? A: At time of writing, the API does not require authentication.

Q: Are there rate limits? A: Public limits are not documented. Cache reference data and avoid frequent requests.

Q: Which networks are supported? A: Current list available via GET /networks. EVM-compatible networks are supported.

Q: Why does /routing/scan return an empty array? A: No route found. See "If No Route Found" in Quick Start.

Technical Questions

Q: How to get requestId after sending transaction? A: RequestId is emitted in Portal contract events. Use GET /search?search={txHash} to find it.

Q: What to do with inconsistency: true? A: Refund required:

  • Call GET /inconsistency/{requestId} — get parameters for signature

  • Sign data with user wallet

  • Call POST /inconsistency with requestId, signature and original routing

Q: What to do with emergency: true? A: Fund recovery required. Call POST /tx/create/emergency with requestId and signature (user signature).

Q: How does permit (EIP-2612) work? A: If token supports permit (permit: true in tokenlist), you can sign permission offchain instead of separate approve transaction. Pass signature {v, r, s} to /tx/create.


Glossary

Term
Description

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.

Date
Change

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