Get started with Swap API
Learn how to send your first Swap API request.
About Swap APIβ
Swap API is a professional-grade DEX aggregation and smart order routing REST API that allows you to embed crypto swaps in you app with just a few lines of code.
Under the hood, the API performs three tasks:
- Queries prices of ERC20 assets from multiple decentralized exchanges and market makers
- Aggregates the liquidity from the queried sources to provide the best price possible
- Returns the trade in a format that can be easily executed using the Web3 library of your choice
Swap Tokens in 4 Simple Stepsβ
- Get a 0x API key
- (If needed) Set token allowance
- Get an indicative price
- Fetch a firm quote
- Send the transaction to the network
β‘οΈ Quicklink to full example code here: https://github.com/0xProject/0x-examples/tree/main/swap-headless-example
0. Get a 0x API keyβ
Every call to a 0x API must include a 0x API secret key. Create a 0x account and get a live API key. See the guide here to get setup.
1. Set a Token Allowanceβ
A token allowance is required if you want a third-party to move funds on your behalf. In short, you are allowing them to move your tokens.
We need to approve an allowance for the 0x Exchange Proxy smart contract to trade our ERC20 tokens on our behalf.
For implementation details, see How to set your token allowances.
When setting the token allowance, make sure to provide enough allowance for the buy or sell amount as well as the gas; otherwise, you may receive a 'Gas estimation failed' error.
2. Get an Indicative Priceβ
Now, let's find the best price!
The next step is to learn how to get an indicative price which is used when a taker(aka the user) is just browsing for the price they could receive on the specified asset pair.
Use the /swap/v1/price
endpoint to get the indicative price. This endpoint responds with pricing information, but the response does not contain a full 0x order, so it does not constitute a full transaction that can be submitted to the Ethereum network (you must use /quote
for this). Think of /price
as the the "read-only" version of /quote
.
Example requestβ
Here is an example indicative price request to sell 100 DAI for WETH using /price
:
const qs = require('qs');
const params = {
sellToken: '0x6B175474E89094C44Da98b954EedeAC495271d0F', //DAI
buyToken: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', //WETH
sellAmount: '100000000000000000000', // Note that the DAI token uses 18 decimal places, so `sellAmount` is `100 * 10^18`.
takerAddress: '$USER_TAKER_ADDRESS', //Address that will make the trade
};
const headers = {'0x-api-key: [api-key]'}; // Get your live API key from the 0x Dashboard (https://dashboard.0x.org/apps)
const response = await fetch(
`https://api.0x.org/swap/v1/price?${qs.stringify(params)}`, { headers }
); // The example is for Ethereum mainnet https://api.0x.org. Refer to the 0x Cheat Sheet for all supported endpoints: https://0x.org/docs/introduction/0x-cheat-sheet
console.log(await response.json());
Example responseβ
The API response will look like the following (some fields omitted):
"price": "0.002663907000981641",
"gasPrice": "56000000000",
"gas": "111000",
"sellAmount": "100000000000000000000",
"buyAmount": "2663907000981641103",
"buyTokenAddress": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"sellTokenAddress": "0x6b175474e89094c44da98b954eedeac495271d0f",
"allowanceTarget": "0xdef1c0ded9bec7f1a1670819833240f027b25eff"
3. Fetch a Firm Quoteβ
When a taker has found a price they are happy with and are ready to fill a quote, they should request a firm quote from Swap API using the /swap/v1/quote
endpoint. At this point, the taker is making a soft commitment to fill the suggested orders, and understands they may be penalized by the Market Maker if they do not.
/swap/v1/quote
responds with a full 0x order, which can be submitted to an Ethereum node by the client. Therefore it is expected that the maker has reserved the maker assets required to settle the trade, leaving the order unlikely to revert.
Use /quote
only when ready to fill the response; excessive unfilled requests may lead to a ban. /quote
indicates a soft commitment, prompting Market Makers to commit assets. If browsing for prices, use /price
instead.
Example requestβ
Here is an example to fetch a firm quote to sell 100 DAI for WETH using /quote
:
const qs = require('qs');
const params = {
// Not all token symbols are supported. The address of the token should be used instead.
sellToken: '0x6B175474E89094C44Da98b954EedeAC495271d0F', //DAI
buyToken: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', //WETH
sellAmount: '100000000000000000000', // Note that the DAI token uses 18 decimal places, so `sellAmount` is `100 * 10^18`.
takerAddress: '0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B', //Including takerAddress is required to help with gas estimation, catch revert issues, and provide the best price
};
const headers = {'0x-api-key: [api-key]'}; // This is a placeholder. Get your live API key from the 0x Dashboard (https://dashboard.0x.org/apps)
const response = await fetch(
`https://api.0x.org/swap/v1/quote?${qs.stringify(params)}`, { headers }
); // The example is for Ethereum mainnet https://api.0x.org. Refer to the 0x Cheat Sheet for all supported endpoints: https://0x.org/docs/introduction/0x-cheat-sheet
console.log(await response.json());
Example responseβ
The API response will look like the following (some fields omitted):
{
"sellAmount": "100000000000000000000",
"buyAmount": "2663907000981641103",
"price": "0.002663907000981641",
"guaranteedPrice": "0.002637267930971825",
"to": "0xdef1c0ded9bec7f1a1670819833240f027b25eff",
"data": "0xd9627aa40000000000000000000...",
"value": "0",
"gas": "111000",
"gasPrice": "56000000000",
"buyTokenAddress": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"sellTokenAddress": "0x6b175474e89094c44da98b954eedeac495271d0f",
"allowanceTarget": "0xdef1c0ded9bec7f1a1670819833240f027b25eff"
}
A full list of the description of each field is outlined in the Swap API reference.
Note the to
field is the contract address to send call data
to. This is the 0x Exchange Proxy address corresponding to the network the request was made on. For production-level code, make sure to add verification that checks that the to
field returned is actually the 0x Exchange Proxy address as demonstrated in this code example (constructor, swapTarget check).
Specify a Taker Address for Your Swapsβ
The takerAddress
field is the address that will be performing the trade. This parameter is required so the API can more accurately estimate the gas required for the swap transaction. Note that this currently only works with non-contract addresses. Read more on how adding the takerAddress
helps catch issues.
https://api.0x.org/swap/v1/quote // Request a firm quote
?sellToken=DAI // Sell DAI
&sellAmount=4000000000000000000000 // Sell amount: 4000 (18 decimal)
&buyToken=ETH // Buy ETH
&takerAddress=$USER_TAKER_ADDRESS // Address that will make the trade
--header '0x-api-key: [API_KEY]' // Replace with your own API key
Under the hood, 0x API performs an eth_estimateGas
using the takerAddress
if one is provided. This serves two purposes:
- to more accurately estimate the gas required for the transaction,
- to provide the best pricing that includes enabling RFQ liquidity, and
- to catch any reverts that would occur if the
takerAddress
attempts to swap the tokens.
An HTTP response with status 400 will be returned if the eth_estimateGas
results in a revert (i.e. the swap would fail), along with reasons for the revert. In particular,
- the
takerAddress
needs to have a sufficient balance of thesellToken
, and - if the
sellToken
is not ETH, thetakerAddress
needs to have approved the 0x Exchange Proxy (0xdef1c0ded9bec7f1a1670819833240f027b25eff
on mainnet) to transfer their tokens. See below for an example of setting a token approval before sending the API request.
4. Send the Transaction to the Networkβ
Once you've received the API response, in order to submit the transaction to the network you will need to sign the transaction with your preferred web3 library (web3.js, ethers.js, wagmi, etc).
wagmiβ
If you are using React, we recommend using wagmi. You can use a React hooks library like wagmi and use their sendTransaction API. See it implemented in our Next.js 0x Demo App.
If you are using vanilla Javascript, we recommend either web3.js or ether.js.
web3.jsβ
The fields returned by Swap API's /quote
endpoint are designed to overlap with the raw transaction object accepted by web3.js
βs sendTransaction()
function. What this means is that if you are using web3.js, you can directly pass the entire response from /quote
because it contains all the necessary parameters for web3.eth.setTransaction()
- _from, to, value, gas, data.
Both options work, up to use case and developer preference.
Option 1 - Submit the entire quote response to web3.eth.sendTransctionβ
// Fetch the swap quote.
const response = await fetch(`https://api.0x.org/swap/v1/quote?${qs.stringify(params)}`, { headers });
quote = await response.json();
//Fill the quote by submitting the entire response to web3
const receipt = await web3.eth.sendTransaction(quote);
Option 2 - Submit only the required parameters to web3.eth.sendTransactionβ
// Fetch the swap quote.
const response = await fetch(`https://api.0x.org/swap/v1/quote?${qs.stringify(params)}`, { headers });
quote = await response.json();
// Fill the quote.
const receipt = await waitForTxSuccess(
web3.eth.sendTransaction({
from: taker,
to: quote.to,
data: quote.data,
value: quote.value,
gasPrice: quote.gasPrice,
}),
);
ethers.jsβ
ethers.js is more explicit and requires you to pull out and submit only the required parameters (whereas web3.js allows you to just submit the entire json response or submit only require parameters). So if you use ethers.js, make sure you submit only the required parameters similar to the example below.
Also note that ethers.js separates the concept of Wallet, Providers, and Signers. You can use a Wallet and connect it to a provider to send transactions. If you are using a Wallet such as MetaMask, review the ethers.js documentation on how to access these fields - Connecting to Ethereum: MetaMask.
// get signer from a wallet such as MetaMask
const signer = provider.getSigner();
await signer.sendTransaction({
gasLimit: quote.gas,
gasPrice: quote.gasPrice,
to: quote.to,
data: quote.data,
value: quote.value,
chainId: quote.chainId,
});
Examplesβ
These examples illustrate how the response payload from 0x APIβs swap
endpoint can be passed directly into web3.eth.sendTransaction
. Note that in a production implementation, there would be some error handling for the API response.
Sell 100 DAI for ETHβ
This is the most common use pattern for swapping tokens ββ selling a fixed amount of an ERC20 token. Because ERC20 tokens cannot be attached to contract calls the way ETH can, the taker must approve the 0x Exchange Proxy (0xdef1c0ded9bec7f1a1670819833240f027b25eff
) to transfer their DAI prior to executing the swap.
const ZERO_EX_ADDRESS = '0xdef1c0ded9bec7f1a1670819833240f027b25eff';
const DAI_ADDRESS = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48';
// Selling 100 DAI for ETH.
const params = {
sellToken: '0x6B175474E89094C44Da98b954EedeAC495271d0F', //DAI
buyToken: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', //ETH
// Note that the DAI token uses 18 decimal places, so `sellAmount` is `100 * 10^18`.
sellAmount: '100000000000000000000',
takerAddress: '0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B',
}
const headers = {'0x-api-key: [api-key]'}; // This is a placeholder. Get your live API key from the 0x Dashboard (https://dashboard.0x.org/apps)
// Set up a DAI allowance on the 0x contract if needed.
const dai = new web3.eth.Contract(ERC20_ABI, DAI_ADDRESS);
const currentAllowance = new BigNumber(
dai.allowance(params.takerAddress, ZERO_EX_ADDRESS).call()
);
if (currentAllowance.isLessThan(params.sellAmount)) {
await dai
.approve(ZERO_EX_ADDRESS, params.sellAmount)
.send({ from: params.takerAddress });
}
// Fetch the swap quote.
const response = await fetch(
`https://api.0x.org/swap/v1/quote?${qs.stringify(params)}`, { headers }
);
// Perform the swap.
await web3.eth.sendTransaction(await response.json());
Sell 1 ETH for DAIβ
This swaps a fixed quantity of ETH for DAI. Unlike ERC20 tokens, ETH can be βattachedβ to the swap transaction so the taker does not need to set an allowance like in the previous example. The taker must have enough ETH balance to cover both the sellAmount
and the gas cost of the transaction.
// Selling 100 ETH for DAI.
const params = {
sellToken: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', //ETH
buyToken: '0x6B175474E89094C44Da98b954EedeAC495271d0F', //DAI
sellAmount: '1000000000000000000', // 1 ETH = 10^18 wei
takerAddress: '0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B',
}
const headers = {'0x-api-key: [api-key]'}; // This is a placeholder. Get your live API key from the 0x Dashboard (https://dashboard.0x.org/apps)
// Fetch the swap quote.
const response = await fetch(
`https://api.0x.org/swap/v1/quote?${qs.stringify(params)}`, { headers }
);
// Perform the swap.
await web3.eth.sendTransaction(await response.json());
Buy 100 DAI with ETH β
This is similar to the previous example, but instead specifies the amount of DAI to buy, rather than the amount of ETH to sell. Instead of specifying sellAmount
in the API request parameters, we provide buyAmount
. Note that due to slippage, you may end up with slightly more than the requested buyAmount
.
const params = {
buyToken: '0x6B175474E89094C44Da98b954EedeAC495271d0F', //DAI
sellToken: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', //ETH
// Note that the DAI token uses 18 decimal places, so `buyAmount` is `100 * 10^18`.
buyAmount: '100000000000000000000',
takerAddress: '0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B',
}
const headers = {'0x-api-key: [api-key]'}; // This is a placeholder. Get your live API key from the 0x Dashboard (https://dashboard.0x.org/apps)
// Fetch the swap quote.
const response = await fetch(
`https://api.0x.org/swap/v1/quote?${qs.stringify(params)}`, { headers }
);
// Perform the swap.
await web3.eth.sendTransaction(await response.json());
Advanced Optionsβ
Gas Priceβ
By default, 0x API will choose the median βfastβ (<30s) gas price (as reported by various sources, such as ETH Gas Station) and compute the quote based around that. However, you can explicitly provide a gas price with the gasPrice
query parameter. Just like with other quantities, values for this parameter are in wei (e.g. 9 gwei = 9 * 10^9 wei = 9000000000
).
Max Slippageβ
0x API aggregates liquidity from various sources, including on-chain AMMs. Whereas the price of 0x orders are βlocked inβ when they are signed, AMM prices can fluctuate between the time of the API request and the time the swap transaction gets mined (this is known as slippage). If, at the time the swap is executed, the price is below the guaranteedPrice
returned in the API response, the transaction will revert.
The slippagePercentage
parameter determines the difference between the price
returned in the API response and the guaranteedPrice
, i.e. the maximum acceptable slippage. It defaults to 1% but this value may not be appropriate. For example one might expect very low slippage for certain stablecoin pairs like USDC-USDT. On the other hand, one might expect (and deem acceptable) relatively high slippage for newly launched tokens with shallow liquidity.
Starter projectsβ
- (Code) Next.js 0x Demo App - A demo ERC20 swapping app made with 0x Swap API, Next.js, and ConnectKit
- (Video) Build a Token Swap dApp with 0x Swap API, ConnectKit, and Next.js - A video tutorial covering the core concepts when building any token swapping dApp.