Swap APIs & SDKs

Swap API integration: quote, approve, simulate, submit

Build a same-chain EVM swap flow with exact token amounts, correct approval targets, fresh quotes, transaction simulation and receipt tracking.

A working swap integration needs an explicit sequence: obtain a route, resolve its spending permissions, prepare a fresh transaction, simulate that transaction, request wallet confirmation, and track the result. An HTTP success response completes only one part of that sequence. It does not prove that the wallet can spend the input token or that the swap has executed.

Model the integration state

This provider-neutral pseudocode describes UI states. It is not an API endpoint, executable trading code or a complete integration. The user's review must bind the chain, assets, amount, recipient and limits to the transaction being signed.

state = "quoting"
quote = requestFreshQuote(tradeIntent)
validateQuoteAgainstIntent(quote, tradeIntent)
state = "review"
requireExplicitUserConfirmation(quote)
prepareRequiredPermissions(quote)
if quote.isExpired: returnToQuoteReview()
state = "simulating"
simulateAgainstCurrentState(quote.transaction)
state = "awaiting_signature"
hash = requestWalletTransaction(quote.transaction)
state = "pending"
receipt = waitForReceipt(hash)
state = receipt.succeeded ? "confirmed" : "reverted"
verifyRecipientBalances(receipt)
Separate errors from transaction outcomes
Observed stateUI response
User rejects the signatureReturn to review. Do not claim a transaction was submitted.
Receipt request times outKeep the hash and show status unknown or pending. Check before offering another submission.
Quote expires before signingRequest a fresh quote and show changed terms for another review.
Receipt indicates failureShow reverted, preserve the hash and investigate the cause before retrying.

This guide describes a same-chain EVM swap funded by the connected account. The examples reference 0x AllowanceHolder where a concrete API is useful. Signed intent orders, cross-chain settlement and account-abstraction batching require additional states; they should not be forced into this transaction flow.

Capture the trade as an immutable request

Before requesting a quote, record the chain ID, input and output asset identities, input amount, sender, recipient and slippage setting. Treat a token as a chain-and-address pair, with a separate type for native currency. Symbols are display labels. A token named USDC on one chain does not identify a contract on another.

Convert the user-entered decimal string into integer base units without passing it through floating-point arithmetic. In a hypothetical six-decimal token, 12.345678 becomes 12345678 base units; 12.3456789 requires rejection or an explicit rounding decision. Do not silently round up the amount being sold. The ERC-20 specification defines the decimals display relationship and makes metadata methods optional, so missing metadata needs a supported fallback or a clear unsupported-token state.

Give this input snapshot a local request ID. If the user changes the amount while a quote is in flight, discard the older response even if it arrives last. Subscribe to the wallet's account and chain change events; either event invalidates account-dependent approval and execution state.

Use a quote response for its documented purpose

A provider may offer an indicative price endpoint, a separate transaction-building endpoint, or both. In the 0x AllowanceHolder flow, the price request helps populate the form, while the firm quote provides transaction data. The v2 request uses chainId, sellToken, buyToken, sellAmount and taker; authenticated calls include the documented API key and version headers.

Keep service credentials in a backend when they are intended to be secret. The browser can send the proposed trade to that backend, which validates the request and calls the approved provider. A quote proxy should accept a narrow trade schema, not an arbitrary upstream URL supplied by the browser.

Check liquidity availability and validate the response shape before reading transaction fields. Then inspect execution issues. For example, 0x reports allowance, balance and simulation issues separately. A usable price alongside insufficient balance is appropriate for browsing, but it is not a reason to enable the final submission button.

Approve the spender selected by the execution path

Read allowance for the actual token, owner and spender. If it is sufficient, avoid an unnecessary approval transaction. If it is insufficient, explain the permission being requested and submit the approval through the wallet. Wait for its successful receipt, then read allowance again before continuing.

The spender is not a universal synonym for the swap destination. 0x distinguishes allowance targets from execution entry points and explicitly warns against approving its Settler contract. Its response identifies the intended allowance target. Resolve and validate that target using the chosen provider's documented deployment rules; do not copy an address from an unrelated integration.

Provider variants also matter. PancakeSwap's Unified Swap examples use different approval paths for an aggregator candidate and a PancakeSwap X candidate. A generic adapter that assumes every winning quote uses yesterday's spender will fail when the engine changes.

Refresh, inspect and simulate the executable transaction

Approval can take long enough for the displayed route to become stale. Request a fresh executable quote after approval, and show the user any material change to the expected output or fee. Bind the result to the current request snapshot. Never combine the destination from one quote with calldata or value from another.

Inspect the execution chain, destination, calldata and native value together. A native-input swap commonly carries value, while a token-input swap may have different funding requirements. Preserve the provider's transaction semantics instead of assuming every swap has zero value. Keep enough native currency for the transaction's network fee.

Use eth_call to preflight the actual sender, destination, data and value against an appropriate recent state. Estimate gas for the same call. A revert during estimation may reflect a missing allowance, expired route or contract restriction; simply raising the gas limit does not repair those causes. A successful simulation remains evidence about a particular state, not a guarantee about the later block in which the transaction lands.

Submit once, then track evidence

Immediately before opening the wallet, verify that the account and chain still match. Submit only the reviewed transaction. If the wallet returns error 4001, record a user rejection and return control to the form; do not automatically reopen the request.

Once a transaction hash is available, store it with the chain and local attempt ID. Display a pending state. The transaction receipt API supplies execution evidence after inclusion. A receipt's status distinguishes execution success from failure. For a successful transaction, reconcile the received token and amount rather than turning the old estimate into an asserted fill.

If broadcasting times out, preserve an unknown-outcome state. Recover the hash or account transaction history before offering a fresh submission: the first transaction may already exist. The same principle applies when the browser closes during a wallet prompt. An interrupted interface must not erase the distinction between rejected, submitted and confirmed.

Evidence to collect before launch

  • A quote cannot survive a change of account, chain, token, amount or recipient.
  • Insufficient balance and insufficient allowance lead to different recovery actions.
  • Approval failure prevents swap submission, and approval success triggers fresh validation.
  • Native transaction value survives every serialization boundary.
  • A rejected wallet prompt creates no automatic retry loop.
  • A timeout preserves the transaction attempt for reconciliation.
  • A successful HTTP response or transaction hash never appears as a completed swap.

These are proposed acceptance checks, not claims of testing against live providers. Run them against fixtures and a controlled integration environment, then document which provider paths and wallet types the application actually supports.

Sources & verification (9)

Source-check date is recorded in the article details. URLs are provided for manual verification. Use Copy to keep this page open.

  1. ERC-20: Token Standard

    Token units, optional metadata and allowance semantics

    https://eips.ethereum.org/EIPS/eip-20
  2. EIP-1193: Ethereum Provider JavaScript API

    Account/chain events and user rejection error

    https://eips.ethereum.org/EIPS/eip-1193
  3. Get Started with Swap API

    AllowanceHolder sequence, request parameters and transaction payload

    https://docs.0x.org/docs/introduction/quickstart/swap-tokens-with-0x-swap-api
  4. Issues & Error Codes

    Distinct allowance, balance and incomplete simulation issues

    https://docs.0x.org/docs/introduction/api-issues
  5. Contracts

    Allowance target versus execution entry point; Settler warning

    https://docs.0x.org/docs/core-concepts/contracts
  6. TypeScript examples

    Different approval and execution paths for agg and pcsx candidates

    https://developer.pancakeswap.finance/contracts/unified-swap-api/typescript
  7. eth Namespace

    eth_call evaluates transaction context without publishing a transaction

    https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-eth
  8. JSON-RPC API

    Transaction submission, receipt retrieval and transaction fields

    https://ethereum.org/developers/docs/apis/json-rpc/
  9. EIP-658: Embedding transaction status code in receipts

    Receipt success/failure status

    https://eips.ethereum.org/EIPS/eip-658

Continue reading

Approval target versus transaction target Simulate the exact swap transaction before submission