Upgrading to Swap API v2
0x Swap API has undergone a major upgrade that introduces new features that require a new integration. This new version offers:
- improved swap pricing, especially on large trades
- a new set of 0x smart contracts that offer secure upgradability
- increased security via the Permit2 contract or AllowanceHolder contract for allowances
- improved monetization features
- enhanced quote validation to provide accurate gas estimates without a user balance or allowance set
- improved error handling
- expanded token and chain coverage [coming soon]
API referencesβ
Find the latest API references here.
Summary of design changesβ
This section showcases example requests and responses for both the Swap API v1 and v2 endpoints to illustrate updates in the shape of the query and responses made during the API upgrade:
API v1
Swap API /quote
Request
curl --request GET
--url https://api.0x.org/swap/v1/quote?buyToken=0x6B175474E89094C44Da98b954EedeAC495271d0F&sellToken=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE&sellAmount=100000&takerAddress=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045&slippagePercentage=0.03&feeRecipient=0xa8aac589a67ecfade31efde49a062cc21d68a64e&buyTokenFeePercentage=0.1&feeRecipientTradeSurplus=0xa8aac589a67ecfade31efde49a062cc21d68a64e
--header '0x-api-key: YOUR_API_KEY'
Response
{
"chainId": 1,
"price": "3004.35342",
"grossPrice": "3008.73112",
"estimatedPriceImpact": "0.4902",
"value": "100000",
"gasPrice": "2457320000",
"gas": "358839",
"estimatedGas": "358839",
"protocolFee": "0",
"minimumProtocolFee": "0",
"buyTokenAddress": "0x6b175474e89094c44da98b954eedeac495271d0f",
"buyAmount": "300435342",
"grossBuyAmount": "300873112",
"sellTokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"sellAmount": "100000",
"grossSellAmount": "100000",
"sources": [
{
"name": "0x",
"proportion": "0"
},
{
"name": "Uniswap",
"proportion": "0"
},
{"..."}
],
"allowanceTarget": "0x0000000000000000000000000000000000000000",
"sellTokenToEthRate": "1",
"buyTokenToEthRate": "3023.5504768532695617",
"to": "0xdef1c0ded9bec7f1a1670819833240f027b25eff",
"from": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
"data": "0x415565b0000000000000000000000000eeeeeeeee....000000000000000000000000000000e7be0bf798e96f437b0d6e8",
"decodedUniqueId": "0x0e7be0bf798e96f437b0d6e8",
"guaranteedPrice": "2914.09148",
"orders": [
{
"type": 0,
"source": "Uniswap_V2",
"makerToken": "0x6b175474e89094c44da98b954eedeac495271d0f",
"takerToken": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"makerAmount": "300873112",
"takerAmount": "100000",
"fillData": {
"tokenAddressPath": [
"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"0x6b175474e89094c44da98b954eedeac495271d0f"
],
"router": "0xf164fc0ec4e93095b804a4795bbe1e041497b92a"
},
"fill": {
"input": "100000",
"output": "300873112",
"adjustedOutput": "1",
"gas": 115000
}
}
],
"fees": {
"zeroExFee": {
"feeType": "volume",
"feeToken": "0x6b175474e89094c44da98b954eedeac495271d0f",
"feeAmount": "437770",
"billingType": "on-chain"
}
},
"auxiliaryChainData": {}
}
API v2
Swap API /quote
(Permit2)
Request
curl --request GET
--url https://api.0x.org/swap/permit2/quote?chainId=1&buyToken=0x6B175474E89094C44Da98b954EedeAC495271d0F&sellToken=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE&sellAmount=100000&taker=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045&swapFeeBps=10&swapFeeRecipient=0xa8aac589a67ecfade31efde49a062cc21d68a64e&swapFeeToken=0x6B175474E89094C44Da98b954EedeAC495271d0F&tradeSurplusRecipient=0xa8aac589a67ecfade31efde49a062cc21d68a64e&slippageBps=100
--header '0x-api-key: YOUR_API_KEY'
Response
{
"blockNumber": "20264686",
"buyAmount": "300409869",
"buyToken": "0x6b175474e89094c44da98b954eedeac495271d0f",
"fees": {
"integratorFee": {
"amount": "301163",
"token": "0x6b175474e89094c44da98b954eedeac495271d0f",
"type": "volume"
},
"zeroExFee": {
"amount": "451744",
"token": "0x6b175474e89094c44da98b954eedeac495271d0f",
"type": "volume"
},
"gasFee": null
},
"issues": {
"allowance": null,
"balance": null,
"simulationIncomplete": false,
"invalidSourcesPassed": []
},
"liquidityAvailable": true,
"minBuyAmount": "297405770",
"permit2": null,
"route": {
"fills": [
{
"from": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"to": "0x6b175474e89094c44da98b954eedeac495271d0f",
"source": "SushiSwap",
"proportionBps": "10000"
}
],
"tokens": [
{
"address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"symbol": "WETH"
},
{
"address": "0x6b175474e89094c44da98b954eedeac495271d0f",
"symbol": "DAI"
}
]
},
"sellAmount": "100000",
"sellToken": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"totalNetworkFee": "415281807360000",
"transaction": {
"to": "0x7f6cee965959295cc64d0e6c00d99d6532d8e86b",
"data": "0x1fff991f000000000000000000000...000000000000",
"gas": "221184",
"gasPrice": "1877540000",
"value": "100000"
}
}
Swap API /quote
(AllowanceHolder)
Request
curl --request GET
--url https://api.0x.org/swap/allowance-holder/quote?chainId=1&buyToken=0x6B175474E89094C44Da98b954EedeAC495271d0F&sellToken=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE&sellAmount=100000&taker=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045&swapFeeBps=10&swapFeeRecipient=0xa8aac589a67ecfade31efde49a062cc21d68a64e&swapFeeToken=0x6B175474E89094C44Da98b954EedeAC495271d0F&tradeSurplusRecipient=0xa8aac589a67ecfade31efde49a062cc21d68a64e&slippageBps=100
--header '0x-api-key: YOUR_API_KEY'
Response
{
"blockNumber": "20264713",
"buyAmount": "300433569",
"buyToken": "0x6b175474e89094c44da98b954eedeac495271d0f",
"fees": {
"integratorFee": {
"amount": "301187",
"token": "0x6b175474e89094c44da98b954eedeac495271d0f",
"type": "volume"
},
"zeroExFee": {
"amount": "451780",
"token": "0x6b175474e89094c44da98b954eedeac495271d0f",
"type": "volume"
},
"gasFee": null
},
"issues": {
"allowance": null,
"balance": null,
"simulationIncomplete": false,
"invalidSourcesPassed": []
},
"liquidityAvailable": true,
"minBuyAmount": "297429233",
"route": {
"fills": [
{
"from": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"to": "0x6b175474e89094c44da98b954eedeac495271d0f",
"source": "Uniswap_V2",
"proportionBps": "10000"
}
],
"tokens": [
{
"address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"symbol": "WETH"
},
{
"address": "0x6b175474e89094c44da98b954eedeac495271d0f",
"symbol": "DAI"
}
]
},
"sellAmount": "100000",
"sellToken": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"totalNetworkFee": "783821981250000",
"transaction": {
"to": "0x0000000000001ff3684f28c67538d4d072c22734",
"data": "0x2213bc0b0000000000000000000...00000000",
"gas": "233541",
"gasPrice": "3356250000",
"value": "100000"
}
}
Things to noteβ
Updated URLsβ
Unified endpoint and chain designationβ
The chain is no longer designated by the endpoint URL. All chains now use the same api.0x.org
endpoint, with the chain set via the new chainId
query parameter:
- Old:
https://polygon.api.0x.org/swap/v1/quote
- New:
https://api.0x.org/swap/permit2/quote?chainId=137
API version updateβ
The API version is no longer set in the endpoint URL.
Enhanced securityβ
0x V2 enhances security by moving away from unlimited approvals and now sets allowances per trade. You can choose between Permit2 or AllowanceHolder this purpose.
- Old:
https://api.0x.org/swap/v1/quote
- New:
https://api.0x.org/swap/permit2/quote
orhttps://api.0x.org/swap/allowance-holder/quote
Token allowancesβ
For token allowances, the allowance target will no longer be the 0x Exchange Proxy, but rather either the Permit2 contract or AllowanceHolder contracts, depending on your preferred token allowance path.
Permit2 transactionsβ
For transactions using Permit2, you will need to sign a Permit2 EIP-712 message from the /quote
response and append the signature length and signature data to calldata before submitting the transaction to the network. You can find a guide to do so here.
Changes in API responsesβ
Liquidity availabilityβ
There is a new liquidityAvailable
field that validates the availability of liquidity for a quote request. All other parameters will only be returned when this is set to true
.
Validation changesβ
We have removed the skipValidation
field and will always validate the quote. However, we will always attempt to return a valid quote even when the taker has an insufficient balance or doesnβt have a token allowance set in the Swap API.
Issues objectβ
To help provide developers a smooth build experience, 0x API v2 will do as much validation as it can and report all issues it finds in the new issues
object. This object returns a list of potential validation issues detected with the quote. In rare cases where we are unable to validate the quote, weβll return true
in issues.simulationIncomplete
. Learn more about the new issues
object and how you can use it to provide a better experience for your users.
Note the following about the issues
object for Price and Quote:
Price
allowance
: If this field is notnull
, prompt the user to set the allowance onissues.allowance.spender
balance
: If this field is notnull
, do not proceed to get aquote
.simulationIncomplete
: This field can be ignored forprice
since when calling price means aren't close to submitting a transaction (versus calling quote). TypicallysimulationIncomplete: true
won't occur if thetaker
address is set and thetaker
has a sufficient balance of the sell token.
Quote
allowance
: This field should not appear if thequote
is sent after the token allowance is set.balance
: This field will not be returned if the taker has sufficient balance when thequote
request is sent.simulationIncomplete: true
: This field will not be returned if the taker has sufficient balance when thequote
request is sent.
Detailed migration guideβ
The following section overviews of how to update Swap API price and quote to handle the new v2 endpoints whether you are using Permit2 or using AllowanceHolder
Using Permit2β
β‘οΈ See these steps in action in the Permit2 headless example
Step 0. Get 0x API keyβ
Step 1. Get indicative priceβ
- Call
/swap/permit2/price
(code)- Build required price params
- Add
chainId
as new param -
takerAddress
has changed totaker
- Add
- In the response:
sellTokenAddress
changed tosellToken
,buyTokenAddress
changed tobuyToken
- Build required price params
Step 2. Set token allowanceβ
- Check if
taker
needs to set an allowance for Permit2. If needed, set token allowance (code)- Use the info returned by
issues.allowance
returned by/price
(iftaker
is set) and/quote
which contains details of allowances that thetaker
must set for the order to execute successfully
- Use the info returned by
Step 3. Get firm quoteβ
- Call
/swap/permit2/quote
(code)- Build required quote params (price params +
taker
address)- Add
chainId
as new param -
takerAddress
has changed totaker
- Add
- In the response:
sellTokenAddress
changed tosellToken
,buyTokenAddress
changed tobuyToken
(code)
- Build required quote params (price params +
Step 4. Sign Permit2 EIP-712 messageβ
- Sign the Permit2 EIP-712 message from
/quote
response-
signature = await signTypedDataAsync(quote.permit2.eip712);
(code) - Make sure
PriceResponse
andQuoteResponse
types are up-to-date
-
Step 5. Append signature length and signature data to transaction.dataβ
- Append the signature length and signature data to the
transaction.data
(code)
Step 6. Submit transaction with Permit2 signatureβ
- Submit the transaction with Permit2 signature
- Use
sendTransaction({account, gas, txOptions, data, value, chain)
(code) - Note that the
/quote
response structure has changed from v1 to v2, specificallyto
,gas
,data
,value
,gasPrice
β have moved underquoteResponse.transaction.to
,quoteResponse.transaction.gas
,quoteResponse.transaction.data
,quoteResponse.transaction.value
,quoteResponse.transaction.gasPrice
(code)
- Use
Using AllowanceHolderβ
β‘οΈ See these steps in action in the AllowanceHolder headless example
Step 0. Get 0x API keyβ
Step 1. Get indicative priceβ
- Call
/swap/allowance-holder/price
(code)- Build required price params
- Add
chainId
as new param -
takerAddress
has changed totaker
- Add
- In the response:
sellTokenAddress
changed tosellToken
,buyTokenAddress
changed tobuyToken
- Build required price params
Step 2. Set token allowanceβ
- Check if
taker
needs to set an allowance for AllowanceHolder. If needed, set token allowance (code)- Use the info returned by
issues.allowance
returned by/price
(iftaker
is set) and/quote
which contains details of allowances that thetaker
must set for the order to execute successfully
- Use the info returned by
Step 3. Get firm quoteβ
- Call
/swap/allowance-holder/quote
(code)- Build required quote params (price params +
taker
address)- Add
chainId
as new param -
takerAddress
has changed totaker
- Add
- In the response:
sellTokenAddress
changed tosellToken
,buyTokenAddress
changed tobuyToken
(code)
- Build required quote params (price params +
Step 4. Submit transactionβ
- Submit the transaction using
sendTransaction()
(code)- Note that the
/quote
response structure has changed from v1 to v2, specificallyto
,gas
,data
,value
,gasPrice
β have moved underquoteResponse.transaction.to
,quoteResponse.transaction.gas
,quoteResponse.transaction.data
,quoteResponse.transaction.value
,quoteResponse.transaction.gasPrice
(code)
- Note that the