Skip to main content
This guide takes a single-chain quote to a confirmed swap: build the transaction with POST /swap, approve the exact input amount, estimate gas, send the transaction from the wallet and wait for the receipt. Olympex is non-custodial: it returns calldata and never signs or broadcasts the transaction.
You need API credentials and the signing helper from Sign requests, plus a wallet that holds the input token and native token for gas. If you haven’t quoted yet, start with Get a swap quote.

Prerequisites

  • OLYMPEX_API_KEY_ID, OLYMPEX_SECRET_KEY and OLYMPEX_PASSPHRASE in your server’s environment, and sign-request.ts saved next to your code.
  • Node.js 22.18 or later, which runs .ts files directly, in an ES module project (npm pkg set type=module), and viem 2 (npm install viem). The same wallet steps with ethers v6 follow the steps.
  • An RPC URL for the chain, as POLYGON_RPC_URL in this guide.
  • A wallet funded on that chain with the input token (10 USDT here) and POL for gas. The script reads its private key from WALLET_PRIVATE_KEY.

Steps

POST /swap returns real mainnet calldata, and broadcasting it moves funds. Olympex has no testnet environment, so test with a small amount from a dedicated wallet.
1

Set up the clients and get a fresh quote

The snippets in these steps form one script, execute-swap.ts. Run it with node execute-swap.ts.
In a dApp, split the work. Your server signs the Olympex requests and returns the POST /swap response to the browser; the user’s wallet approves and sends the transaction, for example through createWalletClient({ transport: custom(window.ethereum) }). Your API credentials never reach the browser.
Quote right before you build with POST /quotes: a quote is not reserved, and prices move. See Slippage and price impact.
2

Build the transaction with POST /swap

Send the same pair, amount, slippage and gas price hint as the quote, plus two fields:
  • account: the wallet that sends the transaction and receives the output. The calldata is bound to it.
  • aggregatorId: the liquidity source to build with. buildSwap tries the quote’s winner first and moves down aggregatorOrder when a source returns 422 NO_ROUTE or 500 SWAP_ERROR, or when its calldata reverts in the gas estimate (step 4).
If you charge an integrator fee, send the same fees object you sent with the quote.
The same request from cURL or Python:
A response looks like this, with the calldata shortened:
Response
Security model lists every check to run before a wallet signs.
3

Approve the exact input amount

For ERC-20 input, the wallet must allow contractToApprove to spend the input amount. Approve exactly that amount, in base units of the input token, and never an unlimited amount. An approval takes at least a block, so build the swap again once it confirms: the calldata’s expiry window then starts after the approval.
ensureAllowance resets any non-zero allowance to 0 before it approves, which costs one extra transaction on tokens that don’t need it. If you keep a list of tokens that require the reset, reset only for those. approveInput also checks the balance first, so a gas estimate that reverts in the next step points at the route itself.Native-token input. To sell the chain’s native token, set inTokenAddress to 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE. There is nothing to approve: the swap response sets value, in wei, and the transaction carries it. Keep extra native token in the wallet for gas. The uniswapV3Hermes source doesn’t support native-token input.
4

Estimate gas, and fall back if the calldata reverts

Always run eth_estimateGas on the exact transaction before you send it, and add a buffer (20% here). A 200 from POST /swap doesn’t guarantee that the calldata executes: a source can build calldata that reverts. Don’t size the gas limit from the quote’s estimatedGas either: it covers only the source’s part of the route, not the Olympex contracts. Use gasLimit from the response only when your RPC can’t produce an estimate, and never when it’s "0".
An estimate that reverts means the transaction would revert, so never send it. approveInput has checked the balance and the allowance, and the calldata is seconds old, so the route as built can’t execute: the source built calldata that reverts, a market maker’s quote inside the route has already expired, or the price moved past your slippage. The loop builds the swap with the next source in aggregatorOrder, approves its spender if it differs, and estimates again. When no source is left, buildSwap throws: request a new quote and start again. A fallback source can return less, so show the user the new outAmount and minOutAmount before they sign. Gas and fees explains why gasLimit is only a fallback.
5

Send the transaction right away

Send as soon as the estimate succeeds. The calldata carries an on-chain expiry (5 minutes on most routes), and some routes include a market maker’s quote that expires within seconds of the build: if the estimate reverts because that quote expired, build the swap again, as step 4 does. The calldata is also bound to account, and another Olympex swap from the same account can invalidate it. Don’t queue or cache calldata; build it for each transaction.
6

Wait for the receipt

A single-chain swap is final when its transaction is. The receipt from your RPC is the source of truth. To ask Olympex instead, poll GET /transactions/{hash}: it reports the same result, success or reverted. Track a swap to finality covers confirmations, timeouts and replaced transactions.
This replaces steps 3 to 6 for a wallet built with ethers v6 (npm install ethers). It reuses trade, isNative, swap, aggregatorId, revertedSources and buildSwap from steps 1 and 2. Unlike the viem version, it doesn’t fall back to gasLimit when the node returns an error: ethers reports any node error on eth_estimateGas as CALL_EXCEPTION, so it treats every such error as a revert and moves to the next source, and the gasLimit fallback runs only on network or HTTP errors.

Verify

  • receipt.status is "success", and the transaction appears on the chain’s block explorer (Polygonscan for Polygon) with to set to the to from POST /swap.
  • The wallet received at least minOutAmount of the output token. For ERC-20 output, add up the token’s Transfer events to account in the receipt:
For native-token output there is no Transfer event; compare the wallet’s native balance before and after instead, allowing for the gas you paid.

Common pitfalls

Expired or superseded calldata. Calldata carries an on-chain expiry (5 minutes on most routes), and a market maker’s quote inside some routes expires within seconds of the build. It is also bound to account, and another Olympex swap from the same account can invalidate earlier calldata. Build each swap right before you send it, and send one swap at a time per account.
Sending calldata without an estimate. A 200 from POST /swap doesn’t mean the calldata executes. Run eth_estimateGas on every transaction before the wallet signs it, and if it reverts, build the swap with the next source in aggregatorOrder instead of sending it.
Approving the wrong spender or an unlimited amount. Approve contractToApprove, not to, and approve the exact input amount. An unlimited approval leaves the wallet exposed long after the swap.
Trusting gasLimit. gasLimit is estimatedGas × 2, and estimatedGas can be a placeholder ("1500000") or "0". Estimate gas yourself and use gasLimit only when your RPC can’t estimate, and never when it’s "0".
Sending from a different wallet. Send the transaction from the account you passed to POST /swap. The calldata is built for that address, and the output goes to it.
Retrying a broadcast blindly. If sendTransaction throws, the transaction may still have reached the chain. Before you build and send a new swap, look up the first hash or compare the account’s nonce, or the user can end up swapping twice.

What’s next

Track a swap to finality

Confirmations, timeouts and replaced transactions.

Cross-chain swap end-to-end

The same flow across two chains.

Build a swap

Every field of POST /swap.

Security model

Approvals, calldata binding and the checks to run before signing.