Skip to main content

Cross-chain swap (submit signed permits)

POST 

/v1/actions/swap/x-chain

Same parameters as GET. The JSON body carries permits (signed offers from a previous response). The endpoint re-quotes with the permit legs riding INSIDE the composed calldata — safe on value because this endpoint is EXACT_INPUT only — and answers with permitApplied: true on every route whose assembled bytes actually carry the leg (verified, never assumed); those routes need no approve. Router-spender routes are untouched. On the same-chain spot fallback, builds from the previous response are honoured too (spliced without re-quoting).

Plain-text reference — POST /v1/actions/swap/x-chain

Parameters

ParameterInTypeRequiredDescription
fromChainIdquerystringyesSource chain ID
toChainIdquerystringyesDestination chain ID
tokenInquerystringyesInput token address on the source chain
tokenOutquerystringyesOutput token address on the destination chain
amountquerystringyesInput amount in wei
slippagequerynumberyesSlippage tolerance (basis points)
accountquerystringnoAccount address on the source chain
receiverquerystringnoReceiver address on the destination chain
orderqueryCHEAPEST, FASTESTnoRoute preference
bridgesquerystringnoComma-separated bridge filter
permitqueryoff, auto, requirednoPermit mode

Request body

FieldTypeRequiredDescription
permitsobject[]noSigned permits from a previous response of the SAME endpoint.
permits[].permitIdstringyesThe permitId from signatures[]
permits[].signaturestringyesThe eth_signTypedData_v4 signature (0x-hex)
buildsstring[]nobuildIds from the previous response's quote rows. When present alongside permits, the cached builds are re-headed with the permit — no re-quote, the price you saw is the price you execute. Builds expire after ~3 minutes; a BUILD_EXPIRED error means re-quote and resubmit the SAME signature (the permit binds token/spender/value, not the route).

Response 200

FieldTypeDescription
successTrue
dataobjectInformational data (quotes, simulation results, etc.)
data.currencyInobjectInput currency info (source chain)
data.currencyOutobjectOutput currency info (destination chain)
data.quotesobject[]Candidate routes, best output first. Execute exactly one.
data.quotes[].bridgestring
data.quotes[].tradeInputnumber
data.quotes[].tradeOutputnumber
data.quotes[].estimatedDurationnumberEstimated bridging duration in seconds
data.quotes[].approvalTargetstringThis bridge's deposit contract — the ERC-20 approve spender
data.quotes[].approvalRequiredbooleanFalse when the existing on-chain allowance already covers the input amount — or when a submitted permit is embedded in this route's calldata
data.quotes[].permitAppliedbooleanTrue when the submitted permit rides inside this route's calldata (verified against the assembled bytes): no approve needed for this route
data.quotes[].txobjectAn EVM transaction ready to sign and broadcast. Send to, data and value as-is; do not re-encode them.
data.quotes[].tx.chainTypeevmWhich VM executes this step. ABSENT means evm, which is the only value any endpoint returns today — every EVM response is unchanged. A non-EVM chain would return a different shape (a serialized, PERISHABLE transaction rather than to/data/value) carrying its own chainType, so a client that wants to stay forward-compatible should branch on this field rather than assume to is present.
data.quotes[].tx.tostringTarget contract address
data.quotes[].tx.datastringEncoded calldata
data.quotes[].tx.valuestringETH value to send with the transaction
data.quotes[].tx.descriptionstringHuman-readable label. For alternatives, this is the aggregator name (e.g. "Paraswap"). For transactions, describes the setup action (e.g. "Switch e-mode to 1").
data.permissionTxnsobject[]ERC-20 approves per bridge deposit contract; each is labeled with the bridge name — execute only the one matching the chosen quote
data.permissionTxns[].tostringTarget contract address
data.permissionTxns[].datastringEncoded calldata
data.permissionTxns[].valuestringETH value
data.permissionTxns[].descriptionstringHuman-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20")
data.permissionTxns[].spenderstringERC-20 approve spender (x-chain permissions). Match it against the selected quote's approvalTarget — several bridges can share one spender, so do not match by description.
data.permissionTxns[].typeERC20, LenderWhat kind of grant this is. A signatures[] offer names the type it replaces via its replaces field.
data.currencyInobjectInput currency info
data.currencyOutobjectOutput currency info
data.quotesobject[]Candidate routes, best output first. Execute exactly one.
data.quotes[].aggregatorstring
data.quotes[].tradeInputnumber
data.quotes[].tradeOutputnumber
data.quotes[].txobjectAn EVM transaction ready to sign and broadcast. Send to, data and value as-is; do not re-encode them.
data.quotes[].tx.chainTypeevmWhich VM executes this step. ABSENT means evm, which is the only value any endpoint returns today — every EVM response is unchanged. A non-EVM chain would return a different shape (a serialized, PERISHABLE transaction rather than to/data/value) carrying its own chainType, so a client that wants to stay forward-compatible should branch on this field rather than assume to is present.
data.quotes[].tx.tostringTarget contract address
data.quotes[].tx.datastringEncoded calldata
data.quotes[].tx.valuestringETH value to send with the transaction
data.quotes[].tx.descriptionstringHuman-readable label. For alternatives, this is the aggregator name (e.g. "Paraswap"). For transactions, describes the setup action (e.g. "Switch e-mode to 1").
data.quotes[].buildIdstringPresent when permit=auto|required produced a signature offer. Send it back in the POST body (builds[]) together with the signed permit to splice this exact build — no re-quote. Expires after ~3 minutes.
data.permissionTxnsobject[]Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level actions.permissions instead.
data.permissionTxns[].tostringTarget contract address

Example response

{
"success": true,
"data": {
"currencyIn": {},
"currencyOut": {},
"quotes": [
{
"bridge": "string",
"tradeInput": 1.0,
"tradeOutput": 1.0,
"estimatedDuration": 1.0,
"approvalTarget": "string",
"approvalRequired": true,
"permitApplied": true,
"tx": {
"chainType": "evm",
"to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
"data": "0x617ba037000000000000000000000000c02aaa39b2",
"value": "0",
"description": "string"
}
}
],
"permissionTxns": [
{
"to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"data": "0x617ba037000000000000000000000000c02aaa39b2",
"value": "0",
"description": "string",
"spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"type": "ERC20"
}
]
},
"actions": {
"transactions": [
{
"chainType": "evm",
"to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
"data": "0x617ba037000000000000000000000000c02aaa39b2",
"value": "0",
"description": "string"
}
],
"alternatives": [
{
"chainType": "evm",
"to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
"data": "0x617ba037000000000000000000000000c02aaa39b2",
"value": "0",
"description": "string"
}
],
"permissions": [
{
"to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"data": "0x617ba037000000000000000000000000c02aaa39b2",
"value": "0",
"description": "string",
"spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"type": "ERC20"
}
],
"signatures": [
{
"permitId": "string",
"kind": "erc2612",
"typedData": {},
"replaces": "string",
"spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"description": "string",
"unscoped": true,
"deadline": "string"
}
],
"permitSkipped": [
{
"replaces": "string",
"reason": "string"
}
]
}
}

Request

Responses

Cross-chain swap build with the permit embedded