Skip to main content
This walkthrough runs the complete Swaps lifecycle against Base mainnet: set your fee once, quote 100 USDC into WETH, execute the quote from a Turnkey wallet, and poll until the swap settles onchain.
Swaps is currently an Early Access Product. Contact us to enable it for your organization.
Prerequisites
  • Swaps Early Access enabled for your organization
  • A Turnkey API key pair
  • A wallet account holding USDC on Base, plus ETH on Base for gas if you don’t sponsor
  • An EVM wallet account in your parent organization to receive your fee payouts
1

Initialize the client

All requests go through the generic request method of TurnkeyClient, stamped by your API key. Execution confirms asynchronously, so define a polling helper here as well.
2

Configure your fee

One-time setup on your parent organization: your rate in basis points and the wallet account that collects it. The configuration applies to every swap under the parent organization, and quotes reflect it from this point on; without one, quotes carry a client fee of 0.
3

Request a quote

USDC has 6 decimals, so 100 USDC is "100000000" raw units. Both chains derive from the CAIP-19 identifiers — matching prefixes here (eip155:8453) make this a same-chain swap.
4

Show the user the quote

Quoted amounts are already net of all fees — Turnkey’s and yours — so outputAmount is what the recipient receives. Check expiresAt before executing; an expired quote fails, and a fresh quote is more likely to fill.
5

Execute the swap

Execution is pinned to the quote: pass its quoteId and restate the economics the user was shown. Turnkey constructs the transaction, batches any required ERC-20 approval into it, signs with the wallet derived from the quote, and broadcasts. The signer is not resupplied here — it comes from the bound quote.With sponsor: false, the wallet pays its own gas. Set it to true to have Gas Station cover it (requires gas sponsorship enabled for your organization).
6

Poll to settlement

ACTIVITY_STATUS_COMPLETED on the execute activity only means the swap was accepted and enqueued. Poll get_swap_status with the swapRequestId until it reports a terminal state — that’s the only place the actual settled amount appears.
On FAILED, error.reason is either ORIGIN_TRANSACTION_FAILED (never broadcast, or reverted onchain) or PROVIDER_FILL_FAILED (origin succeeded, provider could not fill). Refund details are enriched shortly after the status flips, so they may be absent on the first FAILED response. See What FAILED means.

Going cross-chain

The same code runs a cross-chain swap — only the outputToken changes. Give it a different CAIP-2 prefix — say USDC on Arbitrum, eip155:42161/erc20:<USDC_ON_ARBITRUM> — and the provider routes it across chains where it supports the pair. Asset identifiers come from list_supported_assets. Two things differ after broadcast:
  • The swap stays PENDING past origin-chain inclusion until the destination leg settles, so poll every 5–10 seconds rather than every second.
  • On COMPLETED, destinationTxHashes carries the destination-chain transactions. swapKind in the response tells you which model applied.

Dive deeper

Swaps overview

— Fee model, chains, routes, and the full API surface.

Enable swaps

— Fee configuration and the fee receiver.

Get a quote

— Quote fields, expiry, and slippage.

Execute a swap

— Gas sponsorship, approvals, and the trust boundary.

Track swap status

— Lifecycle states, failures, and refunds.