- A Pay As You Go, Pro, or Enterprise parent 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 if you want to charge a client fee. Omit the fee configuration to swap with a client fee of 0.
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.FAILED is ORIGIN_TRANSACTION_FAILED and has no refund. PROVIDER_FILL_FAILED and refund enrichment apply to cross-chain swaps. See What FAILED means.Going cross-chain
The same code runs a cross-chain EVM ↔ EVM swap — only theoutputToken changes. Give it a different EVM CAIP-2 prefix — say USDC on Arbitrum, eip155:42161/erc20:<USDC_ON_ARBITRUM> — and omit destinationAddress. Asset identifiers come from list_supported_assets.
For EVM ↔ SVM, change the output protocol as well — say Solana USDC, solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v — and set destinationAddress on both the quote and the execute to a raw Solana address. Do not pass a wallet account ID, a private key ID, or a CAIP identifier.
After broadcast:
- The swap stays
PENDINGpast origin-chain inclusion until the destination leg settles, so poll every 5–10 seconds rather than every second. - On
COMPLETED,destinationTxHashescarries the destination-chain transactions.swapKindin the response tells you which model applied. - On
FAILED, refund fields can arrive after the status flip. Keep polling ifrefundis absent.
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.