POST /v1/tx
Builds the on-chain message(s) for a swap. The aggregator re-quotes the route at request time so the slippage limits in the message reflect the current state of the pools.
Request body
Same fields as POST /v1/quote, plus:
| Field | Type | Description |
|---|---|---|
userAddress | string, required | The TON wallet address that will sign and send. Must be a valid TON address (bounceable or non-bounceable form). |
validForSeconds | number, optional | How long the TonConnect validUntil window is open from now. Default 300 (5 minutes). |
Example
curl -X POST https://chop.ag/api/v1/tx \
-H 'content-type: application/json' \
-d '{
"assetIn": "TON",
"assetOut": "EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs",
"amountIn": "1000000000",
"userAddress": "UQAJInSAE7GB_bL49OLFYYVHLgmZTMYF31wlJ51XkQJCTFal"
}'Response (200)
{
"route": { "...": "..." },
"messages": [
{
"to": "EQDa4VOnTYlLvDJ0gZjNYm5PXfSmmtL6Vs6A_CZEtXCNICq_",
"value": "1250000000",
"bodyBoc": "te6cckEBAgEAQAABa+oG…"
}
],
"totalValue": "1250000000",
"tonConnect": {
"validUntil": 1778076501,
"messages": [
{
"address": "EQDa4VOnTYlLv…",
"amount": "1250000000",
"payload": "te6cckEBAgEAQAABa+oG…"
}
]
}
}Two ways to use the response
Browser (TonConnect)
Pass response.tonConnect directly to tonConnectUI.sendTransaction():
await tonConnectUI.sendTransaction(response.tonConnect);TonConnect handles the signing modal and broadcast. The full TonConnect guide is at /docs/integration/tonconnect.
Server-side wallet
Use the raw messages array. Decode each bodyBoc back into a Cell and feed to your wallet:
import { internal, Cell } from '@ton/core';
const messages = response.messages.map((m) =>
internal({
to: m.to,
value: BigInt(m.value),
body: Cell.fromBase64(m.bodyBoc),
bounce: true,
})
);
await wallet.sendTransfer({
seqno: await wallet.getSeqno(),
secretKey: keyPair.secretKey,
messages,
});Multi-message transactions
When the route splits across DEXs, messages.length can be 2 or more. Wallet v4 supports up to 4 outgoing messages per signed transaction; v5 supports many more. If the response would exceed your wallet’s limit, you’ll get a 400 from /v1/tx.
All legs of a multi-message transaction settle in the same block. Either every leg succeeds or none of them broadcast. There is no risk of being half-filled across DEXs in the way a multi-tx flow would carry.
Slippage and re-quoting
Each leg’s minAmountOut is enforced on-chain by the DEX contract. If the price moves against you between the time we built the tx and the time it lands, the swap aborts and your input is refunded (you only pay gas).
We re-quote the route at the moment of the /v1/tx call, so the limits in the message reflect the latest prices, not the prices from the earlier /v1/quote. Don’t cache tx bodies between sessions.