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:

FieldTypeDescription
userAddressstring, requiredThe TON wallet address that will sign and send. Must be a valid TON address (bounceable or non-bounceable form).
validForSecondsnumber, optionalHow long the TonConnect validUntil window is open from now. Default 300 (5 minutes).

Example

bash
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)

json
{
  "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():

ts
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:

ts
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.