private: true, DZap routes the trade through a privacy exchange. Your transaction sends the tokens through the DZap router to the exchange’s deposit address, the recipient is paid separately, and the transaction itself is still public. Ghost Mode is EVM-only and works for swaps and bridges on the pairs the privacy exchanges support. Expect it to be slower and pay out less than the recommended public route.
Setup
This example bridges 100 USDC from Arbitrum to another wallet on Base, signing withwalletClient, a viem wallet client built from the private key in PRIVATE_KEY. Set RECIPIENT to that wallet; sending to your own address defeats the purpose. Amounts are strings in the token’s smallest unit, and no API key is needed.
Steps
1
Quote
getTradeQuotes with private: true returns only privacy-exchange routes. The flag is top-level, so it applies to every pair in the request. pair.quoteRates lists the routes, recommendedSource names DZap’s pick, and each route’s duration is its estimated time in seconds.2
Approve
The DZap router on Arbitrum needs permission to move your USDC, as in a regular bridge.
getAllowance reads the current allowance, and if it’s too low, approve() approves exactly the bridge amount.3
Build
buildTradeTxn with private: true opens an order with the exchange and returns the transaction to send, private: true as confirmation, and a txId. Keep the txId: it’s the only way to track a private trade. additionalInfo holds the order details, including the exchange’s deposit address. Private trades can’t be gasless, so gasless stays false.4
Send
trade() signs and sends the built transaction; passing it as txnData skips a second build. The transaction moves your USDC through the router to the exchange’s deposit address, and the recipient doesn’t appear in it.5
Status
The recipient is paid after your transaction confirms, which takes minutes. Poll
getTradeTxnStatus with the build’s txId until the status leaves PENDING. The status comes back empty until DZap picks up the trade, which the loop treats as “not yet”. The catch skips only the 429s that the keyless limit of 5 requests a minute can cause and rethrows anything else. The loop gives up after 30 minutes, and the check after it throws unless the status is COMPLETED.End-to-end
API usage
The same flow over REST: send"private": true on the quote and the build, and track the trade by the build’s txId.
transaction from the build response with your own wallet. Full reference: Quote, Build Tx, Status.
Public vs Ghost Mode
What can go wrong
- No route: the response has no entry for the pair, or its
quoteRatesis empty. Private routes cover fewer pairs than public ones, and quoting again sometimes returns routes. - The build fails:
buildTradeTxnthrows. The error’sactionsays what to fix;TRY_ANOTHER_ROUTEmeans building with another route frompair.quoteRates. - An old build: the build opens an order with the exchange, and some orders expire an hour later (
additionalInfo.expiresAt). Build again instead of sending an old build. gasless: true: private trades can’t be gasless; the API answersPrivate swaps cannot be gasless.Not completed: no status: the status stayed empty until the loop gave up. Check that your transaction confirmed and thattxIdcomes from this build.- 400
Private transaction status check is not supported: you polled with the transaction hash. Use the build’stxId. - HTTP 429: without an API key, the trade API allows 5 requests a minute in total, shared by every endpoint, and
retryAftersays how many seconds to wait. The status loop skips 429s and polls again.