How to test token-to-token swap flows in the sandbox environment
Prerequisite: Your organization must be approved before it can quote. Swaps do not need a bank account. For onboarding your customers, see KYC Overview.
A swap exchanges one asset for another on the same chain. In v2 a swap is a quote and an order between two wallet payment accounts, the same way an onramp or offramp is. The destination can be the same wallet as the source, or another wallet on the same chain.Every call below runs for one organization, set as $ORGANIZATION_ID in the examples. Use your own organization’s id from GET /me, or a customer organization’s id when you swap for that customer. Register the wallets, quote and order under the same id. See Organizations in the route.
export ORGANIZATION_ID=<organization_id>
Swaps run on Stellar, Solana and Monad. The source and destination wallets must be on the same chain. To move the same token to a wallet on another chain, quote a cross-chain transfer instead. A quote between different tokens on different chains returns 400invalid-request. Base, Polygon and Avalanche support onramps and offramps, not swaps.
Stellar swaps need a funded, trustlined wallet. The wallet must hold XLM for the network fee and a trustline for the asset it receives. An embedded wallet does not need this setup: its first onramp pays for its reserves, we pay its network fees and bill them at cost, and a token it has no trustline for arrives as a claim. See the Stellar, Solana and Monad chain guides for per-chain setup.
Register the wallets: POST /organization/{organizationId}/payment_account
Show Details
Register the wallet that sends the source asset. To deliver to a different wallet, register that one too. The source can also be an embedded wallet you registered with kindembeddedWallet. See Register payment account for the full schema.
Create a quote: POST /organization/{organizationId}/quote
Show Details
Quote between the two wallet accounts. Each account must belong to the organization in the route or to your API key’s organization. Quotes expire 2 minutes after they are created (expiresAt). The response includes rateBeforeFees, rateAfterFees and midMarketRate. See Create quote for the full schema.
Partner fees: We apply your organization’s partner fee automatically. To set it for one quote, add "partnerFeeBpsOverride": 100. We cap values above 500. See Partner fees.
4
Create the order: POST /organization/{organizationId}/order
Show Details
Send the quoteId. The response is 201 with the full order, and the order’s id equals the quoteId. See Create order for the full schema.
As on an offramp, fundingInstructions.rail is the chain, and fundingInstructions.destination gives the address to send to, a memo when one is needed, and a preparedTransaction when we built one. When the source is an embedded wallet, destination holds an authorizationId in place of an address.
5
Send the source asset
Show Details
The swap does not start until the customer’s wallet sends the source asset. Fund the order before fundingDeadline in one of three ways:
Sign the prepared transaction. When preparedTransaction is present, sign transaction with the customer’s wallet and submit it to the network.
Send a transfer yourself. Send the order’s source.amount of source.asset to address, with memo when it is present.
Prepared transactions go stale. A Solana or Stellar transaction goes stale after refreshAfter. A Stellar or EVM transaction also goes stale when the wallet sends another transaction first. In either case, call POST /organization/{organizationId}/order/{id}/funding_instructions/refresh. The new funding instructions arrive a moment later in an orderUpdated webhook and on GET.
6
Track the order: GET /organization/{organizationId}/order/{id}
Show Details
We receive the source asset, run the swap on the chain’s venue, and deliver the result to the destination wallet. The status moves created → funded → completed. Read the order with Get order, or subscribe to orderUpdated with POST /webhook_subscription.
Swaps are orders, so List orders returns them with your onramps and offramps.When the destination is an embedded wallet that has no trustline for the destination token yet, the order ends claimable. Claim it the same way as an onramp: see Claims.
Sandbox API keys only. The tester sends requests from your browser with the API key you paste. Production keys do not work in it. In production, call these endpoints from your server.
The tester lists the organization’s wallet payment accounts and runs a swap between two of them: quote, order, funding, and the order’s progress. Each step shows its request and response, with a curl command to copy.
Embedded wallet source: paste the PKCS#8 PEM private key of the wallet’s signer key. Your organization needs embedded wallets turned on, and the wallet must already hold the source token. The tester signs the order’s funding authorization in your browser and, when the destination is the same wallet and ends claimable, prepares and signs the claim authorization too. The key never leaves the page.
Self-held wallet source: the tester shows fundingInstructions.destination. Send the funds or sign preparedTransaction with your own wallet, and refresh the funding instructions when the prepared transaction goes stale.