{"openapi":"3.0.0","info":{"version":"1.0.0","title":"ShapeShift Public API","description":"The ShapeShift Public API lets you integrate multi-chain swap functionality into your application. Fetch rates from multiple DEX aggregators and bridges, build executable quotes, and track swaps across supported blockchains.\n\n## Base URL\n\n```\nhttps://api.shapeshift.com\n```\n\nAll endpoints are versioned under `/v1` (e.g. `https://api.shapeshift.com/v1/swap/rates`). This interactive reference is served at `https://api.shapeshift.com/docs`, and the raw OpenAPI document at `https://api.shapeshift.com/docs/json`.\n\n## Two ways to integrate\n\n1. **Swap Widget SDK** — a drop-in React component with built-in UI, wallet connection, and multi-chain support. The fastest path. See the **Swap Widget SDK** section.\n2. **REST API** — call the endpoints directly and build your own UI for full control over UX. See the **REST API Guide** section, then the per-endpoint reference below.\n\n## Affiliate tracking (optional)\n\nSend an `X-Partner-Code` header with your registered partner code (e.g. `your-partner-code`) on the swap endpoints to attribute swaps for affiliate revenue share. The API attributes the swap to your affiliate account and applies your configured fee (bps) automatically. All endpoints work without it — unattributed swaps use the default fee. See the [Affiliate Program guide](https://github.com/shapeshift/web/blob/develop/docs/affiliates.md) for how to obtain a code.\n\n## Asset IDs (CAIP-19)\n\nAssets are identified with [CAIP-19](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-19.md): `{chainId}/{assetNamespace}:{assetReference}`\n\n- Native ETH: `eip155:1/slip44:60`\n- USDC on Ethereum: `eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`\n- Native BTC: `bip122:000000000019d6689c085ae165831e93/slip44:0`\n\nChains use [CAIP-2](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-2.md) (e.g. `eip155:1`). Use `GET /v1/chains` and `GET /v1/assets` to discover supported values.\n\n## Errors\n\nErrors return the appropriate HTTP status and a JSON body:\n\n```json\n{ \"error\": \"Human-readable message\", \"code\": \"MACHINE_CODE\", \"details\": [] }\n```\n\n`code` and `details` are present where applicable (e.g. `QUOTE_NOT_FOUND`, `TX_HASH_REQUIRED`, `TX_HASH_MISMATCH`, `RATE_LIMIT_EXCEEDED`, validation `details`).\n\n## Rate limiting\n\nEndpoints are rate limited per IP on a fixed 60-second window. A global limit applies across all endpoints, and individual endpoint groups (data, rates, quote, status, affiliate) have their own independent limits on top of it — so a request counts against both. When either is exceeded, the API returns `429` with code `RATE_LIMIT_EXCEEDED` and these headers:\n\n- `Retry-After` — seconds until the window resets\n- `RateLimit-Limit` — max requests allowed per window\n- `RateLimit-Remaining` — requests remaining in the current window\n- `RateLimit-Reset` — seconds until the window resets\n\nBack off using `Retry-After` and avoid polling faster than necessary (see the REST API Guide for polling guidance).\n"},"servers":[{"url":"https://api.shapeshift.com"},{"url":"http://localhost:3001"}],"components":{"schemas":{"RateLimitError":{"type":"object","properties":{"error":{"type":"string","example":"Too many requests, please try again later"},"code":{"type":"string","enum":["RATE_LIMIT_EXCEEDED"],"example":"RATE_LIMIT_EXCEEDED"}},"required":["error","code"]},"Asset":{"type":"object","properties":{"assetId":{"type":"string","example":"eip155:1/slip44:60"},"chainId":{"type":"string","example":"eip155:1"},"name":{"type":"string","example":"Ethereum"},"symbol":{"type":"string","example":"ETH"},"precision":{"type":"number","example":18},"color":{"type":"string","example":"#5C6BC0"},"icon":{"type":"string","example":"https://assets.coincap.io/assets/icons/eth@2x.png"},"networkName":{"type":"string","example":"Ethereum"},"networkColor":{"type":"string","example":"#5C6BC0"},"networkIcon":{"type":"string","example":"https://assets.coincap.io/assets/icons/eth@2x.png"},"explorer":{"type":"string","example":"https://etherscan.io"},"explorerAddressLink":{"type":"string","example":"https://etherscan.io/address/"},"explorerTxLink":{"type":"string","example":"https://etherscan.io/tx/"},"relatedAssetKey":{"type":"string","nullable":true}},"required":["assetId","chainId","name","symbol","precision","color","icon","explorer","explorerAddressLink","explorerTxLink","relatedAssetKey"]},"AffiliateConfig":{"type":"object","properties":{"id":{"type":"string","example":"abc123"},"walletAddress":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$","example":"0x1234567890123456789012345678901234567890"},"receiveAddress":{"type":"string","nullable":true,"pattern":"^0x[0-9a-fA-F]{40}$","example":"0x1234567890123456789012345678901234567890"},"partnerCode":{"type":"string","example":"mypartner"},"partnerBps":{"type":"number","example":50},"shapeshiftBps":{"type":"number","example":10},"isActive":{"type":"boolean","example":true},"createdAt":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00.000Z"},"updatedAt":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00.000Z"}},"required":["id","walletAddress","receiveAddress","partnerCode","partnerBps","shapeshiftBps","isActive","createdAt","updatedAt"]},"AffiliateSwap":{"type":"object","properties":{"swapId":{"type":"string","example":"swap-uuid-1234"},"status":{"type":"string","example":"completed"},"sellAsset":{"$ref":"#/components/schemas/Asset"},"buyAsset":{"$ref":"#/components/schemas/Asset"},"sellAmountCryptoPrecision":{"type":"string","example":"1.0"},"sellAmountUsd":{"type":"string","nullable":true,"example":"1234.56"},"buyAmountCryptoPrecision":{"type":"string","nullable":true,"example":"948.0"},"buyAmountUsd":{"type":"string","nullable":true,"example":"1234.56"},"affiliateFeeAmountUsd":{"type":"string","nullable":true,"example":"3.70"},"affiliateBps":{"type":"integer","minimum":0,"example":60},"partnerBps":{"type":"integer","nullable":true,"minimum":0,"example":20},"shapeshiftBps":{"type":"integer","minimum":0,"example":10},"swapperName":{"type":"string","example":"THORChain"},"sellTxHash":{"type":"string","nullable":true,"example":"0xabc123"},"buyTxHash":{"type":"string","nullable":true,"example":"0xdef456"},"isAffiliateVerified":{"type":"boolean","nullable":true,"example":true},"createdAt":{"type":"string","example":"2024-01-01T00:00:00.000Z"}},"required":["swapId","status","sellAsset","buyAsset","sellAmountCryptoPrecision","sellAmountUsd","buyAmountCryptoPrecision","buyAmountUsd","affiliateFeeAmountUsd","affiliateBps","partnerBps","shapeshiftBps","swapperName","sellTxHash","buyTxHash","isAffiliateVerified","createdAt"]},"AffiliateSwapsResponse":{"type":"object","properties":{"swaps":{"type":"array","items":{"$ref":"#/components/schemas/AffiliateSwap"}},"nextCursor":{"type":"string","nullable":true,"example":"swap-uuid-1234"}},"required":["swaps","nextCursor"]},"AffiliateStatsResponse":{"type":"object","properties":{"totalSwaps":{"type":"number","example":42},"totalVolumeUsd":{"type":"string","example":"12345.67"},"totalFeesEarnedUsd":{"type":"string","example":"44.44"}},"required":["totalSwaps","totalVolumeUsd","totalFeesEarnedUsd"]},"SiweNonceResponse":{"type":"object","properties":{"nonce":{"type":"string","example":"abcdef123456"}},"required":["nonce"]},"SiweVerifyResponse":{"type":"object","properties":{"token":{"type":"string","example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."},"address":{"type":"string","example":"0x1234567890123456789012345678901234567890"}},"required":["token","address"]},"Chain":{"type":"object","properties":{"chainId":{"type":"string","example":"eip155:1"},"name":{"type":"string","example":"Ethereum"},"type":{"type":"string","enum":["evm","utxo","cosmos","solana","tron","sui","near","starknet","ton"],"example":"evm"},"symbol":{"type":"string","example":"ETH"},"precision":{"type":"number","example":18},"color":{"type":"string","example":"#5C6BC0"},"networkColor":{"type":"string","example":"#5C6BC0"},"icon":{"type":"string","example":"https://rawcdn.githack.com/trustwallet/assets/32e51d582a890b3dd3135fe3ee7c20c2fd699a6d/blockchains/ethereum/info/logo.png"},"networkIcon":{"type":"string","example":"https://rawcdn.githack.com/trustwallet/assets/32e51d582a890b3dd3135fe3ee7c20c2fd699a6d/blockchains/ethereum/info/logo.png"},"explorer":{"type":"string","example":"https://etherscan.io"},"explorerAddressLink":{"type":"string","example":"https://etherscan.io/address/"},"explorerTxLink":{"type":"string","example":"https://etherscan.io/tx/"},"nativeAssetId":{"type":"string","example":"eip155:1/slip44:60"},"isSellSupported":{"type":"boolean","description":"Whether assets on this chain can be sold. Chains without it are destination-only - rates and quotes reject them as a sell asset.","example":true}},"required":["chainId","name","type","symbol","precision","color","explorer","explorerAddressLink","explorerTxLink","nativeAssetId","isSellSupported"]},"PartnerResolution":{"type":"object","properties":{"partnerAddress":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$","example":"0x1234567890123456789012345678901234567890"},"partnerBps":{"type":"integer","minimum":0,"example":50},"partnerCode":{"type":"string","example":"mypartner"},"shapeshiftBps":{"type":"integer","minimum":0,"example":10}},"required":["partnerAddress","partnerBps","partnerCode","shapeshiftBps"]},"QuoteStep":{"type":"object","properties":{"sellAsset":{"$ref":"#/components/schemas/Asset"},"buyAsset":{"$ref":"#/components/schemas/Asset"},"sellAmountCryptoBaseUnit":{"type":"string","example":"1000000000000000000"},"buyAmountAfterFeesCryptoBaseUnit":{"type":"string","example":"995000000"},"allowanceContract":{"type":"string","example":"0xdef1c0ded9bec7f1a1670819833240f027b25eff"},"estimatedExecutionTimeMs":{"type":"number","example":60000},"source":{"type":"string","example":"0x"},"transactionData":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["evm"],"example":"evm"},"chainId":{"type":"number","example":1},"to":{"type":"string","example":"0xdef1c0ded9bec7f1a1670819833240f027b25eff"},"data":{"type":"string","example":"0x..."},"value":{"type":"string","example":"1000000000000000000"},"gasLimit":{"type":"string","example":"300000"},"signatureRequired":{"type":"object","properties":{"type":{"type":"string","enum":["zrx_permit2"]},"eip712":{"type":"object","additionalProperties":{"nullable":true}}},"required":["type","eip712"],"description":"When present, the transaction requires a permit2 signature before broadcast: sign the eip712 payload with eth_signTypedData_v4, then append a 32-byte big-endian signature-length word followed by the signature to `data` (the 0x settler convention). The supplied gasLimit already accounts for the appended signature."}},"required":["type","chainId","to","data","value"]},{"type":"object","properties":{"type":{"type":"string","enum":["solana_instructions"],"example":"solana_instructions"},"instructions":{"type":"array","items":{"type":"object","properties":{"programId":{"type":"string"},"keys":{"type":"array","items":{"type":"object","properties":{"pubkey":{"type":"string"},"isSigner":{"type":"boolean"},"isWritable":{"type":"boolean"}},"required":["pubkey","isSigner","isWritable"]}},"data":{"type":"string"}},"required":["programId","keys","data"]}},"addressLookupTableAddresses":{"type":"array","items":{"type":"string"}}},"required":["type","instructions","addressLookupTableAddresses"]},{"type":"object","properties":{"type":{"type":"string","enum":["solana_serialized_tx"],"example":"solana_serialized_tx"},"serializedTx":{"type":"string"}},"required":["type","serializedTx"]},{"type":"object","properties":{"type":{"type":"string","enum":["utxo"],"example":"utxo"},"to":{"type":"string"},"opReturnData":{"type":"string"},"value":{"type":"string"}},"required":["type","to","value"]},{"type":"object","properties":{"type":{"type":"string","enum":["cosmossdk_msg_send"],"example":"cosmossdk_msg_send"},"chainId":{"type":"string"},"to":{"type":"string"},"denom":{"type":"string","example":"uatom"},"value":{"type":"string"},"memo":{"type":"string"}},"required":["type","chainId","to","denom","value"]},{"type":"object","properties":{"type":{"type":"string","enum":["cosmossdk_msg_deposit"],"example":"cosmossdk_msg_deposit"},"chainId":{"type":"string"},"value":{"type":"string"},"memo":{"type":"string"},"coin":{"type":"string","example":"THOR.RUNE"}},"required":["type","chainId","value","memo","coin"]}]}},"required":["sellAsset","buyAsset","sellAmountCryptoBaseUnit","buyAmountAfterFeesCryptoBaseUnit","allowanceContract","source"]},"QuoteResponse":{"type":"object","properties":{"quoteId":{"type":"string","format":"uuid"},"swapperName":{"type":"string","example":"0x"},"rate":{"type":"string","example":"0.995"},"sellAsset":{"$ref":"#/components/schemas/Asset"},"buyAsset":{"$ref":"#/components/schemas/Asset"},"sellAmountCryptoBaseUnit":{"type":"string"},"buyAmountBeforeFeesCryptoBaseUnit":{"type":"string"},"buyAmountAfterFeesCryptoBaseUnit":{"type":"string"},"affiliateBps":{"type":"string","description":"Total on-chain fee in bps.","example":"60"},"partnerBps":{"type":"string","description":"Partner share in bps.","example":"50"},"shapeshiftBps":{"type":"string","description":"ShapeShift platform fee in bps.","example":"10"},"slippageTolerancePercentageDecimal":{"type":"string","example":"0.01"},"networkFeeCryptoBaseUnit":{"type":"string","example":"23000"},"approval":{"type":"object","properties":{"isRequired":{"type":"boolean","example":true},"spender":{"type":"string","example":"0xdef1c0ded9bec7f1a1670819833240f027b25eff"},"approvalTxs":{"type":"array","items":{"type":"object","properties":{"to":{"type":"string","example":"0xdac17f958d2ee523a2206206994597c13d831ec7"},"data":{"type":"string","example":"0x095ea7b3..."},"value":{"type":"string","example":"0"}},"required":["to","data","value"]},"description":"Ready-to-sign approval transactions in broadcast order, empty when the current allowance already covers the amount. Approvals are exact - sized to the step's sellAmountCryptoBaseUnit and consumed by the swap's execution. Usually a single approve; tokens that require resetting a non-zero allowance before changing it (e.g. USDT) get a preceding approve(spender, 0). Sign and broadcast sequentially, waiting for each to confirm. Clients preferring an unlimited approval can build their own approve to `spender` instead."}},"required":["isRequired","spender","approvalTxs"]},"steps":{"type":"array","items":{"$ref":"#/components/schemas/QuoteStep"}},"expiresAt":{"type":"number","description":"Epoch ms after which the quote must not be executed - the swapper's own deadline (inbound address rotation, deposit channel expiry, order validity). Broadcasting after it risks failed swaps or, for deposit-style swappers, lost funds. Request a fresh quote instead.","example":1754265600000}},"required":["quoteId","swapperName","rate","sellAsset","buyAsset","sellAmountCryptoBaseUnit","buyAmountBeforeFeesCryptoBaseUnit","buyAmountAfterFeesCryptoBaseUnit","affiliateBps","shapeshiftBps","approval","steps","expiresAt"]},"RateResponse":{"type":"object","properties":{"rates":{"type":"array","items":{"type":"object","properties":{"swapperName":{"type":"string"},"rate":{"type":"string"},"buyAmountCryptoBaseUnit":{"type":"string"},"sellAmountCryptoBaseUnit":{"type":"string"},"steps":{"type":"number"},"allowanceContract":{"type":"string","description":"First-hop approval spender for the sell token. Non-empty means executing this swapper pulls the sell token from an approved allowance - clients wanting to check or set an allowance manually before quoting can use it directly. Empty or absent means no approval is involved.","example":"0xdef1c0ded9bec7f1a1670819833240f027b25eff"},"estimatedExecutionTimeMs":{"type":"number"},"priceImpactPercentageDecimal":{"type":"string"},"affiliateBps":{"type":"string","description":"Total on-chain fee in bps.","example":"60"},"partnerBps":{"type":"string","description":"Partner share in bps.","example":"50"},"shapeshiftBps":{"type":"string","description":"ShapeShift platform fee in bps.","example":"10"},"networkFeeCryptoBaseUnit":{"type":"string"},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}},"required":["swapperName","rate","buyAmountCryptoBaseUnit","sellAmountCryptoBaseUnit","steps","affiliateBps","shapeshiftBps"]}},"timestamp":{"type":"number"},"expiresAt":{"type":"number"}},"required":["rates","timestamp","expiresAt"]},"SwapStatusResponse":{"type":"object","properties":{"quoteId":{"type":"string","format":"uuid"},"txHash":{"type":"string"},"status":{"type":"string","enum":["pending","submitted","confirmed","failed"]},"swapperName":{"type":"string"},"sellAssetId":{"type":"string"},"buyAssetId":{"type":"string"},"sellAmountCryptoBaseUnit":{"type":"string"},"buyAmountAfterFeesCryptoBaseUnit":{"type":"string"},"partnerAddress":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$","example":"0x1234567890123456789012345678901234567890"},"affiliateBps":{"type":"string","description":"Total on-chain fee in bps.","example":"60"},"partnerBps":{"type":"string","description":"Partner share in bps.","example":"50"},"shapeshiftBps":{"type":"string","description":"ShapeShift platform fee in bps.","example":"10"},"registeredAt":{"type":"number"},"buyTxHash":{"type":"string"},"isAffiliateVerified":{"type":"boolean"}},"required":["quoteId","status","swapperName","sellAssetId","buyAssetId","sellAmountCryptoBaseUnit","buyAmountAfterFeesCryptoBaseUnit","affiliateBps","shapeshiftBps"]}},"parameters":{}},"paths":{"/v1/affiliate":{"post":{"operationId":"createAffiliate","summary":"Create affiliate","description":"Register a new affiliate. Requires a valid SIWE JWT in the Authorization header.","tags":["Affiliate"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"walletAddress":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$","example":"0x1234567890123456789012345678901234567890"},"receiveAddress":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$","example":"0x1234567890123456789012345678901234567890"},"partnerCode":{"type":"string","minLength":3,"maxLength":32,"pattern":"^[a-z0-9]+$"},"bps":{"type":"integer","minimum":0,"maximum":1000}},"required":["walletAddress","partnerCode","bps"]}}}},"responses":{"201":{"description":"Affiliate created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AffiliateConfig"}}}},"400":{"description":"Invalid request body"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"409":{"description":"Affiliate already exists"},"429":{"description":"Rate limit exceeded. Includes Retry-After header with seconds until reset.","headers":{"Retry-After":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}},"RateLimit-Limit":{"description":"Maximum requests allowed per window","schema":{"type":"integer","example":60}},"RateLimit-Remaining":{"description":"Requests remaining in the current window","schema":{"type":"integer","example":0}},"RateLimit-Reset":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}},"500":{"description":"Internal server error"},"503":{"description":"Swap service unavailable"},"504":{"description":"Swap service timed out"}}}},"/v1/affiliate/{address}":{"get":{"operationId":"getAffiliate","summary":"Get affiliate config","description":"Retrieve affiliate configuration for a given wallet address.","tags":["Affiliate"],"parameters":[{"schema":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$","example":"0x1234567890123456789012345678901234567890"},"required":true,"name":"address","in":"path"}],"responses":{"200":{"description":"Affiliate configuration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AffiliateConfig"}}}},"400":{"description":"Invalid request parameters"},"404":{"description":"Affiliate not found"},"429":{"description":"Rate limit exceeded. Includes Retry-After header with seconds until reset.","headers":{"Retry-After":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}},"RateLimit-Limit":{"description":"Maximum requests allowed per window","schema":{"type":"integer","example":60}},"RateLimit-Remaining":{"description":"Requests remaining in the current window","schema":{"type":"integer","example":0}},"RateLimit-Reset":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}},"500":{"description":"Internal server error"},"503":{"description":"Swap service unavailable"},"504":{"description":"Swap service timed out"}}},"patch":{"operationId":"updateAffiliate","summary":"Update affiliate","description":"Update an existing affiliate configuration. Requires a valid SIWE JWT in the Authorization header.","tags":["Affiliate"],"parameters":[{"schema":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$","example":"0x1234567890123456789012345678901234567890"},"required":true,"name":"address","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"receiveAddress":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$","example":"0x1234567890123456789012345678901234567890"},"bps":{"type":"integer","minimum":0,"maximum":1000}}}}}},"responses":{"200":{"description":"Updated affiliate configuration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AffiliateConfig"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Affiliate not found"},"429":{"description":"Rate limit exceeded. Includes Retry-After header with seconds until reset.","headers":{"Retry-After":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}},"RateLimit-Limit":{"description":"Maximum requests allowed per window","schema":{"type":"integer","example":60}},"RateLimit-Remaining":{"description":"Requests remaining in the current window","schema":{"type":"integer","example":0}},"RateLimit-Reset":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}},"500":{"description":"Internal server error"},"503":{"description":"Swap service unavailable"},"504":{"description":"Swap service timed out"}}}},"/v1/affiliate/stats":{"get":{"operationId":"getAffiliateStats","summary":"Get affiliate statistics","description":"Retrieve aggregated swap statistics for an affiliate by partnerCode. Returns total swaps, volume, and fees earned. Supports optional date range filtering.","tags":["Affiliate"],"parameters":[{"schema":{"type":"string","minLength":3,"maxLength":32,"pattern":"^[a-z0-9]+$"},"required":true,"name":"partnerCode","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"startDate","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"endDate","in":"query"}],"responses":{"200":{"description":"Affiliate statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AffiliateStatsResponse"}}}},"400":{"description":"Invalid request parameters"},"429":{"description":"Rate limit exceeded. Includes Retry-After header with seconds until reset.","headers":{"Retry-After":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}},"RateLimit-Limit":{"description":"Maximum requests allowed per window","schema":{"type":"integer","example":60}},"RateLimit-Remaining":{"description":"Requests remaining in the current window","schema":{"type":"integer","example":0}},"RateLimit-Reset":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}},"500":{"description":"Internal server error"},"503":{"description":"Swap service unavailable"},"504":{"description":"Swap service timed out"}}}},"/v1/affiliate/swaps":{"get":{"operationId":"getAffiliateSwaps","summary":"Get affiliate swaps","description":"Retrieve paginated swap history for an affiliate by partnerCode. Supports optional date range filtering.","tags":["Affiliate"],"parameters":[{"schema":{"type":"string","minLength":3,"maxLength":32,"pattern":"^[a-z0-9]+$"},"required":true,"name":"partnerCode","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"startDate","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"endDate","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":1},"required":false,"name":"cursor","in":"query"}],"responses":{"200":{"description":"Affiliate swaps","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AffiliateSwapsResponse"}}}},"400":{"description":"Invalid query parameters"},"429":{"description":"Rate limit exceeded. Includes Retry-After header with seconds until reset.","headers":{"Retry-After":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}},"RateLimit-Limit":{"description":"Maximum requests allowed per window","schema":{"type":"integer","example":60}},"RateLimit-Remaining":{"description":"Requests remaining in the current window","schema":{"type":"integer","example":0}},"RateLimit-Reset":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}},"500":{"description":"Internal server error"},"503":{"description":"Swap service unavailable"},"504":{"description":"Swap service timed out"}}}},"/v1/assets":{"get":{"operationId":"listAssets","summary":"List supported assets","description":"Get a list of all supported assets, optionally filtered by chain.","tags":["Supported Assets"],"parameters":[{"schema":{"type":"string","example":"eip155:1"},"required":false,"name":"chainId","in":"query"},{"schema":{"type":"number","minimum":1,"maximum":1000,"default":100,"example":100},"required":false,"name":"limit","in":"query"},{"schema":{"type":"number","nullable":true,"minimum":0,"default":0,"example":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"List of assets","content":{"application/json":{"schema":{"type":"object","properties":{"assets":{"type":"array","items":{"$ref":"#/components/schemas/Asset"}},"timestamp":{"type":"number"}},"required":["assets","timestamp"]}}}},"400":{"description":"Invalid query parameters"},"429":{"description":"Rate limit exceeded. Includes Retry-After header with seconds until reset.","headers":{"Retry-After":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}},"RateLimit-Limit":{"description":"Maximum requests allowed per window","schema":{"type":"integer","example":60}},"RateLimit-Remaining":{"description":"Requests remaining in the current window","schema":{"type":"integer","example":0}},"RateLimit-Reset":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}},"500":{"description":"Internal server error"}}}},"/v1/assets/{assetId}":{"get":{"operationId":"getAssetById","summary":"Get asset by ID","description":"Get details of a specific asset by its ID (URL encoded).","tags":["Supported Assets"],"parameters":[{"schema":{"type":"string","minLength":1,"example":"eip155:1/slip44:60"},"required":true,"name":"assetId","in":"path"}],"responses":{"200":{"description":"Asset details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Asset"}}}},"400":{"description":"Invalid asset ID"},"404":{"description":"Asset not found"},"429":{"description":"Rate limit exceeded. Includes Retry-After header with seconds until reset.","headers":{"Retry-After":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}},"RateLimit-Limit":{"description":"Maximum requests allowed per window","schema":{"type":"integer","example":60}},"RateLimit-Remaining":{"description":"Requests remaining in the current window","schema":{"type":"integer","example":0}},"RateLimit-Reset":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}},"500":{"description":"Internal server error"}}}},"/v1/assets/count":{"get":{"operationId":"getAssetCount","summary":"Get asset count","description":"Get the total number of supported assets, optionally filtered by chain.","tags":["Supported Assets"],"parameters":[{"schema":{"type":"string","example":"eip155:1"},"required":false,"name":"chainId","in":"query"}],"responses":{"200":{"description":"Asset count","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"number","example":5000},"timestamp":{"type":"number"}},"required":["count","timestamp"]}}}},"400":{"description":"Invalid query parameters"},"429":{"description":"Rate limit exceeded. Includes Retry-After header with seconds until reset.","headers":{"Retry-After":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}},"RateLimit-Limit":{"description":"Maximum requests allowed per window","schema":{"type":"integer","example":60}},"RateLimit-Remaining":{"description":"Requests remaining in the current window","schema":{"type":"integer","example":0}},"RateLimit-Reset":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}},"500":{"description":"Internal server error"}}}},"/v1/auth/siwe/nonce":{"post":{"operationId":"siweNonce","summary":"Get SIWE nonce","description":"Request a nonce for Sign-In with Ethereum (SIWE) authentication.","tags":["Auth"],"responses":{"200":{"description":"SIWE nonce","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiweNonceResponse"}}}},"429":{"description":"Rate limit exceeded. Includes Retry-After header with seconds until reset.","headers":{"Retry-After":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}},"RateLimit-Limit":{"description":"Maximum requests allowed per window","schema":{"type":"integer","example":60}},"RateLimit-Remaining":{"description":"Requests remaining in the current window","schema":{"type":"integer","example":0}},"RateLimit-Reset":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}},"500":{"description":"Internal server error"},"503":{"description":"Swap service unavailable"},"504":{"description":"Swap service timed out"}}}},"/v1/auth/siwe/verify":{"post":{"operationId":"siweVerify","summary":"Verify SIWE signature","description":"Verify a Sign-In with Ethereum (SIWE) message and signature. Returns a JWT token on success.","tags":["Auth"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"signature":{"type":"string"}},"required":["message","signature"]}}}},"responses":{"200":{"description":"Authentication successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiweVerifyResponse"}}}},"400":{"description":"Invalid request body"},"401":{"description":"Invalid signature"},"429":{"description":"Rate limit exceeded. Includes Retry-After header with seconds until reset.","headers":{"Retry-After":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}},"RateLimit-Limit":{"description":"Maximum requests allowed per window","schema":{"type":"integer","example":60}},"RateLimit-Remaining":{"description":"Requests remaining in the current window","schema":{"type":"integer","example":0}},"RateLimit-Reset":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}},"500":{"description":"Internal server error"},"503":{"description":"Swap service unavailable"},"504":{"description":"Swap service timed out"}}}},"/v1/chains":{"get":{"operationId":"listChains","summary":"List supported chains","description":"Get a list of all supported blockchain networks, sorted alphabetically by name.","tags":["Supported Chains"],"responses":{"200":{"description":"List of chains","content":{"application/json":{"schema":{"type":"object","properties":{"chains":{"type":"array","items":{"$ref":"#/components/schemas/Chain"}},"timestamp":{"type":"number"}},"required":["chains","timestamp"]}}}},"429":{"description":"Rate limit exceeded. Includes Retry-After header with seconds until reset.","headers":{"Retry-After":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}},"RateLimit-Limit":{"description":"Maximum requests allowed per window","schema":{"type":"integer","example":60}},"RateLimit-Remaining":{"description":"Requests remaining in the current window","schema":{"type":"integer","example":0}},"RateLimit-Reset":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}},"500":{"description":"Internal server error"}}}},"/v1/chains/count":{"get":{"operationId":"getChainCount","summary":"Get chain count","description":"Get the total number of supported blockchain networks.","tags":["Supported Chains"],"responses":{"200":{"description":"Chain count","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"number","example":28},"timestamp":{"type":"number"}},"required":["count","timestamp"]}}}},"429":{"description":"Rate limit exceeded. Includes Retry-After header with seconds until reset.","headers":{"Retry-After":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}},"RateLimit-Limit":{"description":"Maximum requests allowed per window","schema":{"type":"integer","example":60}},"RateLimit-Remaining":{"description":"Requests remaining in the current window","schema":{"type":"integer","example":0}},"RateLimit-Reset":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}},"500":{"description":"Internal server error"}}}},"/v1/partner/{code}":{"get":{"operationId":"resolvePartner","summary":"Resolve a partner referral code","description":"Resolve a partner referral code to its attribution details (partner address and bps split).","tags":["Affiliate"],"parameters":[{"schema":{"type":"string","minLength":1},"required":true,"name":"code","in":"path"}],"responses":{"200":{"description":"Partner attribution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerResolution"}}}},"400":{"description":"Invalid request parameters"},"404":{"description":"Partner code not found"},"429":{"description":"Rate limit exceeded. Includes Retry-After header with seconds until reset.","headers":{"Retry-After":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}},"RateLimit-Limit":{"description":"Maximum requests allowed per window","schema":{"type":"integer","example":60}},"RateLimit-Remaining":{"description":"Requests remaining in the current window","schema":{"type":"integer","example":0}},"RateLimit-Reset":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}},"500":{"description":"Internal server error"},"503":{"description":"Swap service unavailable"},"504":{"description":"Swap service timed out"}}}},"/v1/swap/quote":{"post":{"operationId":"getSwapQuote","summary":"Get executable quote","description":"Get an executable quote for a swap, including transaction data. Requires a specific swapper name.","tags":["Swaps"],"parameters":[{"schema":{"type":"string"},"required":false,"description":"Partner code for affiliate fee attribution. The API resolves the code to the registered affiliate address and BPS. Register a code at the affiliate dashboard.","name":"X-Partner-Code","in":"header","example":"vultisig"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"sellAssetId":{"type":"string","minLength":1,"example":"eip155:1/slip44:60"},"buyAssetId":{"type":"string","minLength":1,"example":"bip122:000000000019d6689c085ae165831e93/slip44:0"},"sellAmountCryptoBaseUnit":{"type":"string","pattern":"^\\d+$","description":"Exact amount of the sell asset to send, in base units. Required unless buyAmountCryptoBaseUnit is given.","example":"1000000000000000000"},"buyAmountCryptoBaseUnit":{"type":"string","pattern":"^(?!0+$)\\d+$","description":"Exact amount of the buy asset to receive, in base units. The sell amount you must send is derived from it and returned on the quote. Mutually exclusive with sellAmountCryptoBaseUnit, and rejected for swappers that cannot quote an exact output.","example":"100000"},"receiveAddress":{"type":"string","minLength":1,"example":"bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq"},"sendAddress":{"type":"string","minLength":1,"example":"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"},"swapperName":{"type":"string","minLength":1,"example":"Relay"},"slippageTolerancePercentageDecimal":{"type":"string","example":"0.01"},"accountNumber":{"type":"number","nullable":true,"default":0,"example":0},"xpub":{"type":"string","example":"zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs"}},"required":["sellAssetId","buyAssetId","receiveAddress","sendAddress","swapperName"]}}}},"responses":{"200":{"description":"Swap quote","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteResponse"}}}},"400":{"description":"Invalid request or unavailable swapper"},"404":{"description":"No quote available"},"429":{"description":"Rate limit exceeded. Includes Retry-After header with seconds until reset.","headers":{"Retry-After":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}},"RateLimit-Limit":{"description":"Maximum requests allowed per window","schema":{"type":"integer","example":60}},"RateLimit-Remaining":{"description":"Requests remaining in the current window","schema":{"type":"integer","example":0}},"RateLimit-Reset":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}},"500":{"description":"Internal server error"},"502":{"description":"Swapper returned an expired or implausible quote deadline"}}}},"/v1/swap/rates":{"get":{"operationId":"getSwapRates","summary":"Get swap rates","description":"Get informative swap rates from all available swappers. This does not create a transaction.","tags":["Swaps"],"parameters":[{"schema":{"type":"string","minLength":1,"example":"eip155:1/slip44:60"},"required":true,"name":"sellAssetId","in":"query"},{"schema":{"type":"string","minLength":1,"example":"eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"},"required":true,"name":"buyAssetId","in":"query"},{"schema":{"type":"string","pattern":"^\\d+$","description":"Exact amount of the sell asset to send, in base units. Required unless buyAmountCryptoBaseUnit is given.","example":"1000000000000000000"},"required":false,"name":"sellAmountCryptoBaseUnit","in":"query"},{"schema":{"type":"string","pattern":"^(?!0+$)\\d+$","description":"Exact amount of the buy asset to receive, in base units. Each rate returns the sell amount needed to get it. Mutually exclusive with sellAmountCryptoBaseUnit; swappers that cannot quote an exact output come back with an ExactOutputNotSupported error.","example":"100000"},"required":false,"name":"buyAmountCryptoBaseUnit","in":"query"},{"schema":{"type":"string","pattern":"^(?:\\d+)(?:\\.\\d+)?$","example":"0.01"},"required":false,"name":"slippageTolerancePercentageDecimal","in":"query"},{"schema":{"type":"string"},"required":false,"description":"Partner code for affiliate fee attribution. The API resolves the code to the registered affiliate address and BPS. Register a code at the affiliate dashboard.","name":"X-Partner-Code","in":"header","example":"vultisig"}],"responses":{"200":{"description":"Swap rates","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateResponse"}}}},"400":{"description":"Invalid request"},"429":{"description":"Rate limit exceeded. Includes Retry-After header with seconds until reset.","headers":{"Retry-After":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}},"RateLimit-Limit":{"description":"Maximum requests allowed per window","schema":{"type":"integer","example":60}},"RateLimit-Remaining":{"description":"Requests remaining in the current window","schema":{"type":"integer","example":0}},"RateLimit-Reset":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}},"500":{"description":"Internal server error"}}}},"/v1/swap/status":{"get":{"operationId":"getSwapStatus","summary":"Get swap status","description":"Look up the current status of a swap by its quote ID. Pass txHash on the first call after broadcasting to bind it to the quote and start tracking. Subsequent calls can omit txHash.","tags":["Swaps"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"quoteId","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":128},"required":false,"name":"txHash","in":"query"},{"schema":{"type":"string"},"required":false,"description":"Partner code for affiliate fee attribution. The API resolves the code to the registered affiliate address and BPS. Register a code at the affiliate dashboard.","name":"X-Partner-Code","in":"header","example":"vultisig"}],"responses":{"200":{"description":"Swap status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SwapStatusResponse"}}}},"400":{"description":"Invalid request parameters or txHash required to begin tracking"},"404":{"description":"Quote not found or expired"},"409":{"description":"Transaction hash mismatch"},"429":{"description":"Rate limit exceeded. Includes Retry-After header with seconds until reset.","headers":{"Retry-After":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}},"RateLimit-Limit":{"description":"Maximum requests allowed per window","schema":{"type":"integer","example":60}},"RateLimit-Remaining":{"description":"Requests remaining in the current window","schema":{"type":"integer","example":0}},"RateLimit-Reset":{"description":"Seconds until the rate limit window resets","schema":{"type":"integer","example":30}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}},"500":{"description":"Internal server error"},"503":{"description":"Swap service unavailable"},"504":{"description":"Swap service timed out"}}}}},"tags":[{"name":"Swap Widget SDK","description":"The `@shapeshiftoss/swap-widget` package is a drop-in React component that provides a complete swap interface — asset selection, rate comparison, wallet connection, transaction signing, and status tracking — backed by this API.\n\n> 📖 **The canonical, always-current reference is the package README:**\n> [`packages/swap-widget/README.md`](https://github.com/shapeshift/web/blob/develop/packages/swap-widget/README.md).\n> It documents every prop, the theming API, supported chains/swappers, and exported hooks. This page is a short orientation; defer to the README for details.\n\n## Installation\n\n```bash\nnpm install @shapeshiftoss/swap-widget\n```\n\nInstall the peer dependencies alongside it (React, wagmi/viem, React Query, and Reown AppKit):\n\n```bash\nnpm install react react-dom wagmi @wagmi/core viem \\\n  @tanstack/react-query \\\n  @reown/appkit @reown/appkit-adapter-wagmi \\\n  @reown/appkit-adapter-bitcoin @reown/appkit-adapter-solana \\\n  @solana/wallet-adapter-phantom @solana/wallet-adapter-solflare @solana/web3.js\n```\n\nImport the stylesheet once (required for the widget to render correctly):\n\n```tsx\nimport '@shapeshiftoss/swap-widget/style.css'\n```\n\n## Quick Start\n\n```tsx\nimport '@shapeshiftoss/swap-widget/style.css'\n\nimport { SwapWidget } from '@shapeshiftoss/swap-widget'\n\nfunction App() {\n  return (\n    <SwapWidget\n      walletConnectProjectId=\"your-walletconnect-project-id\"\n      partnerCode=\"your-partner-code\"\n      theme=\"dark\"\n      onSwapSuccess={txHash => console.log('Success:', txHash)}\n    />\n  )\n}\n```\n\n## Key things to know\n\n- **Wallet connection is built in.** The widget connects wallets via Reown AppKit (EVM, Bitcoin, and Solana).\n- **AppKit must be initialized before the widget mounts.** Either pass `walletConnectProjectId` and the widget initializes AppKit for you (get a free project ID at [dashboard.reown.com](https://dashboard.reown.com)), or call `createAppKit()` yourself in the host app (with a wagmi EVM adapter) before mounting the widget — the widget detects the shared singleton and supplies its own providers, so you wrap it in none. Pair the host-owned path with `showConnectButton={false}` to drive connection from your own UI. This requires `@reown/appkit*`/`wagmi`/`viem` to dedupe to a single shared copy. See the [README](https://github.com/shapeshift/web/blob/develop/packages/swap-widget/README.md#wallet-connection).\n- **`partnerCode` drives affiliate attribution.** It is forwarded to this API as the `X-Partner-Code` header. See the [Affiliate Program guide](https://github.com/shapeshift/web/blob/develop/docs/affiliates.md).\n- **Chain/asset filtering** uses the `sellFilters` and `buyFilters` props (objects with `allowedChainIds` / `disabledChainIds` / `allowedAssetIds` / `disabledAssetIds`). See the README for the full prop list and examples.\n\nFor the complete props reference, theming options, supported chains and swappers, and exported utilities/hooks, see the [package README](https://github.com/shapeshift/web/blob/develop/packages/swap-widget/README.md).\n"},{"name":"REST API Guide","description":"A step-by-step guide to executing a swap via the REST API. Full request/response schemas for every endpoint are in the reference sections below — this guide covers the flow and the semantics that aren't obvious from the schemas alone (quote expiry, status polling, errors).\n\nAll paths are relative to `https://api.shapeshift.com`. Send `X-Partner-Code: <your-code>` on the swap endpoints to attribute swaps for affiliate revenue (optional).\n\n## 1. Discover chains and assets\n\n```\nGET /v1/chains\nGET /v1/assets?chainId=eip155:1&limit=100&offset=0\n```\n\n`GET /v1/assets` supports optional `chainId`, `limit` (1–1000, default 100), and `offset` (default 0) query params for filtering and pagination. Use `GET /v1/assets/count` to size pagination. Look up a single asset with `GET /v1/assets/{assetId}` (the asset ID is a full CAIP-19 string).\n\n### Destination-only chains\n\nEach chain carries `isSellSupported`. Where it is `false` the chain can be **bought into but not sold from** — we have no way to give you a transaction to sign on it, so `/v1/swap/rates` and `/v1/swap/quote` reject it as a `sellAssetId` with a `400` and `code: 'UNSUPPORTED_SELL_CHAIN'`. It remains valid as a `buyAssetId`, where all you need is a receive address.\n\nThere is no per-asset equivalent — the constraint is a property of the chain, so filter your sell-asset list by joining assets to their `chainId`:\n\n```js\nconst sellable = new Set(chains.filter(c => c.isSellSupported).map(c => c.chainId))\nconst sellAssets = assets.filter(a => sellable.has(a.chainId))\n```\n\nThe set shrinks over time as more chains become executable, so read the flag rather than hardcoding the list.\n\n## 2. Get rates\n\n```\nGET /v1/swap/rates?sellAssetId=eip155:1/slip44:60&buyAssetId=eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48&sellAmountCryptoBaseUnit=1000000000000000000\nX-Partner-Code: your-partner-code\n```\n\nOptional `slippageTolerancePercentageDecimal` (e.g. `0.01` for 1%). The response returns a `rates` array (one entry per swapper, each with its own `swapperName`, amounts, fees, and an optional per-swapper `error`) plus `timestamp` and `expiresAt`. **Rates are indicative**, expire quickly (`expiresAt` ≈ 30s after issue), and are for display/comparison — request a quote to execute.\n\nA non-empty `allowanceContract` on a rate means executing that swapper pulls the sell token from an ERC-20 allowance. Clients that want to handle approvals themselves — checking the current allowance, or setting an unlimited approval ahead of time — can use it directly at this stage; otherwise the quote supplies ready-to-sign approval transactions.\n\n## 3. Get an executable quote\n\n```\nPOST /v1/swap/quote\nContent-Type: application/json\nX-Partner-Code: your-partner-code\n\n{\n  \"sellAssetId\": \"eip155:1/slip44:60\",\n  \"buyAssetId\": \"bip122:000000000019d6689c085ae165831e93/slip44:0\",\n  \"sellAmountCryptoBaseUnit\": \"1000000000000000000\",\n  \"swapperName\": \"Relay\",\n  \"receiveAddress\": \"bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq\",\n  \"sendAddress\": \"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\",\n  \"slippageTolerancePercentageDecimal\": \"0.01\",\n  \"accountNumber\": 0\n}\n```\n\n- `swapperName` comes from the rate you chose in step 2.\n- `slippageTolerancePercentageDecimal` is optional; `accountNumber` is optional (defaults to `0`) and is needed for chains that derive addresses per account index (e.g. UTXO/Cosmos).\n- The response includes a `quoteId` (needed for status tracking), an `approval` object (whether an ERC-20 approval is required, the spender, and ready-to-sign `approvalTxs` when it is), and a `steps` array. Each step may include `transactionData` — a discriminated union on `type` (`evm`, `solana`, `utxo`, `cosmossdk_msg_send`, `cosmossdk_msg_deposit`) — describing exactly what to sign for that chain.\n- Quotes expire: honor the `expiresAt` timestamp — it reflects the swapper's own quote deadline (e.g. THORChain inbound addresses rotate, deposit-address swappers deactivate their channels; deadline-less providers get a conservative 60s). **Never sign or broadcast after `expiresAt`** — for deposit-style swappers funds sent late can be lost. Request a fresh quote instead.\n\n## 4. Execute the swap\n\nThe API does **not** broadcast transactions — your application signs and broadcasts with the user's wallet:\n\n1. If `approval.isRequired` is true, sign and broadcast each transaction in `approval.approvalTxs` in order, waiting for each to confirm. These are **exact approvals** — sized to the step's `sellAmountCryptoBaseUnit` and consumed by the swap's execution, so a later swap needs its own approval unless a sufficient allowance is already in place (`approvalTxs` is empty in that case, with `isRequired: false`). Usually it is a single approve; tokens that require resetting a non-zero allowance before changing it (e.g. USDT) get a preceding `approve(spender, 0)`. Clients preferring an unlimited approval can build their own `approve(approval.spender, amount)` instead. Quotes are issued before approval exists — network fees are estimated as if the approval were already in place.\n2. For each step with `transactionData`, build, sign, and broadcast the transaction according to its `type` (EVM tx, Solana instructions, UTXO PSBT/deposit, or Cosmos message).\n3. Capture the resulting transaction hash for status tracking.\n\n## 5. Track status\n\n```\nGET /v1/swap/status?quoteId=<quoteId>&txHash=0x...\n```\n\n- On the **first call after broadcasting**, include `txHash` to bind it to the quote and begin tracking. This sets status to `submitted`. Subsequent polls can omit `txHash`.\n- `status` is one of `submitted`, `confirmed`, `failed`. Poll until `confirmed` or `failed`; a `buyTxHash` appears once the destination transaction is known.\n- Poll at a modest interval (e.g. every 5–15s) and respect rate-limit headers. Stop polling on a terminal status.\n\n### Status errors\n\n- `404` `QUOTE_NOT_FOUND` — the quote is unknown or has expired from the store. Request a new quote.\n- `400` `TX_HASH_REQUIRED` — no `txHash` was provided and none is bound yet; pass the broadcast tx hash.\n- `409` `TX_HASH_MISMATCH` — a different `txHash` is already bound to this quote.\n\n## Affiliate reporting (optional)\n\nOnce live, partners can review attributed activity by partner code:\n\n```\nGET /v1/affiliate/stats?partnerCode=your-partner-code\nGET /v1/affiliate/swaps?partnerCode=your-partner-code\n```\n\nYou can also resolve a code to its attribution details (partner address and bps split) with `GET /v1/partner/{code}`.\n"}]}