Skip to main content
What you’ll build:
  • Get swap quotes from multiple DEX aggregators in a single call
  • Receive ready-to-sign transaction data — no separate quote/execute steps
  • Handle token approvals before swapping
  • Bridge assets across chains
Swap 0.05 ETH → DAI on Ethereum

  Offer 1 (1inch):
    Output: 128.45 DAI (min: 125.88 after slippage)
    Gas: $2.34
    ✅ Transaction ready to sign

  Offer 2 (ParaSwap):
    Output: 128.12 DAI (min: 125.56 after slippage)
    Gas: $2.18
    ✅ Transaction ready to sign
Time: ~15 minutes

Prerequisites

  • A Zerion API key (get one here)
  • A wallet address with tokens to swap

How it works

Unlike most swap APIs that require separate quote and execute endpoints, the Zerion API combines both into a single call:
  1. Call GET /v1/swap/offers/ with the input token, output token, and amount
  2. Receive multiple offers from providers (1inch, ParaSwap, 0x, etc.), each including a quote and a complete transaction object
  3. Pick the best offer and sign the transaction with your wallet
1
Get swap offers
2
Use the swap offers endpoint to get quotes with ready-to-sign transactions.
3
JavaScript
const API_KEY = process.env.ZERION_API_KEY;
const headers = {
  accept: "application/json",
  authorization: `Basic ${btoa(API_KEY + ":")}`,
};

// Swap 0.05 ETH → DAI on Ethereum
const params = new URLSearchParams({
  "input[from]": "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B", // your wallet
  "input[chain_id]": "ethereum",
  "input[asset_address]": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", // ETH
  "input[amount]": "50000000000000000", // 0.05 ETH in wei
  "output[chain_id]": "ethereum",
  "output[asset_address]": "0x6B175474E89094C44Da98b954EedeAC495271d0F", // DAI
});

const response = await fetch(
  `https://api.zerion.io/v1/swap/offers/?${params}`,
  { headers }
);
const { data } = await response.json();

for (const offer of data) {
  const { estimation, output_quantity_max, transaction, liquidity_source } = offer.attributes;
  console.log(`\nOffer from ${liquidity_source.name}:`);
  console.log(`  Output: ${estimation.output_quantity.float}`);
  console.log(`  Min output: ${output_quantity_max.float} (after slippage)`);
  console.log(`  Gas: ${estimation.gas}`);
  console.log(`  Tx to: ${transaction.to}`);
  console.log(`  Tx data: ${transaction.data.slice(0, 40)}...`);
}
Python
import os, requests
from base64 import b64encode

api_key = os.environ["ZERION_API_KEY"]

# Swap 0.05 ETH → DAI on Ethereum
response = requests.get(
    "https://api.zerion.io/v1/swap/offers/",
    params={
        "input[from]": "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B",  # your wallet
        "input[chain_id]": "ethereum",
        "input[asset_address]": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",  # ETH
        "input[amount]": "50000000000000000",  # 0.05 ETH in wei
        "output[chain_id]": "ethereum",
        "output[asset_address]": "0x6B175474E89094C44Da98b954EedeAC495271d0F",  # DAI
    },
    auth=(api_key, ""),
)

for offer in response.json()["data"]:
    attrs = offer["attributes"]
    print(f"\nOffer from {attrs['liquidity_source']['name']}:")
    print(f"  Output: {attrs['estimation']['output_quantity']['float']}")
    print(f"  Min output: {attrs['output_quantity_max']['float']} (after slippage)")
    print(f"  Gas: {attrs['estimation']['gas']}")
    print(f"  Tx to: {attrs['transaction']['to']}")
    print(f"  Tx data: {attrs['transaction']['data'][:40]}...")
cURL
curl -g -u "YOUR_API_KEY:" \
  "https://api.zerion.io/v1/swap/offers/?input[from]=0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B&input[chain_id]=ethereum&input[asset_address]=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE&input[amount]=50000000000000000&output[chain_id]=ethereum&output[asset_address]=0x6B175474E89094C44Da98b954EedeAC495271d0F"
4
Each offer includes:
5
  • estimation — expected output amount (output_quantity) and gas cost (gas)
  • output_quantity_max — minimum guaranteed output after slippage
  • transaction — complete transaction object (to, from, data, value, gas, chain_id) ready to sign
  • liquidity_source — provider name and icon (1inch, ParaSwap, 0x, etc.)
  • preconditions_met — whether the wallet has sufficient balance and token approval
  • fee — breakdown of protocol and integrator fees
  • 6
    Check preconditions
    7
    Before signing, verify the wallet meets the requirements.
    8
    const bestOffer = data[0]; // offers are sorted by best output amount
    const { preconditions_met, asset_spender } = bestOffer.attributes;
    
    if (!preconditions_met.enough_balance) {
      console.log("Insufficient balance");
      process.exit(1);
    }
    
    if (!preconditions_met.enough_allowance) {
      // Token approval needed — see next step
      console.log(`Approval needed for spender: ${asset_spender}`);
    }
    
    9
    Native assets (ETH, MATIC, etc.) don’t require approvals. This step only applies when swapping ERC-20 tokens.
    10
    Approve token spending (if needed)
    11
    If preconditions_met.enough_allowance is false, you need to approve the asset_spender contract to spend your tokens before submitting the swap transaction.
    12
    import { ethers } from "ethers";
    
    const ERC20_ABI = ["function approve(address spender, uint256 amount) returns (bool)"];
    
    async function approveIfNeeded(offer, signer) {
      const { preconditions_met, asset_spender } = offer.attributes;
    
      if (preconditions_met.enough_allowance) return; // already approved
    
      const tokenAddress = "0x6B175474E89094C44Da98b954EedeAC495271d0F"; // DAI
      const token = new ethers.Contract(tokenAddress, ERC20_ABI, signer);
    
      const tx = await token.approve(asset_spender, ethers.MaxUint256);
      await tx.wait();
      console.log("Approval confirmed");
    }
    
    13
    Sign and send the transaction
    14
    The transaction object from the offer can be passed directly to your wallet for signing.
    15
    import { ethers } from "ethers";
    
    const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
    const signer = new ethers.Wallet(process.env.PRIVATE_KEY, provider);
    
    const bestOffer = data[0];
    const { transaction } = bestOffer.attributes;
    
    // Approve token if needed (skip for native assets like ETH)
    await approveIfNeeded(bestOffer, signer);
    
    // Sign and send the swap transaction
    const tx = await signer.sendTransaction({
      to: transaction.to,
      data: transaction.data,
      value: transaction.value,
      gas: transaction.gas,
      chainId: transaction.chain_id,
    });
    
    console.log(`Transaction sent: ${tx.hash}`);
    const receipt = await tx.wait();
    console.log(`Confirmed in block ${receipt.blockNumber}`);
    
    16
    Bridge assets across chains
    17
    To bridge tokens between chains, use the same endpoint — just set different input[chain_id] and output[chain_id] values.
    18
    # Bridge USDC from Ethereum to Polygon
    curl -g -u "YOUR_API_KEY:" \
      "https://api.zerion.io/v1/swap/offers/?input[from]=YOUR_WALLET&input[chain_id]=ethereum&input[asset_address]=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48&input[amount]=1000000000&output[chain_id]=polygon&output[asset_address]=0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359"
    
    19
    Use the List fungibles available for bridging endpoint to discover which tokens can be bridged between two specific chains before requesting offers.

    Key parameters

    ParameterDescription
    input[from]Your wallet address
    input[chain_id]Source chain (e.g., ethereum, polygon, optimism)
    input[asset_address]Token contract address to sell. Use 0xEeee...eEEeE for native assets
    input[amount]Amount in the token’s smallest unit (e.g., wei for ETH)
    output[chain_id]Destination chain (same as input for swaps, different for bridges)
    output[asset_address]Token contract address to buy
    slippage_percentMax slippage tolerance, 0–3%. Default: 2
    liquidity_source_idFilter to a specific provider, or all (default)