Developer docs

Swap Plans

VeTrade is a VeChain DEX aggregator for quotes, executable swap bundles, and limit-order workflows.

POST /v2/swap-plans returns a quote-only plan or wallet-bound VeChain clauses. It does not sign or submit. GET /v2/swap-plans describes the request contract.

First quote

Prerequisites: curl and the mainnet addresses of both supported tokens. This runnable request uses 1 native VET as input and B3TR as output. No wallet or key is required for quote_only.

Units beside the request: HTTP amountIn is an integer string in raw token units. VET has 18 decimals: "1000000000000000000" means 1 VET. slippageBps: 100 means 1%, not 100%.

curl -fsS https://vetrade.vet/v2/swap-plans \
  -H 'Content-Type: application/json' \
  --data-binary @- <<'JSON'
{
  "mode": "quote_only",
  "inputToken": "0x0000000000000000000000000000000000000000",
  "outputToken": "0x5ef79995fe8a89e0812330e4378eb2660cede699",
  "amountIn": "1000000000000000000",
  "slippageBps": 100
}
JSON

Expected: quote, routePlan, warnings, and bundle: null. A route may be unavailable. The following successful-response excerpt is illustrative, with made-up raw output amounts; it is not a live quote or a complete response:

{
  "apiVersion": "v2",
  "mode": "quote_only",
  "quote": {
    "amountIn": "1000000000000000000",
    "amountOut": "2000000000000000000",
    "amountOutMin": "1980000000000000000",
    "slippageBps": 100
  },
  "bundle": null,
  "simulation": null,
  "warnings": []
}

Read quote.generatedAt and quote.validUntil in the full response. Refresh the plan when expired; an old quote is not an available trade.

Amount units

Entry pointAmount fieldMeaning
HTTP swap plans and hosted quote_swapamountInRaw integer units of the input token
Hosted quoteamountHuman decimal string; token selectors accept symbols or addresses
Hosted swapamountHuman decimal string such as "1.5"
Local helper quote-swap and SDK quote_swapamountHuman decimal string
Quote responseamountOut, amountOutMinRaw integer units of the output token

Use the token registry decimals for each side. Do not assume every token has 18 decimals. Convert using exact decimal/integer arithmetic, not JavaScript floating-point multiplication. Keep raw amounts as strings.

Wallet-bound plan

Use mode: "wallet_bound" and the actual signer-bound recipient. Request include.simulation: true. All other fields use the same raw units as the first example.

{
  "mode": "wallet_bound",
  "inputToken": "0x0000000000000000000000000000000000000000",
  "outputToken": "0x5ef79995fe8a89e0812330e4378eb2660cede699",
  "amountIn": "1000000000000000000",
  "recipient": "0x1111111111111111111111111111111111111111",
  "slippageBps": 100,
  "include": { "simulation": true }
}

The recipient above is an example address. Replace it before using the plan. For a different final recipient, use transfer plans instead of changing a signer-bound local swap.

Correct a failed request

amountIn: "1.5" is invalid here. To request 1.5 VET, use amountIn: "1500000000000000000". For wallet_bound, a missing recipient is also invalid: add the actual wallet address, or use quote_only when no clauses are needed.

Inspect error.details.issues and error.action; correct the named fields before retrying. UPSTREAM_QUOTE_API_ERROR can indicate quote-service or route failure. Recheck pair and amount, then retry after the underlying issue changes. Error reference.

Review and settlement

Check minimum received, route, permissions, costs and freshness before local signing. Simulation is a preflight result. Only the receipt and actual settlement establish the outcome; failure may consume gas. Continue with MCP, the skill or SDK.