How to test token-to-token swap flows in the sandbox environment
Prerequisite: You need a KYC-approved wallet. Register one with POST /ramp/wallet (set claimOwnership: true to inherit your organization’s KYB approval), or onboard a customer wallet via KYC WebSDK. Swaps do not require a bank account.
For onboarding your customers, see KYC Overview.
Swaps are currently available on Stellar, Solana, and Monad, and the source and destination must be on the same chain (no cross-chain swaps). The other EVM chains (Base, Polygon, Avalanche) support direct on/off-ramps but do not yet support token-to-token swaps.
Stellar swaps need a funded, trustlined wallet. The wallet must already hold XLM and a trustline for the asset it will receive — otherwise Etherfuse can’t build the swap transaction and no swap_updated webhook fires. See the Stellar, Solana, and Monad chain guides for per-chain setup.
Either of these endpoints will give you the asset identifiers needed for quotes:
GET /ramp/assets — Requires auth. Returns all rampable stablecoins and stablebonds for the specified blockchain. The currency parameter controls sort priority (matching assets appear first). Best for building integrations where you already know the customer’s wallet.
GET /lookup/stablebonds — Public, no auth. Returns all stablebonds across all chains with pricing and supply data. Best for exploring what’s available before onboarding a customer.
Use the identifier from either response as the asset value in your quote.Swap constraint: A swap must involve at least one stablebond; the other side can be a stablecoin such as USDC, so both USDC → CETES and the reverse CETES → USDC are valid. Both assets must be stable, so non-stable tokens (SOL, XLM) return Non-stable assets are not supported, and stablecoin-to-stablecoin swaps (USDC → USDT) are not supported.
Asset identifier format differs by chain:
Solana — Base58 mint address (e.g. AvvetPGuuB5FD5m86fpw3LtDKyQoUFT1mG9WarNQLW4q)
Stellar — CODE:ISSUER format (e.g. CETES:GC3CW7...)
Monad — raw token contract address only (e.g. 0xcC77c598d42f2f78Beb42C91d12B9d4041a5cE29)
Using SYMBOL:0x... (Stellar format) on other chains will return UnsupportedBlockchain.
Quotes expire after 2 minutes. For swaps, set type: "swap" with the source token identifier as sourceAsset and the stablebond identifier as targetAsset. The response includes requiresSwap: true and the exchangeRate between the two assets. See POST /ramp/quote for the full schema.
Partner fees: If your organization has a partner fee configured, it is applied automatically. To override per-quote, add "partnerFeeBps": 100 (0–500) to the request body. See Partner Fees for details.
3
Create the Swap — POST /ramp/swap
Show Details
Unlike orders, the swap endpoint requires blockchain and publicKey in the request body (these are not derived from the quote). The endpoint returns an empty 200 — all swap progress is delivered via webhooks. See POST /ramp/swap for the full schema.
curl -X POST https://api.sand.etherfuse.com/ramp/swap \ -H "Authorization: <api_key>" \ -H "Content-Type: application/json" \ -d '{ "orderId": "<uuid>", # You generate this UUID "quoteId": "<quote_uuid_from_step_2>", # From Step 2 "publicKey": "<wallet_public_key>", # From onboarding "blockchain": "stellar" }'
curl -X POST https://api.etherfuse.com/ramp/swap \ -H "Authorization: <api_key>" \ -H "Content-Type: application/json" \ -d '{ "orderId": "<uuid>", # You generate this UUID "quoteId": "<quote_uuid_from_step_2>", # From Step 2 "publicKey": "<wallet_public_key>", # From onboarding "blockchain": "stellar" }'
The orderId here is a swap identifier you generate — it tracks this swap through webhooks. The optional targetWallet field lets you send the swapped tokens to a different wallet than publicKey.
4
Sign the Transaction
Show Details
After creating the swap, you’ll receive a swap_updated webhook with the sendTransaction — a pre-built, encoded transaction ready to sign.
Sign the sendTransaction using a wallet adapter and submit it to the testnet blockchain. Once confirmed, you’ll receive another swap_updated webhook with status: "completed".
The first webhook is a call to action, not a progress notification. Etherfuse has partially signed sendTransaction, but the swap does not advance until the customer’s wallet adds its signature and submits it on-chain. Until then the swap stays at pending and no further webhooks fire.
Do not build your own transaction. Always use the sendTransaction provided in the webhook. This transaction is pre-built by Etherfuse with the correct swap parameters.
If the transaction expires before you submit it, fetch a fresh one with POST /ramp/swap/{order_id}/regenerate_tx — the new sendTransaction arrives over the swap_updated webhook. (Stellar transactions expire in ~1–2 minutes.) sendTransaction is only present while funds are still owed; after they’re received you instead get sendTransactionHash and receiveTransactionHash.
5
Verify Completion
Show Details
Monitor swap progress via swap_updated webhooks. The status field progresses pending → funds_received → completed (or failed). Register a webhook for the swap_updated event type via POST /ramp/webhook.
funds_received fires on Stellar and Monad only. On Solana the swap goes straight from pending to completed, so treat the middle event as optional rather than gating your state machine on it.
Unlike on/off-ramps, there is no polling endpoint for swap status; webhooks are the only way to track progress. Swaps are not stored as orders, so calling GET /ramp/order/{order_id} with a swap orderId returns 404 Order not found. The swap_updated payload carries everything the UI needs.
Use the interactive tutorial below to test the swap flow with your sandbox API key. Each step builds on the previous one, and you can edit the request bodies before sending.
Check that the source asset has testnet liquidity against the target
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Etherfuse API","colors":{"primary":"#141414","light":"#E4FF3F","dark":"#141414"},"logo":{"light":"https://mintcdn.com/etherfuse/XRSchVFGUgreQatD/img/logo-black.svg?fit=max\u0026auto=format\u0026n=XRSchVFGUgreQatD\u0026q=85\u0026s=92cf84eca27df4a19f7b032da398d110","dark":"https://mintcdn.com/etherfuse/XRSchVFGUgreQatD/img/logo-white.svg?fit=max\u0026auto=format\u0026n=XRSchVFGUgreQatD\u0026q=85\u0026s=7c87780c9a248347ffe6357ccf6762ed","href":"https://etherfuse.com"},"favicon":"https://mintcdn.com/etherfuse/pF4txuzXWQE790kS/img/favicon.png?fit=max\u0026auto=format\u0026n=pF4txuzXWQE790kS\u0026q=85\u0026s=ac74be5f7f4605e75bc961be0c6e5ff9","api":{"playground":{"display":"interactive"},"examples":{"languages":["curl","javascript","python"],"autogenerate":true}},"navbar":{"links":[{"href":"https://cal.com/team/etherfuse/api-overview?overlayCalendar=true","label":"Book a demo"},{"href":"https://app.etherfuse.com","label":"App"}],"primary":{"type":"button","label":"Get sandbox keys","href":"https://sandbox.etherfuse.com/sign-in?returnTo=%2Faccount%2Fmanage"}},"footer":{"links":[{"items":[{"label":"Website","href":"https://etherfuse.com"},{"label":"App","href":"https://app.etherfuse.com"},{"label":"Book a demo","href":"https://cal.com/team/etherfuse/api-overview?overlayCalendar=true"}]}]},"fonts":{"family":"Figtree"},"integrations":{"posthog":{"apiKey":"phc_vJEpZk4aZr9PxdPqapjg8ZKWFybTTmDvAxZNg88LTuPu","apiHost":"https://us.i.posthog.com"}},"contextual":{"options":["copy","view","chatgpt","claude"],"display":"header"},"styling":{"latex":false},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"etherfuse","hasAudioNarration":false,"actualSubdomain":"etherfuse","customDomains":["docs.etherfuse.com"],"gitSource":{"type":"github","owner":"etherfuse","repo":"docs","deployBranch":"main","contentDirectory":"","isPrivate":true,"mountPath":"","label":""},"chroma":{"liveDeploymentHistoryId":"6ae3779d1c0f0903e5d7bbe7","collectionId":"954573e7-24c6-4c9a-8b93-551f6122b6ad","schemaVersion":"v3","latestBuiltDeploymentHistoryId":"6ae3779d1c0f0903e5d7bbe7"},"entitlements":{"AI_CHAT":{"status":"ENABLED"},"WEB_MCP":{"status":"ENABLED"},"NARRATION":{"status":"ENABLED"}},"buildId":"6ae3779d1c0f0903e5d7bbe7","clientVersion":"0.0.4021","searchFilterCounts":[{"language":"default","tag":"API Reference","count":151},{"language":"default","tag":"Ramp API","count":72},{"language":"default","tag":"Guides","count":65},{"language":"default","tag":"KYC","count":20},{"language":"default","tag":"Lookup API","count":18},{"language":"default","tag":"Orders","count":17},{"language":"default","tag":"Organizations","count":16},{"language":"default","tag":"User Authentication","count":12},{"language":"default","tag":"Blockchains","count":12},{"language":"default","tag":"Integration Guides","count":12}]},"assistantConfig":{},"basePath":"","hasChatPermissions":true,"hasWebMcpPermissions":true,"toggles":[],"googleFontsInlined":true},"customCss":[{"filePath":"global.css","content":"body{scrollbar-gutter:stable}.sandbox-playground-cta{display:block;margin:1rem 0 1.25rem;padding:1rem 1.25rem;border-radius:.75rem;border:1px solid #141414;background-color:#e4ff3f;color:#141414!important;text-decoration:none;transition:background-color .15s ease,box-shadow .15s ease}.sandbox-playground-cta:hover{background-color:#d8f32f;box-shadow:0 2px 8px rgba(20,20,20,.12);color:#141414!important}.sandbox-playground-cta__body,.sandbox-playground-cta__detail,.sandbox-playground-cta__title{color:inherit!important}.dark .sandbox-playground-cta{border-color:#e4ff3f;background-color:#e4ff3f;color:#141414!important}.dark .sandbox-playground-cta:hover{background-color:#d8f32f;color:#141414!important}.sandbox-playground-cta__title{display:block;font-size:1rem;font-weight:600;margin-bottom:.35rem}.sandbox-playground-cta__body{display:block;font-size:.95rem;line-height:1.45;font-weight:500}.sandbox-playground-cta__detail{display:block;margin-top:.35rem;font-size:.85rem;line-height:1.45;opacity:.85}"}],"page":{"pagePath":"guides/testing-swaps","slug":"/guides/testing-swaps","pageMetadata":{"title":"Swaps","description":"How to test token-to-token swap flows in the sandbox environment","href":"/guides/testing-swaps"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"How to test token-to-token swap flows in the sandbox environment\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];const SwapTutorial=({sandboxOnly=true}={})=>{const _components={a:`a`,..._provideComponents()};const{useState,useEffect,useMemo,useCallback}=React;const[envSandbox,setEnvSandbox]=useState(true);const isSandbox=sandboxOnly||envSandbox;const[apiKey,setApiKey]=useState(``);const isProdKey=apiKey.startsWith(`api_prod:`);const prodKeyBlocked=sandboxOnly\u0026\u0026isProdKey;useEffect(()=>{const stored=sessionStorage.getItem(`etherfuse_api_key`);if(stored)setApiKey(stored)},[]);const handleApiKeyChange=value=>{setApiKey(value);if(value){sessionStorage.setItem(`etherfuse_api_key`,value)}else{sessionStorage.removeItem(`etherfuse_api_key`)}};const getOrgIdFromApiKey=()=>{if(!apiKey)return null;const parts=apiKey.split(`:`);if(parts.length>=3){const orgId=parts[2];if(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(orgId)){return orgId}}return null};const orgIdFromApiKey=getOrgIdFromApiKey();useEffect(()=>{if(orgIdFromApiKey\u0026\u0026(!customerId||customerId===``)){setCustomerId(orgIdFromApiKey);setSelectedCustomer(orgIdFromApiKey)}},[orgIdFromApiKey]);const baseUrl=isSandbox?`https://api.sand.etherfuse.com`:`https://api.etherfuse.com`;const rejectProdKey=()=>{if(prodKeyBlocked){throw new Error(`Production API keys are not allowed in this sandbox playground. Use a sandbox key (api_sand:...).`)}};const[loading,setLoading]=useState(false);const[error,setError]=useState(null);const[lookupAssets,setLookupAssets]=useState(null);const[quote,setQuote]=useState(null);const[swap,setSwap]=useState(null);const[customers,setCustomers]=useState(null);const[wallets,setWallets]=useState(null);const[selectedCustomer,setSelectedCustomer]=useState(``);const[selectedWallet,setSelectedWallet]=useState(null);const[stepErrors,setStepErrors]=useState({});const[selectedBlockchain,setSelectedBlockchain]=useState(`stellar`);const[selectedBond,setSelectedBond]=useState(``);const[sourceAsset,setSourceAsset]=useState(``);const[customerId,setCustomerId]=useState(``);const[publicKey,setPublicKey]=useState(``);const[sourceAmount,setSourceAmount]=useState(`10`);const[quoteId,setQuoteId]=useState(``);const[swapId,setSwapId]=useState(``);const[orgDataLoading,setOrgDataLoading]=useState(false);const[assetSource,setAssetSource]=useState(`lookup`);const[currencies,setCurrencies]=useState([]);const[selectedCurrency,setSelectedCurrency]=useState(``);const[assetsLoading,setAssetsLoading]=useState(false);const[swapAssets,setSwapAssets]=useState([]);const usdcAddresses={sandbox:{stellar:{symbol:`USDC`,identifier:`USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5`,isStablebond:false},solana:{symbol:`USDC`,identifier:`4D4r1KuS9WxbPCzzAJnWtYUJSSzDEZzrF1CbwajWGVjg`,isStablebond:false},base:{symbol:`USDC`,identifier:`0x036CbD53842c5426634e7929541eC2318f3dCF7e`,isStablebond:false},polygon:{symbol:`USDC`,identifier:`0x9999f7Fea5938fD3b1E26A12c3f2fb024e194f97`,isStablebond:false}},production:{stellar:{symbol:`USDC`,identifier:`USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN`,isStablebond:false},solana:{symbol:`USDC`,identifier:`EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v`,isStablebond:false},base:{symbol:`USDC`,identifier:`0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`,isStablebond:false},polygon:{symbol:`USDC`,identifier:`0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359`,isStablebond:false}}};const blockchains=useMemo(()=>{if(!lookupAssets?.stablebonds)return[`stellar`,`solana`,`base`,`polygon`];const chains=new Set;lookupAssets.stablebonds.forEach(bond=>{bond.blockchains?.forEach(bc=>chains.add(bc.blockchain))});return Array.from(chains).sort()},[lookupAssets]);const fetchSwapAssets=useCallback(async()=>{if(assetSource!==`currency`||!selectedCurrency||!publicKey||prodKeyBlocked){setSwapAssets([]);return}setAssetsLoading(true);try{const params=new URLSearchParams({blockchain:selectedBlockchain,currency:selectedCurrency.toLowerCase(),wallet:publicKey});const res=await fetch(baseUrl+`/ramp/assets?`+params.toString(),{headers:{\"Authorization\":apiKey}});if(res.ok){const data=await res.json();setSwapAssets((data.assets||[]).map(a=>({symbol:a.symbol,identifier:a.identifier,balance:a.balance,isStablebond:a.currency!==null})))}}catch{setSwapAssets([])}finally{setAssetsLoading(false)}},[assetSource,selectedCurrency,publicKey,selectedBlockchain,baseUrl,apiKey,prodKeyBlocked]);useEffect(()=>{fetchSwapAssets()},[fetchSwapAssets]);const lookupAvailableAssets=useMemo(()=>{if(!lookupAssets?.stablebonds)return[];const env=isSandbox?`sandbox`:`production`;const usdc=usdcAddresses[env][selectedBlockchain];const assetList=[...usdc?[usdc]:[],...lookupAssets.stablebonds.map(bond=>{const chainInfo=bond.blockchains?.find(bc=>bc.blockchain===selectedBlockchain);if(chainInfo){return{symbol:bond.symbol,identifier:chainInfo.tokenIdentifier,isStablebond:true}}return null}).filter(Boolean)];return assetList},[lookupAssets,selectedBlockchain,isSandbox]);const availableAssets=assetSource===`currency`?swapAssets:lookupAvailableAssets;const targetAssets=useMemo(()=>{return availableAssets.filter(a=>a.isStablebond\u0026\u0026a.identifier!==sourceAsset)},[availableAssets,sourceAsset]);const generateUUID=()=>{return`xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`.replace(/[xy]/g,function(c){const r=Math.random()*16|0;const v=c===`x`?r:r\u00263|8;return v.toString(16)})};useEffect(()=>{if(!quoteId)setQuoteId(generateUUID());if(!swapId)setSwapId(generateUUID())},[]);const defaultQuote={quoteId:generateUUID(),customerId:`YOUR_CUSTOMER_ID`,blockchain:`stellar`,quoteAssets:{type:`swap`,sourceAsset:`USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN`,targetAsset:`CETES:GCRYUGD5NVARGXT56XEZI5CIFCQETYHAPQQTHO203IQZTHDHH4LATMYW`},sourceAmount:`10`};const defaultSwap={orderId:generateUUID(),publicKey:`YOUR_PUBLIC_KEY`,blockchain:`stellar`,quoteId:`WILL_BE_FILLED_FROM_QUOTE`};const[quoteRequest,setQuoteRequest]=useState(JSON.stringify(defaultQuote,null,2));const[swapRequest,setSwapRequest]=useState(JSON.stringify(defaultSwap,null,2));useEffect(()=>{if(availableAssets.length===0)return;const usdc=availableAssets.find(a=>a.symbol===`USDC`);if(usdc\u0026\u0026!sourceAsset){setSourceAsset(usdc.identifier)}else if(!sourceAsset){setSourceAsset(availableAssets[0].identifier)}const stablebonds=availableAssets.filter(a=>a.isStablebond);const cetes=stablebonds.find(b=>b.symbol.toUpperCase()===`CETES`);if(cetes\u0026\u0026!selectedBond){setSelectedBond(cetes.symbol)}else if(stablebonds.length>0\u0026\u0026!selectedBond){setSelectedBond(stablebonds[0].symbol)}},[availableAssets]);useEffect(()=>{if(!customerId\u0026\u0026orgIdFromApiKey){setCustomerId(orgIdFromApiKey)}},[orgIdFromApiKey]);const getEffectiveSourceAsset=()=>sourceAsset;const getEffectiveTargetAsset=()=>{const asset=availableAssets.find(a=>a.symbol===selectedBond);return asset?.identifier||``};useEffect(()=>{const effectiveSourceAsset=getEffectiveSourceAsset();const effectiveTargetAsset=getEffectiveTargetAsset();if(effectiveSourceAsset\u0026\u0026effectiveTargetAsset\u0026\u0026quoteId){const newQuote={quoteId,customerId:customerId||`YOUR_CUSTOMER_ID`,blockchain:selectedBlockchain,quoteAssets:{type:`swap`,sourceAsset:effectiveSourceAsset,targetAsset:effectiveTargetAsset},sourceAmount:sourceAmount||`10`};setQuoteRequest(JSON.stringify(newQuote,null,2))}},[selectedBlockchain,isSandbox,sourceAsset,selectedBond,customerId,sourceAmount,lookupAssets,quoteId]);useEffect(()=>{if(swapId){const newSwap={orderId:swapId,publicKey:publicKey||`YOUR_PUBLIC_KEY`,blockchain:selectedBlockchain,quoteId:quote?.quoteId||`WILL_BE_FILLED_FROM_QUOTE`};setSwapRequest(JSON.stringify(newSwap,null,2))}},[publicKey,quote,swapId,selectedBlockchain]);useEffect(()=>{if(selectedCustomer){setCustomerId(selectedCustomer)}},[selectedCustomer]);useEffect(()=>{if(selectedWallet){setPublicKey(selectedWallet.publicKey);if(selectedWallet.blockchain!==selectedBlockchain){setSelectedBlockchain(selectedWallet.blockchain)}}},[selectedWallet]);useEffect(()=>{if(wallets?.items?.length>0){const walletsForChain=wallets.items.filter(w=>w.blockchain===selectedBlockchain);if(walletsForChain.length>0){if(!selectedWallet||selectedWallet.blockchain!==selectedBlockchain){setSelectedWallet(walletsForChain[0]);setPublicKey(walletsForChain[0].publicKey)}}else{setPublicKey(``)}}},[selectedBlockchain,wallets]);const makeRequest=async(method,endpoint,body)=>{setLoading(true);setError(null);try{rejectProdKey();const options={method,headers:{\"Content-Type\":`application/json`,\"Authorization\":apiKey}};if(body){options.body=JSON.stringify(body)}const response=await fetch(baseUrl+endpoint,options);const responseText=await response.text();let data=null;try{if(responseText){data=JSON.parse(responseText)}}catch(parseErr){}if(!response.ok){let errorMessage=`HTTP `+response.status;if(data){errorMessage+=`: `+(data.message||data.error||JSON.stringify(data))}else if(responseText){errorMessage+=`: `+responseText.substring(0,200)}else{errorMessage+=` (no response body)`}throw new Error(errorMessage)}return data}catch(err){const msg=err.message||String(err);if(msg.includes(`Failed to fetch`)){setError(`Request failed - likely a 401 Unauthorized (CORS headers not sent on error responses). Verify your API key is correct.`)}else{setError(msg)}throw err}finally{setLoading(false)}};const makeSilentRequest=async(method,endpoint,body)=>{rejectProdKey();const options={method,headers:{\"Content-Type\":`application/json`,\"Authorization\":apiKey}};if(body){options.body=JSON.stringify(body)}const response=await fetch(baseUrl+endpoint,options);if(!response.ok)return null;const text=await response.text();return text?JSON.parse(text):null};const fetchOrgData=async()=>{if(!apiKey)return;setOrgDataLoading(true);try{const customersData=await makeSilentRequest(`POST`,`/ramp/customers`,{pageSize:100,pageNumber:0});if(customersData?.items){setCustomers(customersData);let customerIdToSelect=orgIdFromApiKey||customersData.items[0]?.customerId;if(customerIdToSelect){setSelectedCustomer(customerIdToSelect);setCustomerId(customerIdToSelect);const walletsData=await makeSilentRequest(`POST`,`/ramp/customer/`+customerIdToSelect+`/wallets`,{pageSize:100,pageNumber:0});if(walletsData?.items){setWallets(walletsData);if(walletsData.items.length>0){const firstWallet=walletsData.items[0];setSelectedWallet(firstWallet);setPublicKey(firstWallet.publicKey);setSelectedBlockchain(firstWallet.blockchain)}}}}}catch(err){console.error(`Failed to fetch org data:`,err)}finally{setOrgDataLoading(false)}};useEffect(()=>{if(apiKey\u0026\u0026apiKey.startsWith(`api_`)){fetchOrgData()}},[apiKey,baseUrl]);useEffect(()=>{const fetchStablebonds=async()=>{try{const response=await fetch(baseUrl+`/lookup/stablebonds`);if(response.ok){const data=await response.json();setLookupAssets(data)}}catch(err){console.error(`Failed to fetch stablebonds:`,err)}};fetchStablebonds()},[baseUrl]);useEffect(()=>{const fetchCurrencies=async()=>{try{const response=await fetch(baseUrl+`/lookup/exchange_rate`);if(response.ok){const data=await response.json();const currencyList=Object.keys(data).filter(key=>key.startsWith(`usd_to_`)).map(key=>{const code=key.replace(`usd_to_`,``).toUpperCase();return{currency:code,name:code}}).filter(c=>c.currency!==`USD`);setCurrencies(currencyList)}}catch(err){console.error(`Failed to fetch currencies:`,err)}};fetchCurrencies()},[baseUrl]);const fetchWalletsForCustomer=async custId=>{try{const walletsData=await makeRequest(`POST`,`/ramp/customer/`+custId+`/wallets`,{pageSize:100,pageNumber:0});setWallets(walletsData);if(walletsData?.items?.length>0){const firstWallet=walletsData.items[0];setSelectedWallet(firstWallet);setPublicKey(firstWallet.publicKey);setSelectedBlockchain(firstWallet.blockchain)}else{setSelectedWallet(null);setPublicKey(``)}return walletsData}catch(err){console.error(`Failed to fetch wallets for customer:`,err);setWallets({items:[]});return{items:[]}}};const handleCustomerChange=async custId=>{setSelectedCustomer(custId);setCustomerId(custId);await fetchWalletsForCustomer(custId)};const handleWalletChange=walletId=>{const wallet=wallets?.items?.find(w=>w.walletId===walletId);if(wallet){setSelectedWallet(wallet);setPublicKey(wallet.publicKey);setSelectedBlockchain(wallet.blockchain)}};const getWalletsForCustomer=()=>{if(!wallets?.items)return[];return wallets.items};const getWalletsForBlockchain=()=>{if(!wallets?.items)return[];return wallets.items.filter(w=>w.blockchain===selectedBlockchain)};const createQuote=async()=>{setStepErrors(prev=>({...prev,step3:null}));try{const body=JSON.parse(quoteRequest);const data=await makeRequest(`POST`,`/ramp/quote`,body);setQuote(data);setQuoteId(generateUUID());setSwapId(generateUUID());const swapBody=JSON.parse(swapRequest);swapBody.quoteId=data.quoteId;swapBody.publicKey=publicKey;swapBody.blockchain=selectedBlockchain;setSwapRequest(JSON.stringify(swapBody,null,2))}catch(err){setStepErrors(prev=>({...prev,step3:err.message||String(err)}))}};const createSwap=async()=>{setStepErrors(prev=>({...prev,step4:null}));try{const body=JSON.parse(swapRequest);const data=await makeRequest(`POST`,`/ramp/swap`,body);setSwap(data||{accepted:true});setSwapId(generateUUID())}catch(err){setStepErrors(prev=>({...prev,step4:err.message||String(err)}))}};const[copied,setCopied]=useState(null);const copyToClipboard=(text,id)=>{navigator.clipboard.writeText(text);setCopied(id);setTimeout(()=>setCopied(null),2e3)};const getCurl=(method,endpoint,body)=>{let cmd=`curl`;if(method!==`GET`)cmd+=` -X `+method;cmd+=` \"`+baseUrl+endpoint+`\"`;cmd+=` \\\\\n -H \"Authorization: `+(apiKey||`YOUR_API_KEY`)+`\"`;if(body){cmd+=` \\\\\n -H \"Content-Type: application/json\"`;cmd+=` \\\\\n -d '`+JSON.stringify(body)+`'`}return cmd};const getFetch=(method,endpoint,body)=>{const opts={method,headers:{\"Authorization\":apiKey||`YOUR_API_KEY`}};if(body){opts.headers[`Content-Type`]=`application/json`;opts.body=`JSON.stringify(`+JSON.stringify(body)+`)`}let code=`const response = await fetch(\"`+baseUrl+endpoint+`\", {\n`;code+=` method: \"`+method+`\",\n`;code+=` headers: {\n`;code+=` \"Authorization\": \"`+(apiKey||`YOUR_API_KEY`)+`\"`;if(body){code+=`,\n \"Content-Type\": \"application/json\"`}code+=`\n }`;if(body){code+=`,\n body: JSON.stringify(`+JSON.stringify(body,null,2).split(`\n`).join(`\n `)+`)`}code+=`\n});\n`;code+=`const data = await response.json();`;return code};const buttonStyle=(enabled,completed)=>({padding:`10px 20px`,margin:`5px`,borderRadius:`6px`,border:`none`,cursor:enabled?`pointer`:`not-allowed`,backgroundColor:completed?`#22c55e`:enabled?`#3b82f6`:`#6b7280`,color:`white`,opacity:loading?.7:1,fontWeight:500});const secondaryButtonStyle={padding:`8px 12px`,margin:`5px`,borderRadius:`6px`,border:`1px solid #d1d5db`,cursor:`pointer`,backgroundColor:`transparent`,color:`#6b7280`,fontSize:`13px`};const codeBlockStyle={width:`100%`,maxHeight:`300px`,overflow:`auto`,padding:`16px`,fontFamily:`ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, monospace`,fontSize:`13px`,lineHeight:`1.5`,borderRadius:`8px`,backgroundColor:`#f8fafc`,color:`#334155`,border:`1px solid #e2e8f0`,margin:0,whiteSpace:`pre-wrap`,wordBreak:`break-word`,boxSizing:`border-box`};const tryItButtonStyle=(enabled,completed)=>({display:`inline-flex`,alignItems:`center`,gap:`6px`,padding:`8px 16px`,borderRadius:`20px`,border:`none`,cursor:enabled?`pointer`:`not-allowed`,backgroundColor:completed?`#22c55e`:enabled?`#0d9488`:`#9ca3af`,color:`white`,fontSize:`14px`,fontWeight:500,opacity:loading?.7:1});const inputStyle={width:`100%`,padding:`8px 10px`,borderRadius:`4px`,border:`1px solid #d1d5db`,fontSize:`13px`,fontFamily:`ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, monospace`,boxSizing:`border-box`};const selectStyle={...inputStyle,backgroundColor:`white`,cursor:`pointer`,appearance:`auto`,WebkitAppearance:`menulist`,MozAppearance:`menulist`};const labelStyle={display:`block`,fontSize:`12px`,fontWeight:600,color:`#374151`,marginBottom:`4px`};const fieldGroupStyle={marginBottom:`12px`};const stepErrorStyle={padding:`12px`,backgroundColor:`#fef2f2`,color:`#dc2626`,borderRadius:`6px`,marginTop:`12px`,fontSize:`13px`,border:`1px solid #fecaca`};const renderStepError=stepKey=>{const err=stepErrors[stepKey];if(!err)return null;return _jsxs(`div`,{style:stepErrorStyle,children:[_jsx(`strong`,{children:`Error:`}),` `,err]})};const renderRandomIdBox=(label,value,onRegenerate)=>_jsxs(`div`,{style:fieldGroupStyle,children:[_jsx(`label`,{style:labelStyle,children:label}),_jsxs(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`,padding:`8px 10px`,backgroundColor:`#f0f9ff`,border:`1px dashed #3b82f6`,borderRadius:`4px`,fontFamily:`ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, monospace`,fontSize:`12px`,color:`#1e40af`},children:[_jsx(`span`,{style:{flex:1,overflow:`hidden`,textOverflow:`ellipsis`},children:value}),_jsx(`button`,{onClick:onRegenerate,title:`Generate new random ID`,style:{background:`none`,border:`none`,cursor:`pointer`,fontSize:`16px`,padding:`2px 6px`,borderRadius:`4px`,transition:`background-color 0.2s`},onMouseOver:e=>e.target.style.backgroundColor=`#dbeafe`,onMouseOut:e=>e.target.style.backgroundColor=`transparent`,children:`🎲`})]}),_jsx(`div`,{style:{fontSize:`10px`,color:`#6b7280`,marginTop:`2px`},children:`Auto-generated UUID`})]});return _jsxs(`div`,{style:{padding:`20px`,border:`1px solid #e5e7eb`,borderRadius:`8px`,marginTop:`20px`},children:[_jsxs(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,marginBottom:`20px`},children:[_jsx(`h3`,{style:{margin:0},children:`Interactive Swap Tutorial`}),sandboxOnly?_jsx(`span`,{style:{fontSize:12,fontWeight:600,color:`#166534`,padding:`4px 10px`,backgroundColor:`#f0fdf4`,borderRadius:999,border:`1px solid #bbf7d0`},children:`Sandbox only`}):_jsxs(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`},children:[_jsx(`span`,{style:{fontSize:`14px`,color:isSandbox?`#111827`:`#6b7280`,fontWeight:isSandbox?600:400},children:`Sandbox`}),_jsx(`button`,{onClick:()=>setEnvSandbox(!envSandbox),style:{position:`relative`,width:`48px`,height:`24px`,borderRadius:`12px`,border:`none`,backgroundColor:isSandbox?`#22c55e`:`#3b82f6`,cursor:`pointer`,transition:`background-color 0.2s`},children:_jsx(`span`,{style:{position:`absolute`,top:`2px`,left:isSandbox?`2px`:`26px`,width:`20px`,height:`20px`,borderRadius:`50%`,backgroundColor:`white`,transition:`left 0.2s`}})}),_jsx(`span`,{style:{fontSize:`14px`,color:isSandbox?`#6b7280`:`#111827`,fontWeight:isSandbox?400:600},children:`Production`})]})]}),_jsxs(`div`,{style:{marginBottom:`20px`,padding:`16px`,backgroundColor:`#f3f4f6`,borderRadius:`6px`},children:[_jsxs(`div`,{style:{marginBottom:`12px`},children:[_jsx(`span`,{style:{fontSize:`12px`,color:`#6b7280`},children:`Host: `}),_jsx(`code`,{style:{fontSize:`12px`},children:baseUrl})]}),_jsxs(`div`,{children:[_jsxs(`div`,{style:{display:`flex`,alignItems:`baseline`,gap:`8px`,marginBottom:`8px`},children:[_jsx(`label`,{style:{fontWeight:600},children:`API Key`}),_jsxs(`span`,{style:{fontSize:`12px`,color:`#6b7280`},children:[`Find it under 'API Keys' at`,` `,_jsx(_components.a,{href:isSandbox?`https://sandbox.etherfuse.com/ramp?view=manage`:`https://app.etherfuse.com/ramp?view=manage`,target:`_blank`,rel:`noopener noreferrer`,style:{color:`#3b82f6`},children:isSandbox?`sandbox.etherfuse.com/ramp`:`app.etherfuse.com/ramp`})]})]}),_jsx(`input`,{type:`password`,value:apiKey,onChange:e=>handleApiKeyChange(e.target.value),placeholder:`Paste your API key (api_sand:...)`,style:{width:`100%`,padding:`10px`,borderRadius:`4px`,border:`1px solid ${prodKeyBlocked?`#fca5a5`:`#d1d5db`}`,fontSize:`14px`,fontFamily:`monospace`,boxSizing:`border-box`}})]}),prodKeyBlocked\u0026\u0026_jsxs(`div`,{style:{marginTop:8,padding:`8px 12px`,backgroundColor:`#fef2f2`,borderRadius:4,border:`1px solid #fecaca`,fontSize:12,color:`#dc2626`},children:[`Production keys are not accepted in this playground. Use a sandbox key from`,` `,_jsx(`a`,{href:`https://sandbox.etherfuse.com/ramp?view=manage`,target:`_blank`,rel:`noopener noreferrer`,style:{color:`#dc2626`,textDecoration:`underline`},children:`sandbox.etherfuse.com/ramp`}),`.`]}),orgIdFromApiKey\u0026\u0026_jsxs(`div`,{style:{marginTop:`12px`,padding:`8px 12px`,backgroundColor:`#f0fdf4`,borderRadius:`4px`,border:`1px solid #bbf7d0`},children:[_jsxs(`span`,{style:{fontSize:`12px`,color:`#166534`},children:[_jsx(`strong`,{children:`Your org →`}),` `,orgIdFromApiKey]}),orgDataLoading\u0026\u0026_jsx(`span`,{style:{fontSize:`12px`,color:`#6b7280`,marginLeft:`12px`},children:`Loading org data...`}),!orgDataLoading\u0026\u0026customers?.items?.length>0\u0026\u0026_jsxs(`span`,{style:{fontSize:`12px`,color:`#166534`,marginLeft:`12px`},children:[`(`,customers.items.length,` customers, `,wallets?.items?.length||0,` wallets)`]})]}),_jsx(`p`,{style:{fontSize:`12px`,color:`#6b7280`,marginTop:`12px`,marginBottom:0},children:`Your API key is stored in your browser's session storage and cleared when you close the tab.`})]}),error\u0026\u0026_jsxs(`div`,{style:{padding:`12px`,backgroundColor:`#fef2f2`,color:`#dc2626`,borderRadius:`6px`,marginBottom:`16px`},children:[`Error: `,error]}),_jsxs(`div`,{style:{marginBottom:`24px`,border:`1px solid #e5e7eb`,borderRadius:`8px`,overflow:`hidden`},children:[_jsxs(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,padding:`12px 16px`,backgroundColor:`#f8fafc`,borderBottom:`1px solid #e5e7eb`},children:[_jsxs(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`},children:[_jsx(`span`,{style:{padding:`4px 8px`,backgroundColor:`#6366f1`,color:`white`,borderRadius:`4px`,fontSize:`12px`,fontWeight:600},children:`Step 1`}),_jsx(`span`,{style:{fontSize:`14px`,fontWeight:500},children:`Select Customer \u0026 Wallet`})]}),orgDataLoading\u0026\u0026_jsx(`span`,{style:{fontSize:`12px`,color:`#6b7280`},children:`Loading...`})]}),_jsxs(`div`,{style:{padding:`16px`},children:[_jsx(`p`,{style:{color:`#6b7280`,margin:0,marginBottom:`16px`},children:`Select the customer and wallet for the swap. Data is auto-loaded when you enter your API key.`}),customers?.items?.length>0\u0026\u0026_jsxs(`div`,{style:{marginTop:`16px`},children:[_jsxs(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`,marginBottom:`8px`},children:[_jsx(`span`,{style:{padding:`4px 8px`,backgroundColor:`#dcfce7`,color:`#166534`,borderRadius:`4px`,fontSize:`12px`,fontWeight:500},children:`200`}),_jsxs(`span`,{style:{fontSize:`13px`,color:`#6b7280`},children:[`Found `,customers.items?.length||0,` customers, `,wallets?.items?.length||0,` wallets for selected customer`]})]}),_jsxs(`div`,{style:{backgroundColor:`#f9fafb`,padding:`16px`,borderRadius:`6px`,border:`1px solid #e5e7eb`},children:[_jsxs(`div`,{style:{display:`grid`,gridTemplateColumns:`repeat(auto-fit, minmax(250px, 1fr))`,gap:`12px`},children:[_jsxs(`div`,{style:fieldGroupStyle,children:[_jsx(`label`,{style:labelStyle,children:`Customer`}),_jsxs(`select`,{value:selectedCustomer,onChange:e=>handleCustomerChange(e.target.value),style:selectStyle,children:[orgIdFromApiKey\u0026\u0026_jsxs(`option`,{value:orgIdFromApiKey,children:[`Your org → `,customers.items?.find(c=>c.customerId===orgIdFromApiKey)?.displayName||orgIdFromApiKey.substring(0,8)+`...`]}),customers.items?.filter(c=>c.customerId!==orgIdFromApiKey).map(c=>_jsx(`option`,{value:c.customerId,children:c.displayName||c.customerId.substring(0,8)+`...`},c.customerId))]}),_jsx(`div`,{style:{fontSize:`11px`,color:`#6b7280`,marginTop:`4px`,fontFamily:`monospace`},children:selectedCustomer})]}),_jsxs(`div`,{style:fieldGroupStyle,children:[_jsxs(`label`,{style:labelStyle,children:[`Wallet `,selectedWallet?.blockchain\u0026\u0026_jsxs(`span`,{style:{color:`#6b7280`},children:[`(`,selectedWallet.blockchain,`)`]})]}),_jsxs(`select`,{value:selectedWallet?.walletId||``,onChange:e=>handleWalletChange(e.target.value),style:selectStyle,children:[getWalletsForCustomer().map(w=>_jsxs(`option`,{value:w.walletId,children:[`[`,w.blockchain,`] `,w.publicKey.substring(0,8),`...`,w.publicKey.slice(-4)]},w.walletId)),getWalletsForCustomer().length===0\u0026\u0026_jsx(`option`,{value:``,children:`No wallets for this customer`})]}),_jsx(`div`,{style:{fontSize:`11px`,color:`#6b7280`,marginTop:`4px`,fontFamily:`monospace`},children:publicKey||`No wallet selected`})]})]}),_jsxs(`div`,{style:{display:`flex`,flexWrap:`wrap`,gap:`8px`,marginTop:`12px`},children:[_jsx(`button`,{onClick:()=>copyToClipboard(getCurl(`POST`,`/ramp/customers`,{pageSize:100,pageNumber:0}),`curl-customers`),style:secondaryButtonStyle,children:copied===`curl-customers`?`✓ Copied`:`Copy customers curl`}),_jsx(`button`,{onClick:()=>copyToClipboard(getFetch(`POST`,`/ramp/customers`,{pageSize:100,pageNumber:0}),`fetch-customers`),style:secondaryButtonStyle,children:copied===`fetch-customers`?`✓ Copied`:`Copy customers fetch`}),_jsx(`button`,{onClick:()=>copyToClipboard(getCurl(`POST`,`/ramp/customer/`+selectedCustomer+`/wallets`,{pageSize:100,pageNumber:0}),`curl-wallets`),style:secondaryButtonStyle,children:copied===`curl-wallets`?`✓ Copied`:`Copy wallets curl`}),_jsx(`button`,{onClick:()=>copyToClipboard(getFetch(`POST`,`/ramp/customer/`+selectedCustomer+`/wallets`,{pageSize:100,pageNumber:0}),`fetch-wallets`),style:secondaryButtonStyle,children:copied===`fetch-wallets`?`✓ Copied`:`Copy wallets fetch`})]})]})]})]})]}),_jsxs(`div`,{style:{marginBottom:`24px`,border:`1px solid #e5e7eb`,borderRadius:`8px`,overflow:`hidden`,opacity:selectedWallet?1:.5},children:[_jsx(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,padding:`12px 16px`,backgroundColor:`#f8fafc`,borderBottom:`1px solid #e5e7eb`},children:_jsxs(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`},children:[_jsx(`span`,{style:{padding:`4px 8px`,backgroundColor:`#6366f1`,color:`white`,borderRadius:`4px`,fontSize:`12px`,fontWeight:600},children:`Step 2`}),_jsx(`span`,{style:{fontSize:`14px`,fontWeight:500},children:`Select Assets`})]})}),_jsxs(`div`,{style:{padding:`16px`},children:[_jsx(`p`,{style:{color:`#6b7280`,margin:0,marginBottom:`16px`},children:`Choose which assets to swap. You can use the public lookup endpoint or get personalized opportunities via the ramp/assets endpoint.`}),selectedWallet\u0026\u0026_jsx(`div`,{style:{backgroundColor:`#f9fafb`,padding:`16px`,borderRadius:`6px`,border:`1px solid #e5e7eb`},children:_jsxs(`div`,{style:{padding:`12px`,backgroundColor:`#eff6ff`,border:`1px solid #bfdbfe`,borderRadius:`6px`,marginBottom:`16px`},children:[_jsxs(`div`,{style:{fontSize:`12px`,color:`#1e40af`,marginBottom:`8px`},children:[_jsx(`strong`,{children:`Asset Data Source:`}),` Assets below are populated from the`,` `,assetSource===`lookup`?_jsx(_components.a,{href:`/api-reference/lookup/stablebonds`,style:{color:`#2563eb`},children:`/lookup/stablebonds`}):_jsx(_components.a,{href:`/api-reference/ramp/assets`,style:{color:`#2563eb`},children:`/ramp/assets`}),` endpoint.`,assetSource===`currency`\u0026\u0026_jsx(`span`,{children:` This provides personalized swap opportunities for your customer.`})]}),_jsxs(`div`,{style:{display:`flex`,borderRadius:`6px`,overflow:`hidden`,border:`1px solid #3b82f6`},children:[_jsx(`button`,{onClick:()=>setAssetSource(`lookup`),style:{flex:1,padding:`8px 12px`,border:`none`,backgroundColor:assetSource===`lookup`?`#3b82f6`:`white`,color:assetSource===`lookup`?`white`:`#3b82f6`,cursor:`pointer`,fontSize:`12px`,fontWeight:500},children:`Lookup (All Stablebonds)`}),_jsx(`button`,{onClick:()=>setAssetSource(`currency`),style:{flex:1,padding:`8px 12px`,border:`none`,borderLeft:`1px solid #3b82f6`,backgroundColor:assetSource===`currency`?`#3b82f6`:`white`,color:assetSource===`currency`?`white`:`#3b82f6`,cursor:`pointer`,fontSize:`12px`,fontWeight:500},children:`By Currency (Personalized)`})]}),assetSource===`currency`\u0026\u0026_jsxs(`div`,{style:{marginTop:`12px`},children:[_jsx(`label`,{style:{...labelStyle,marginBottom:`4px`},children:`Select Currency`}),_jsxs(`select`,{value:selectedCurrency,onChange:e=>setSelectedCurrency(e.target.value),style:{...selectStyle,maxWidth:`200px`},children:[_jsx(`option`,{value:``,children:`Choose a currency...`}),currencies.map(curr=>_jsx(`option`,{value:curr.currency,children:curr.currency},curr.currency))]}),assetsLoading\u0026\u0026_jsx(`span`,{style:{fontSize:`11px`,color:`#6b7280`,marginLeft:`8px`},children:`Loading assets...`})]}),assetSource===`lookup`\u0026\u0026_jsxs(`div`,{style:{display:`flex`,gap:`8px`,marginTop:`12px`},children:[_jsx(`button`,{onClick:()=>copyToClipboard(`curl \"`+baseUrl+`/lookup/stablebonds\"`,`curl-lookup`),style:secondaryButtonStyle,children:copied===`curl-lookup`?`✓ Copied`:`Copy lookup curl`}),_jsx(`button`,{onClick:()=>copyToClipboard(`const response = await fetch(\"`+baseUrl+`/lookup/stablebonds\");\nconst data = await response.json();`,`fetch-lookup`),style:secondaryButtonStyle,children:copied===`fetch-lookup`?`✓ Copied`:`Copy lookup fetch`})]}),assetSource===`currency`\u0026\u0026selectedCurrency\u0026\u0026_jsxs(`div`,{style:{display:`flex`,gap:`8px`,marginTop:`12px`},children:[_jsx(`button`,{onClick:()=>copyToClipboard(`curl \"`+baseUrl+`/ramp/assets?blockchain=`+selectedBlockchain+`\u0026currency=`+selectedCurrency.toLowerCase()+`\u0026wallet=`+publicKey+`\" \\\\\n -H \"Authorization: `+(apiKey||`YOUR_API_KEY`)+`\"`,`curl-assets`),style:secondaryButtonStyle,children:copied===`curl-assets`?`✓ Copied`:`Copy assets curl`}),_jsx(`button`,{onClick:()=>copyToClipboard(`const response = await fetch(\"`+baseUrl+`/ramp/assets?blockchain=`+selectedBlockchain+`\u0026currency=`+selectedCurrency.toLowerCase()+`\u0026wallet=`+publicKey+`\", {\n headers: { \"Authorization\": \"`+(apiKey||`YOUR_API_KEY`)+`\" }\n});\nconst data = await response.json();`,`fetch-assets`),style:secondaryButtonStyle,children:copied===`fetch-assets`?`✓ Copied`:`Copy assets fetch`})]})]})})]})]}),_jsxs(`div`,{style:{marginBottom:`24px`,border:`1px solid #e5e7eb`,borderRadius:`8px`,overflow:`hidden`,opacity:selectedWallet?1:.5},children:[_jsxs(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,padding:`12px 16px`,backgroundColor:`#f8fafc`,borderBottom:`1px solid #e5e7eb`},children:[_jsxs(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`},children:[_jsx(`span`,{style:{padding:`4px 8px`,backgroundColor:`#6366f1`,color:`white`,borderRadius:`4px`,fontSize:`12px`,fontWeight:600},children:`Step 3`}),_jsx(`span`,{style:{padding:`4px 8px`,backgroundColor:`#3b82f6`,color:`white`,borderRadius:`4px`,fontSize:`12px`,fontWeight:600},children:`POST`}),_jsx(`span`,{style:{fontFamily:`monospace`,fontSize:`14px`},children:`/ramp/quote`})]}),_jsxs(`button`,{onClick:createQuote,disabled:!selectedWallet||!apiKey||loading,style:tryItButtonStyle(selectedWallet\u0026\u0026apiKey\u0026\u0026!loading),children:[loading?`Loading...`:`Try it`,` `,!loading\u0026\u0026_jsx(`span`,{children:`▶`})]})]}),_jsxs(`div`,{style:{padding:`16px`},children:[_jsxs(`p`,{style:{color:`#6b7280`,margin:0,marginBottom:`16px`},children:[`Generate a quote for the swap.`,` `,_jsx(_components.a,{href:`/api-reference/quotes/create-quote`,style:{color:`#0d9488`},children:`View API reference →`})]}),selectedWallet\u0026\u0026_jsxs(`div`,{style:{backgroundColor:`#f9fafb`,padding:`16px`,borderRadius:`6px`,marginBottom:`16px`,border:`1px solid #e5e7eb`},children:[_jsxs(`div`,{style:{display:`flex`,flexWrap:`wrap`,gap:`16px`,marginBottom:`16px`,paddingBottom:`16px`,borderBottom:`1px solid #e5e7eb`},children:[_jsxs(`div`,{style:{display:`flex`,alignItems:`center`,gap:`6px`},children:[_jsx(`span`,{style:{fontSize:`11px`,color:`#6b7280`,textTransform:`uppercase`,fontWeight:600},children:`Customer:`}),_jsx(`span`,{style:{padding:`4px 8px`,backgroundColor:`#f3f4f6`,border:`1px solid #d1d5db`,borderRadius:`4px`,fontSize:`11px`,fontFamily:`ui-monospace, monospace`,color:`#374151`},children:customerId?customerId.substring(0,8)+`...`:`Not selected`})]}),_jsxs(`div`,{style:{display:`flex`,alignItems:`center`,gap:`6px`},children:[_jsx(`span`,{style:{fontSize:`11px`,color:`#6b7280`,textTransform:`uppercase`,fontWeight:600},children:`Blockchain:`}),_jsx(`span`,{style:{padding:`4px 8px`,backgroundColor:`#f3f4f6`,border:`1px solid #d1d5db`,borderRadius:`4px`,fontSize:`11px`,fontFamily:`ui-monospace, monospace`,color:`#374151`},children:selectedBlockchain})]}),_jsx(`span`,{style:{fontSize:`10px`,color:`#9ca3af`,alignSelf:`center`},children:`from Step 1`})]}),_jsxs(`div`,{style:{display:`grid`,gridTemplateColumns:`repeat(auto-fit, minmax(200px, 1fr))`,gap:`12px`,marginBottom:`16px`},children:[_jsxs(`div`,{style:fieldGroupStyle,children:[_jsx(`label`,{style:labelStyle,children:`Source Asset`}),_jsxs(`select`,{value:sourceAsset,onChange:e=>setSourceAsset(e.target.value),style:selectStyle,disabled:assetSource===`currency`\u0026\u0026(!selectedCurrency||assetsLoading),children:[availableAssets.map(asset=>_jsx(`option`,{value:asset.identifier,children:asset.symbol},asset.identifier)),availableAssets.length===0\u0026\u0026_jsx(`option`,{value:``,children:`No assets available`})]})]}),_jsxs(`div`,{style:fieldGroupStyle,children:[_jsx(`label`,{style:labelStyle,children:`Target Asset`}),_jsxs(`select`,{value:selectedBond,onChange:e=>setSelectedBond(e.target.value),style:selectStyle,disabled:assetSource===`currency`\u0026\u0026(!selectedCurrency||assetsLoading),children:[targetAssets.map(asset=>_jsx(`option`,{value:asset.symbol,children:asset.symbol},asset.identifier)),targetAssets.length===0\u0026\u0026_jsx(`option`,{value:``,children:`No assets available`})]})]}),_jsxs(`div`,{style:fieldGroupStyle,children:[_jsx(`label`,{style:labelStyle,children:`Amount`}),_jsx(`input`,{type:`text`,value:sourceAmount,onChange:e=>setSourceAmount(e.target.value),placeholder:`10`,style:inputStyle})]})]}),_jsx(`div`,{style:{marginBottom:`16px`},children:renderRandomIdBox(`Quote ID`,quoteId,()=>setQuoteId(generateUUID()))}),_jsxs(`div`,{children:[_jsx(`label`,{style:labelStyle,children:`Request Body`}),_jsx(`pre`,{style:{...codeBlockStyle,maxHeight:`150px`,margin:0},children:quoteRequest})]})]}),_jsxs(`div`,{style:{display:`flex`,gap:`8px`,marginTop:`12px`},children:[_jsx(`button`,{onClick:()=>{try{copyToClipboard(getCurl(`POST`,`/ramp/quote`,JSON.parse(quoteRequest)),`curl2`)}catch(e){}},style:secondaryButtonStyle,children:copied===`curl2`?`✓ Copied`:`Copy curl`}),_jsx(`button`,{onClick:()=>{try{copyToClipboard(getFetch(`POST`,`/ramp/quote`,JSON.parse(quoteRequest)),`fetch2`)}catch(e){}},style:secondaryButtonStyle,children:copied===`fetch2`?`✓ Copied`:`Copy fetch`})]}),renderStepError(`step3`),quote\u0026\u0026_jsxs(`div`,{children:[_jsxs(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`,marginBottom:`8px`},children:[_jsx(`span`,{style:{padding:`4px 8px`,backgroundColor:`#dcfce7`,color:`#166534`,borderRadius:`4px`,fontSize:`12px`,fontWeight:500},children:`200`}),_jsx(`span`,{style:{fontSize:`13px`,color:`#6b7280`},children:`Success`})]}),_jsx(`pre`,{style:codeBlockStyle,children:JSON.stringify(quote,null,2)})]})]})]}),_jsxs(`div`,{style:{marginBottom:`24px`,border:`1px solid #e5e7eb`,borderRadius:`8px`,overflow:`hidden`,opacity:quote?1:.5},children:[_jsxs(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,padding:`12px 16px`,backgroundColor:`#f8fafc`,borderBottom:`1px solid #e5e7eb`},children:[_jsxs(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`},children:[_jsx(`span`,{style:{padding:`4px 8px`,backgroundColor:`#6366f1`,color:`white`,borderRadius:`4px`,fontSize:`12px`,fontWeight:600},children:`Step 4`}),_jsx(`span`,{style:{padding:`4px 8px`,backgroundColor:`#3b82f6`,color:`white`,borderRadius:`4px`,fontSize:`12px`,fontWeight:600},children:`POST`}),_jsx(`span`,{style:{fontFamily:`monospace`,fontSize:`14px`},children:`/ramp/swap`})]}),_jsxs(`button`,{onClick:createSwap,disabled:!quote||!apiKey||loading,style:tryItButtonStyle(quote\u0026\u0026apiKey\u0026\u0026!loading),children:[loading?`Loading...`:`Try it`,` `,!loading\u0026\u0026_jsx(`span`,{children:`▶`})]})]}),_jsxs(`div`,{style:{padding:`16px`},children:[_jsxs(`p`,{style:{color:`#6b7280`,margin:0,marginBottom:`16px`},children:[`Execute the swap with the quote from the previous step.`,` `,_jsx(_components.a,{href:`/api-reference/swaps/create-swap`,style:{color:`#0d9488`},children:`View API reference →`})]}),quote\u0026\u0026_jsxs(`div`,{style:{backgroundColor:`#f9fafb`,padding:`16px`,borderRadius:`6px`,marginBottom:`16px`,border:`1px solid #e5e7eb`},children:[_jsxs(`div`,{style:{display:`grid`,gridTemplateColumns:`repeat(auto-fit, minmax(250px, 1fr))`,gap:`12px`},children:[renderRandomIdBox(`Order ID`,swapId,()=>setSwapId(generateUUID())),_jsxs(`div`,{style:fieldGroupStyle,children:[_jsx(`label`,{style:labelStyle,children:`Wallet (Public Key)`}),wallets?.items?.length>0?_jsxs(`select`,{value:publicKey,onChange:e=>{setPublicKey(e.target.value);const wallet=wallets.items.find(w=>w.publicKey===e.target.value);if(wallet)setSelectedWallet(wallet)},style:selectStyle,children:[getWalletsForBlockchain().map(w=>_jsx(`option`,{value:w.publicKey,children:w.displayName||w.publicKey.substring(0,12)+`...`+w.publicKey.slice(-6)},w.walletId)),getWalletsForBlockchain().length===0\u0026\u0026_jsxs(`option`,{value:``,children:[`No wallets for `,selectedBlockchain]})]}):_jsx(`input`,{type:`text`,value:publicKey,onChange:e=>setPublicKey(e.target.value),placeholder:`Enter wallet public key`,style:inputStyle}),_jsx(`div`,{style:{fontSize:`11px`,color:`#6b7280`,marginTop:`4px`,fontFamily:`monospace`},children:publicKey||`No wallet selected`})]})]}),_jsxs(`div`,{style:{marginTop:`12px`},children:[_jsx(`label`,{style:labelStyle,children:`Request Body`}),_jsx(`pre`,{style:{...codeBlockStyle,maxHeight:`100px`,margin:0},children:swapRequest})]})]}),_jsxs(`div`,{style:{display:`flex`,gap:`8px`,marginTop:`12px`},children:[_jsx(`button`,{onClick:()=>{try{copyToClipboard(getCurl(`POST`,`/ramp/swap`,JSON.parse(swapRequest)),`curl3`)}catch(e){}},style:secondaryButtonStyle,children:copied===`curl3`?`✓ Copied`:`Copy curl`}),_jsx(`button`,{onClick:()=>{try{copyToClipboard(getFetch(`POST`,`/ramp/swap`,JSON.parse(swapRequest)),`fetch3`)}catch(e){}},style:secondaryButtonStyle,children:copied===`fetch3`?`✓ Copied`:`Copy fetch`})]}),renderStepError(`step4`),swap\u0026\u0026_jsxs(`div`,{children:[_jsxs(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`,marginBottom:`8px`},children:[_jsx(`span`,{style:{padding:`4px 8px`,backgroundColor:`#dcfce7`,color:`#166534`,borderRadius:`4px`,fontSize:`12px`,fontWeight:500},children:`200`}),_jsx(`span`,{style:{fontSize:`13px`,color:`#6b7280`},children:`Success (empty body)`})]}),_jsxs(`div`,{style:{padding:`12px`,backgroundColor:`#f0fdf4`,color:`#16a34a`,borderRadius:`6px`,marginTop:`12px`},children:[`✓ Swap accepted! This endpoint returns an empty 200. Watch the `,_jsx(`code`,{children:`swap_updated`}),` webhook for the `,_jsx(`code`,{children:`sendTransaction`}),` to sign and submit.`]})]})]})]})]})};function _createMdxContent(props){const _components={a:`a`,code:`code`,li:`li`,p:`p`,pre:`pre`,span:`span`,strong:`strong`,tbody:`tbody`,td:`td`,th:`th`,thead:`thead`,tr:`tr`,ul:`ul`,..._provideComponents(),...props.components},{CodeBlock,CodeGroup,Expandable,Heading,Info,Step,Steps,Table,Tip,Warning,_MdxComponentBoundary}=_components;if(!CodeBlock)_missingMdxReference(`CodeBlock`,true);if(!CodeGroup)_missingMdxReference(`CodeGroup`,true);if(!Expandable)_missingMdxReference(`Expandable`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!Info)_missingMdxReference(`Info`,true);if(!Step)_missingMdxReference(`Step`,true);if(!Steps)_missingMdxReference(`Steps`,true);if(!Table)_missingMdxReference(`Table`,true);if(!Tip)_missingMdxReference(`Tip`,true);if(!Warning)_missingMdxReference(`Warning`,true);if(!_MdxComponentBoundary)_missingMdxReference(`_MdxComponentBoundary`,true);return _jsxs(_Fragment,{children:[_jsx(Info,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Prerequisite:`}),` You need a KYC-approved wallet. Register one with `,_jsx(_components.a,{href:`/api-reference/wallets/register-wallet`,children:`POST /ramp/wallet`}),` (set `,_jsx(_components.code,{children:`claimOwnership: true`}),` to inherit your organization’s KYB approval), or onboard a customer wallet via `,_jsx(_components.a,{href:`/guides/kyc-websdk`,children:`KYC WebSDK`}),`. Swaps do not require a bank account.\nFor onboarding your customers, see `,_jsx(_components.a,{href:`/guides/onboarding`,children:`KYC Overview`}),`.`]})}),`\n`,_jsx(Warning,{children:_jsxs(_components.p,{children:[`Swaps are currently available on `,_jsx(_components.strong,{children:`Stellar`}),`, `,_jsx(_components.strong,{children:`Solana`}),`, and `,_jsx(_components.strong,{children:`Monad`}),`, and the source and destination must be on the `,_jsx(_components.strong,{children:`same chain`}),` (no cross-chain swaps). The other EVM chains (Base, Polygon, Avalanche) support direct on/off-ramps but do not yet support token-to-token swaps.`]})}),`\n`,_jsx(Info,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Stellar swaps need a funded, trustlined wallet.`}),` The wallet must already hold XLM and a trustline for the asset it will receive — otherwise Etherfuse can’t build the swap transaction and no `,_jsx(_components.code,{children:`swap_updated`}),` webhook fires. See the `,_jsx(_components.a,{href:`/guides/chains/stellar#offramps-and-swaps-fund-the-wallet-first`,children:`Stellar`}),`, `,_jsx(_components.a,{href:`/guides/chains/solana`,children:`Solana`}),`, and `,_jsx(_components.a,{href:`/guides/chains/monad`,children:`Monad`}),` chain guides for per-chain setup.`]})}),`\n`,_jsx(Heading,{level:`2`,id:`swap-flow`,children:`Swap Flow`}),`\n`,_jsxs(Steps,{children:[_jsx(Step,{title:`Discover Assets`,children:_jsxs(Expandable,{title:`Details`,children:[_jsx(_components.p,{children:`Either of these endpoints will give you the asset identifiers needed for quotes:`}),_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[_jsx(_components.a,{href:`/api-reference/assets/list-assets`,children:`GET /ramp/assets`}),` — Requires auth. Returns all rampable stablecoins and stablebonds for the specified blockchain. The `,_jsx(_components.code,{children:`currency`}),` parameter controls sort priority (matching assets appear first). Best for building integrations where you already know the customer’s wallet.`]}),`\n`]}),`\n`,_jsxs(_components.li,{children:[`\n`,_jsxs(_components.p,{children:[_jsx(_components.a,{href:`/api-reference/lookup/list-stablebonds`,children:`GET /lookup/stablebonds`}),` — Public, no auth. Returns all stablebonds across all chains with pricing and supply data. Best for exploring what’s available before onboarding a customer.`]}),`\n`]}),`\n`]}),_jsxs(_components.p,{children:[`Use the `,_jsx(_components.code,{children:`identifier`}),` from either response as the asset value in your quote.`]}),_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Swap constraint:`}),` A swap must involve at least one stablebond; the other side can be a stablecoin such as USDC, so both `,_jsx(_components.code,{children:`USDC → CETES`}),` and the reverse `,_jsx(_components.code,{children:`CETES → USDC`}),` are valid. Both assets must be stable, so non-stable tokens (SOL, XLM) return `,_jsx(_components.code,{children:`Non-stable assets are not supported`}),`, and stablecoin-to-stablecoin swaps (`,_jsx(_components.code,{children:`USDC → USDT`}),`) are not supported.`]}),_jsxs(Warning,{children:[_jsx(_components.p,{children:_jsx(_components.strong,{children:`Asset identifier format differs by chain:`})}),_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Solana`}),` — Base58 mint address (e.g. `,_jsx(_components.code,{children:`AvvetPGuuB5FD5m86fpw3LtDKyQoUFT1mG9WarNQLW4q`}),`)`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Stellar`}),` — `,_jsx(_components.code,{children:`CODE:ISSUER`}),` format (e.g. `,_jsx(_components.code,{children:`CETES:GC3CW7...`}),`)`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Monad`}),` — raw token contract address only (e.g. `,_jsx(_components.code,{children:`0xcC77c598d42f2f78Beb42C91d12B9d4041a5cE29`}),`)`]}),`\n`]}),_jsxs(_components.p,{children:[`Using `,_jsx(_components.code,{children:`SYMBOL:0x...`}),` (Stellar format) on other chains will return `,_jsx(_components.code,{children:`UnsupportedBlockchain`}),`.`]})]}),_jsxs(Tip,{children:[_jsx(_components.p,{children:_jsx(_components.strong,{children:`USDC addresses for swap sources:`})}),_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Stellar sandbox:`}),` `,_jsx(_components.code,{children:`USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5`})]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Stellar production:`}),` `,_jsx(_components.code,{children:`USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN`})]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Solana sandbox:`}),` `,_jsx(_components.code,{children:`4D4r1KuS9WxbPCzzAJnWtYUJSSzDEZzrF1CbwajWGVjg`})]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.strong,{children:`Solana production:`}),` `,_jsx(_components.code,{children:`EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v`})]}),`\n`]})]})]})}),_jsx(Step,{title:`Create a Swap Quote — POST /ramp/quote`,children:_jsxs(Expandable,{title:`Details`,children:[_jsxs(_components.p,{children:[`Quotes expire after `,_jsx(_components.strong,{children:`2 minutes`}),`. For swaps, set `,_jsx(_components.code,{children:`type: \"swap\"`}),` with the source token identifier as `,_jsx(_components.code,{children:`sourceAsset`}),` and the stablebond identifier as `,_jsx(_components.code,{children:`targetAsset`}),`. The response includes `,_jsx(_components.code,{children:`requiresSwap: true`}),` and the `,_jsx(_components.code,{children:`exchangeRate`}),` between the two assets. See `,_jsx(_components.a,{href:`/api-reference/quotes/get-quote`,children:`POST /ramp/quote`}),` for the full schema.`]}),_jsxs(CodeGroup,{children:[_jsx(CodeBlock,{filename:`Sandbox`,numberOfLines:`14`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`14`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`curl`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -X`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` POST`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` https://api.sand.etherfuse.com/ramp/quote`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D7BA7D`},children:` \\\\`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -H`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"Authorization: \u003capi_key>\"`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D7BA7D`},children:` \\\\`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -H`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"Content-Type: application/json\"`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D7BA7D`},children:` \\\\`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -d`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` '{`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"quoteId\": \"\u003cuuid>\", # You generate this UUID`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"customerId\": \"\u003corg_uuid>\", # From onboarding`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"blockchain\": \"stellar\",`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"quoteAssets\": {`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"type\": \"swap\",`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"sourceAsset\": \"USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5\",`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"targetAsset\": \"CETES:GC3CW7EDYRTWQ635VDIGY6S4ZUF5L6TQ7AA4MWS7LEQDBLUSZXV7UPS4\"`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` },`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"sourceAmount\": \"10\"`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` }'`})}),`\n`]})})}),_jsx(CodeBlock,{filename:`Production`,numberOfLines:`14`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`14`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`curl`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -X`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` POST`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` https://api.etherfuse.com/ramp/quote`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D7BA7D`},children:` \\\\`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -H`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"Authorization: \u003capi_key>\"`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D7BA7D`},children:` \\\\`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -H`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"Content-Type: application/json\"`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D7BA7D`},children:` \\\\`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -d`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` '{`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"quoteId\": \"\u003cuuid>\", # You generate this UUID`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"customerId\": \"\u003corg_uuid>\", # From onboarding`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"blockchain\": \"stellar\",`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"quoteAssets\": {`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"type\": \"swap\",`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"sourceAsset\": \"USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN\",`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"targetAsset\": \"CETES:GC3CW7EDYRTWQ635VDIGY6S4ZUF5L6TQ7AA4MWS7LEQDBLUSZXV7UPS4\"`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` },`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"sourceAmount\": \"10\"`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` }'`})}),`\n`]})})})]}),_jsx(Tip,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Partner fees:`}),` If your organization has a partner fee configured, it is applied automatically. To override per-quote, add `,_jsx(_components.code,{children:`\"partnerFeeBps\": 100`}),` (0–500) to the request body. See `,_jsx(_components.a,{href:`/fees#partner-fees`,children:`Partner Fees`}),` for details.`]})})]})}),_jsx(Step,{title:`Create the Swap — POST /ramp/swap`,children:_jsxs(Expandable,{title:`Details`,children:[_jsxs(_components.p,{children:[`Unlike orders, the swap endpoint requires `,_jsx(_components.code,{children:`blockchain`}),` and `,_jsx(_components.code,{children:`publicKey`}),` in the request body (these are not derived from the quote). The endpoint returns an `,_jsx(_components.strong,{children:`empty 200`}),` — all swap progress is delivered via webhooks. See `,_jsx(_components.a,{href:`/api-reference/swaps/swap-assets`,children:`POST /ramp/swap`}),` for the full schema.`]}),_jsxs(CodeGroup,{children:[_jsx(CodeBlock,{filename:`Sandbox`,numberOfLines:`9`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`9`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`curl`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -X`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` POST`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` https://api.sand.etherfuse.com/ramp/swap`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D7BA7D`},children:` \\\\`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -H`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"Authorization: \u003capi_key>\"`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D7BA7D`},children:` \\\\`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -H`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"Content-Type: application/json\"`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D7BA7D`},children:` \\\\`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -d`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` '{`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"orderId\": \"\u003cuuid>\", # You generate this UUID`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"quoteId\": \"\u003cquote_uuid_from_step_2>\", # From Step 2`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"publicKey\": \"\u003cwallet_public_key>\", # From onboarding`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"blockchain\": \"stellar\"`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` }'`})}),`\n`]})})}),_jsx(CodeBlock,{filename:`Production`,numberOfLines:`9`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`9`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`curl`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -X`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` POST`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` https://api.etherfuse.com/ramp/swap`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D7BA7D`},children:` \\\\`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -H`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"Authorization: \u003capi_key>\"`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D7BA7D`},children:` \\\\`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -H`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"Content-Type: application/json\"`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D7BA7D`},children:` \\\\`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -d`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` '{`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"orderId\": \"\u003cuuid>\", # You generate this UUID`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"quoteId\": \"\u003cquote_uuid_from_step_2>\", # From Step 2`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"publicKey\": \"\u003cwallet_public_key>\", # From onboarding`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"blockchain\": \"stellar\"`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` }'`})}),`\n`]})})})]}),_jsx(Info,{children:_jsxs(_components.p,{children:[`The `,_jsx(_components.code,{children:`orderId`}),` here is a swap identifier you generate — it tracks this swap through webhooks. The optional `,_jsx(_components.code,{children:`targetWallet`}),` field lets you send the swapped tokens to a different wallet than `,_jsx(_components.code,{children:`publicKey`}),`.`]})})]})}),_jsx(Step,{title:`Sign the Transaction`,children:_jsxs(Expandable,{title:`Details`,children:[_jsxs(_components.p,{children:[`After creating the swap, you’ll receive a `,_jsx(_components.code,{children:`swap_updated`}),` webhook with the `,_jsx(_components.code,{children:`sendTransaction`}),` — a pre-built, encoded transaction ready to sign.`]}),_jsx(CodeBlock,{filename:``,numberOfLines:`8`,language:`json`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`json`,children:_jsxs(_components.code,{language:`json`,numberOfLines:`8`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`{`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"swap_updated\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"orderId\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"\u003cswap_uuid>\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"customerId\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"\u003corg_uuid>\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"sendTransaction\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"AQAAAA...encoded_transaction\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"status\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"pending\"`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` }`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})}),`\n`]})})}),_jsxs(_components.p,{children:[`Sign the `,_jsx(_components.code,{children:`sendTransaction`}),` using a wallet adapter and submit it to the testnet blockchain. Once confirmed, you’ll receive another `,_jsx(_components.code,{children:`swap_updated`}),` webhook with `,_jsx(_components.code,{children:`status: \"completed\"`}),`.`]}),_jsx(Warning,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`The first webhook is a call to action, not a progress notification.`}),` Etherfuse has partially signed `,_jsx(_components.code,{children:`sendTransaction`}),`, but the swap does not advance until the customer’s wallet adds its signature and submits it on-chain. Until then the swap stays at `,_jsx(_components.code,{children:`pending`}),` and no further webhooks fire.`]})}),_jsx(Warning,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Do not build your own transaction.`}),` Always use the `,_jsx(_components.code,{children:`sendTransaction`}),` provided in the webhook. This transaction is pre-built by Etherfuse with the correct swap parameters.`]})}),_jsx(Tip,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`If the transaction expires before you submit it`}),`, fetch a fresh one with `,_jsx(_components.a,{href:`/api-reference/swaps/regenerate-swap-tx`,children:`POST /ramp/swap/{order_id}/regenerate_tx`}),` — the new `,_jsx(_components.code,{children:`sendTransaction`}),` arrives over the `,_jsx(_components.code,{children:`swap_updated`}),` webhook. (Stellar transactions expire in ~1–2 minutes.) `,_jsx(_components.code,{children:`sendTransaction`}),` is only present while funds are still owed; after they’re received you instead get `,_jsx(_components.code,{children:`sendTransactionHash`}),` and `,_jsx(_components.code,{children:`receiveTransactionHash`}),`.`]})})]})}),_jsx(Step,{title:`Verify Completion`,children:_jsxs(Expandable,{title:`Details`,children:[_jsxs(_components.p,{children:[`Monitor swap progress via `,_jsx(_components.code,{children:`swap_updated`}),` webhooks. The `,_jsx(_components.code,{children:`status`}),` field progresses `,_jsx(_components.code,{children:`pending`}),` → `,_jsx(_components.code,{children:`funds_received`}),` → `,_jsx(_components.code,{children:`completed`}),` (or `,_jsx(_components.code,{children:`failed`}),`). Register a webhook for the `,_jsx(_components.code,{children:`swap_updated`}),` event type via `,_jsx(_components.a,{href:`/api-reference/webhooks/create-webhook`,children:`POST /ramp/webhook`}),`.`]}),_jsx(Warning,{children:_jsxs(_components.p,{children:[_jsxs(_components.strong,{children:[_jsx(_components.code,{children:`funds_received`}),` fires on Stellar and Monad only.`]}),` On Solana the swap goes straight from `,_jsx(_components.code,{children:`pending`}),` to `,_jsx(_components.code,{children:`completed`}),`, so treat the middle event as optional rather than gating your state machine on it.`]})}),_jsx(Info,{children:_jsxs(_components.p,{children:[`Unlike on/off-ramps, there is no polling endpoint for swap status; webhooks are the only way to track progress. Swaps are not stored as orders, so calling `,_jsx(_components.a,{href:`/api-reference/orders/get-order`,children:`GET /ramp/order/{order_id}`}),` with a swap `,_jsx(_components.code,{children:`orderId`}),` returns `,_jsx(_components.code,{children:`404 Order not found`}),`. The `,_jsx(_components.code,{children:`swap_updated`}),` payload carries everything the UI needs.`]})})]})})]}),`\n`,_jsx(Heading,{level:`2`,id:`interactive-tutorial`,children:`Interactive Tutorial`}),`\n`,_jsx(_components.p,{children:`Use the interactive tutorial below to test the swap flow with your sandbox API key. Each step builds on the previous one, and you can edit the request bodies before sending.`}),`\n`,_jsx(_MdxComponentBoundary,{name:`SwapTutorial`,children:_jsx(SwapTutorial,{sandboxOnly:true})}),`\n`,_jsxs(Expandable,{title:`Chain-specific swap examples`,children:[_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Stellar`}),` — USDC to CETES:`]}),_jsx(CodeBlock,{filename:``,numberOfLines:`8`,language:`json`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`json`,children:_jsxs(_components.code,{language:`json`,numberOfLines:`8`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`{`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"blockchain\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"stellar\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"quoteAssets\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"type\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"swap\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"sourceAsset\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"targetAsset\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"CETES:GC3CW7EDYRTWQ635VDIGY6S4ZUF5L6TQ7AA4MWS7LEQDBLUSZXV7UPS4\"`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` }`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})}),`\n`]})})}),_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Solana`}),` — USDC to CETES:`]}),_jsx(CodeBlock,{filename:``,numberOfLines:`8`,language:`json`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`json`,children:_jsxs(_components.code,{language:`json`,numberOfLines:`8`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`{`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"blockchain\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"solana\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"quoteAssets\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"type\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"swap\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"sourceAsset\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"4D4r1KuS9WxbPCzzAJnWtYUJSSzDEZzrF1CbwajWGVjg\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"targetAsset\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"AvvetPGuuB5FD5m86fpw3LtDKyQoUFT1mG9WarNQLW4q\"`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` }`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})}),`\n`]})})})]}),`\n`,_jsx(Expandable,{title:`Common errors`,children:_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Error`}),_jsx(_components.th,{children:`Cause`}),_jsx(_components.th,{children:`Fix`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`Swaps must involve at least one stablebond asset`})}),_jsx(_components.td,{children:`Neither side is a stablebond (e.g. a stablecoin-to-stablecoin swap)`}),_jsxs(_components.td,{children:[`Make at least one side a stablebond — use identifiers from `,_jsx(_components.code,{children:`/lookup/stablebonds`})]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`Non-stable assets are not supported`})}),_jsx(_components.td,{children:`A side is a non-stable token (SOL, XLM, ETH)`}),_jsx(_components.td,{children:`Both sides must be a stablebond or a supported stablecoin`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`UnsupportedBlockchain`})}),_jsx(_components.td,{children:`Swaps not yet available on this chain, or using wrong identifier format`}),_jsx(_components.td,{children:`Swaps are currently available on Stellar, Solana, and Monad. Check your asset identifier format.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`Quote not found or expired`})}),_jsx(_components.td,{children:`Quote TTL is 2 minutes`}),_jsx(_components.td,{children:`Create a fresh quote`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`Terms and conditions have not been completed`})}),_jsx(_components.td,{children:`Wallet not KYC-approved`}),_jsxs(_components.td,{children:[`Complete the `,_jsx(_components.a,{href:`/guides/onboarding`,children:`onboarding flow`})]})]}),_jsxs(_components.tr,{children:[_jsxs(_components.td,{children:[_jsx(_components.code,{children:`Temporarily unable to get a valid quote for this trading path`}),` (`,_jsx(_components.code,{children:`424`}),`)`]}),_jsxs(_components.td,{children:[`Sandbox liquidity for that path is thin right now, not a direction restriction (reverse `,_jsx(_components.code,{children:`stablebond → USDC`}),` swaps are valid)`]}),_jsxs(_components.td,{children:[`Transient. Retry with backoff. See `,_jsx(_components.a,{href:`/errors#status-codes`,children:`Errors`}),`.`]})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:_jsx(_components.code,{children:`Unexpected`})}),_jsx(_components.td,{children:`Swap provider (Jupiter/SDEX) returned an error`}),_jsx(_components.td,{children:`Check that the source asset has testnet liquidity against the target`})]})]})]})})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{SwapTutorial,default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Swaps","description":"How to test token-to-token swap flows in the sandbox environment","href":"/guides/testing-swaps"}}},"mdxSourceWithNoJs":null,"noJsSplices":[[148,38666,")=>null;function _cr"]]},"mdxExtracts":{"tableOfContents":[{"title":"Swap Flow","slug":"swap-flow","depth":2,"children":[]},{"title":"Interactive Tutorial","slug":"interactive-tutorial","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":[],"subdomain":"etherfuse","siteName":"Etherfuse API","title":"Swaps - Etherfuse API","navMaps":{"firstHrefInVersion":{"v2 (beta)":{"href":"/v2/guides/testing-swaps","matchLevel":1},"v1 (legacy)":{"href":"/guides/testing-swaps","matchLevel":0}},"firstHrefInLanguage":{}},"lastModified":"2026-09-29T18:01:52.247Z","originalFileLocation":"guides/testing-swaps.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"How to test token-to-token swap flows in the sandbox environment\">\u003cmeta data-mint-head name=\"application-name\" content=\"Etherfuse API\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/etherfuse/2PYR-_ECBzhTGa_z/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/etherfuse/2PYR-_ECBzhTGa_z/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/etherfuse/2PYR-_ECBzhTGa_z/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/etherfuse/2PYR-_ECBzhTGa_z/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/etherfuse/2PYR-_ECBzhTGa_z/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/etherfuse/2PYR-_ECBzhTGa_z/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/etherfuse/2PYR-_ECBzhTGa_z/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/etherfuse/2PYR-_ECBzhTGa_z/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/etherfuse/2PYR-_ECBzhTGa_z/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Swaps - Etherfuse API\">\u003cmeta data-mint-head property=\"og:description\" content=\"How to test token-to-token swap flows in the sandbox environment\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Etherfuse API\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.etherfuse.com/guides/testing-swaps\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://etherfuse.mintlify.app/_mintlify/api/og/v2?division=Integration+Guides\u0026amp;title=Swaps\u0026amp;description=How+to+test+token-to-token+swap+flows+in+the+sandbox+environment\u0026amp;theme=a63046a1b6875a84019a21bc\u0026amp;signature=5a96f3b1aa69337000396617111d2c3be64232da7e857bfbedeedd017e82eb65\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Swaps - Etherfuse API\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"How to test token-to-token swap flows in the sandbox environment\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://etherfuse.mintlify.app/_mintlify/api/og/v2?division=Integration+Guides\u0026amp;title=Swaps\u0026amp;description=How+to+test+token-to-token+swap+flows+in+the+sandbox+environment\u0026amp;theme=a63046a1b6875a84019a21bc\u0026amp;signature=5a96f3b1aa69337000396617111d2c3be64232da7e857bfbedeedd017e82eb65\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/etherfuse/2PYR-_ECBzhTGa_z/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Etherfuse API\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#141414\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.etherfuse.com/guides/testing-swaps\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/guides/testing-swaps.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.etherfuse.com/#organization\",\"name\":\"Etherfuse API\",\"url\":\"https://docs.etherfuse.com\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/etherfuse/XRSchVFGUgreQatD/img/logo-black.svg?fit=max\u0026auto=format\u0026n=XRSchVFGUgreQatD\u0026q=85\u0026s=92cf84eca27df4a19f7b032da398d110\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.etherfuse.com#website\",\"name\":\"Etherfuse API\",\"url\":\"https://docs.etherfuse.com\",\"publisher\":{\"@id\":\"https://docs.etherfuse.com/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.etherfuse.com/guides/testing-swaps#webpage\",\"url\":\"https://docs.etherfuse.com/guides/testing-swaps\",\"name\":\"Swaps\",\"description\":\"How to test token-to-token swap flows in the sandbox environment\",\"dateModified\":\"2026-09-29T18:01:52.247Z\",\"isPartOf\":{\"@id\":\"https://docs.etherfuse.com#website\"},\"breadcrumb\":{\"@id\":\"https://docs.etherfuse.com/guides/testing-swaps#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.etherfuse.com/guides/testing-swaps#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Integration Guides\",\"item\":\"https://docs.etherfuse.com/guides/embedded-wallets\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Swaps\",\"item\":\"https://docs.etherfuse.com/guides/testing-swaps\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://docs.etherfuse.com/guides/testing-swaps#article\",\"headline\":\"Swaps\",\"name\":\"Swaps\",\"description\":\"How to test token-to-token swap flows in the sandbox environment\",\"url\":\"https://docs.etherfuse.com/guides/testing-swaps\",\"mainEntityOfPage\":{\"@id\":\"https://docs.etherfuse.com/guides/testing-swaps#webpage\"},\"dateModified\":\"2026-09-29T18:01:52.247Z\",\"publisher\":{\"@id\":\"https://docs.etherfuse.com/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.etherfuse.com#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Etherfuse API\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"Etherfuse API","nav":{"global":null,"versions":[{"version":"v2 (beta)","default":true,"pages":[{"title":"v2 (beta)","href":"/v2/guides/testing-swaps"}]},{"version":"v1 (legacy)","tabs":[{"tab":"Guides","groups":[{"group":"Get Started","icon":"rocket","pages":[{"title":"Introduction","href":"/introduction"},{"title":"Quickstart","href":"/quickstart"},{"title":"Initial Setup","href":"/initial-setup"},{"title":"Sandbox Reference","href":"/test-environment"}]},{"group":"Concepts","icon":"lightbulb","pages":[{"title":"How it works","href":"/overview"},{"title":"Webhooks","href":"/webhooks"}]},{"group":"User Authentication","icon":"key","pages":[{"title":"JWT User Authentication","href":"/guides/jwt-authentication"},{"title":"User Launch Flows","href":"/guides/user-launch-flows"},{"title":"Authentication errors","href":"/guides/authentication-errors"}]},{"group":"Integration Guides","icon":"code","pages":[{"group":"Embedded Wallets","root":{"title":"Embedded Wallets","href":"/guides/embedded-wallets"},"directory":"card","pages":[{"title":"Embedded Wallets","href":"/guides/embedded-wallets"},{"title":"Embedded Wallets Sandbox Playground","sidebarTitle":"Sandbox playground","href":"/guides/embedded-wallets-walkthrough"}]},{"title":"Verifying Webhooks","description":"How to verify webhook signatures to ensure payloads are authentic","href":"/guides/verifying-webhooks"},{"title":"Swaps","href":"/guides/testing-swaps"},{"title":"Onramps","description":"How to test onramp flows in the sandbox environment","href":"/guides/testing-onramps"},{"title":"Offramps","href":"/guides/testing-offramps"}]},{"group":"KYC","icon":"id-card","pages":[{"title":"KYC Overview","sidebarTitle":"Overview","href":"/guides/onboarding"},{"title":"KYC WebSDK","href":"/guides/kyc-websdk"},{"title":"KYC API","href":"/guides/kyc-api"},{"title":"KYC Sumsub Shared Token","href":"/guides/kyc-sumsub-shared-token"}]},{"group":"KYB","icon":"building","pages":[{"title":"KYB Overview","sidebarTitle":"Overview","href":"/guides/kyb"},{"title":"KYB WebSDK","href":"/guides/kyb-websdk"}]},{"group":"Blockchains","icon":"cubes","pages":[{"title":"Stellar","href":"/guides/chains/stellar"},{"title":"Solana","href":"/guides/chains/solana"},{"title":"Monad","href":"/guides/chains/monad"},{"title":"Base","href":"/guides/chains/base"},{"title":"Polygon","href":"/guides/chains/polygon"},{"title":"Avalanche","href":"/guides/chains/avalanche"}]},{"group":"Resources","icon":"book-open","pages":[{"title":"Ramp Fees","href":"/fees"},{"title":"Price Feeds","href":"/price-feeds"},{"title":"Glossary","href":"/glossary"},{"title":"SDKs","href":"/sdks"},{"title":"MCP Server","href":"/mcp-overview"}]}]},{"tab":"API Reference","pages":[{"title":"API Reference","href":"/api-reference/introduction"}]},{"tab":"Changelog","pages":[{"title":"Changelog","href":"/changelog"}]}]}]},"title":"Swaps - Etherfuse API","buildId":"dpl_EnxDqhjaNc9a8MVa833TGULPd9uJ","deploymentId":"dpl_EnxDqhjaNc9a8MVa833TGULPd9uJ","dynamics":[],"chunks":[]}