Transaction Builder
The Transaction Builder API turns a high-level intent — "supply 1,000 USDC to Aave V3" or "bridge USDC from Ethereum to Base via CCTP" — into ready-to-submit calldata for a vault's Manager contract. It's the same engine that powers the rebalance feature in the Veda Console, exposed for programmatic use.
Base URL: https://api.veda.tech
OpenAPI / Swagger: api.veda.tech/docs
Always verify calldata independently before signing. The Transaction Builder is a convenience — it is not a substitute for review. Decode the returned encoded_tx_data against the Manager ABI and run it through Tenderly or another simulator before broadcasting. Confirm the target address and every encoded argument match what you intended. Never rely solely on the API response for correctness. Independent simulation is the last line of defense.
Concepts
A rebalance is one or more onchain actions executed through a vault's Manager contract. The API is build-only: it returns encoded calldata and a target address; you sign and submit the transaction from your strategist address.
The workflow:
Discover what actions are available for a vault —
GET /actionsInspect constraints for actions with correlated parameters —
GET /constraintsBuild a single action —
POST /execute— or several atomically —POST /execute-multipleSubmit the returned
encoded_tx_datato the Manager from the strategist address
Every action endpoint is scoped by three path parameters:
chain
Lowercase chain slug (e.g. ethereum, base, arbitrum). See Chain Support for the full list.
vault_address
The BoringVault contract address
strategist_address
The strategist address whose merkle tree / permissions are being used. A single vault can have multiple strategists with different permitted actions.
Authentication
All Transaction Builder endpoints require an API key created in the Veda Console. Pass it as a Bearer token:
See Quick Start for how to create one. All examples below assume the key is in $VEDA_API_KEY.
1. List available actions
Returns every action the vault's merkle tree authorizes for the given strategist, along with the parameter metadata you need to build a transaction. No request body, no query parameters.
Example request
Response structure
A JSON object keyed by route (e.g. aavev3/supply). Each entry describes one action:
name
string
Human-readable action name
protocol
string
Protocol identifier (e.g. AaveV3, 1Inch)
protocol_app_url
string
Link to the protocol's app, when applicable
description
string
What the action does
has_constraints
boolean
If true, params are correlated — call /constraints/{route} for valid combinations
params
array
Parameter definitions (see below)
Each params[i] is:
name
string
Parameter name to pass in the execute request
type
string
Python type name (str, int, float, Decimal)
description
string
Human-readable description
required
boolean
Whether the parameter must be provided
default_value
any | null
Default if not provided (only meaningful for non-required params)
choices
array | null
Allowed values. [] means freeform; null means optional and may be omitted; a populated list means you must pick from it.
min_value
number | null
Minimum valid value, if applicable
max_value
number | null
Maximum valid value, if applicable
omitToUseAll
boolean
If true, omitting this parameter uses the vault's full balance of the token
acceptRawString
boolean
If true, the value is forwarded as-is (no numeric conversion)
Grouped choices. Most params have choices as a flat array of strings (["USDC", "USDT"]). Some params use nested arrays ([["USDC", "0xa0b8..."], ["USDT", "0xdac1..."]]) where each inner array is [display_label, value]. When building a UI, check whether the first element of choices is itself an array to decide which format you're dealing with.
Example response (abbreviated)
When has_constraints is true, the values in each param's choices are the projection of the valid combinations onto that one param. You still need to call the constraints endpoint to know which combinations are actually valid (e.g. USDC → USDT may be allowed but USDC → USDC is not).
2. Inspect parameter constraints
When has_constraints is true, not every combination of choices is valid. The constraints endpoint returns the valid combinations.
Example request
Example response
Each entry in constraints is one valid combination. Use this to drive dependent dropdowns in a UI, or to filter to a single combination in a script. Routes where has_constraints is false have fully independent parameters — any combination of values from choices is valid.
A 404 from this endpoint means the route has no parameter constraints (i.e. you didn't need to call it).
3. Build a single action
The tail matcher captures everything after the vault. It accepts either of:
{strategist_address}/{route}— recommended; explicit{route}— the API resolves the strategist for the vault
When tail begins with a 0x…-prefixed 42-character string, that prefix is treated as the strategist address and the rest is the route. The route itself contains a slash (e.g. aavev3/supply), which is why tail:path is used.
Request body
params
object (string → any)
{}
Key-value map of action parameters, matching the /actions metadata for this route
verbose
boolean
false
Return detailed simulation output — token transfers, gas cost in ETH, and protocol-level metadata in action_api_response (including warnings). Recommended for any review step.
skip_sim
boolean
false
Skip the Tenderly simulation. Set true for faster responses or when you've already simulated.
Example request
Response structure
encoded_tx_data
string
Yes
Calldata (hex, 0x-prefixed) to submit to the vault's Manager contract
target
string
Yes
Manager contract address — the to of your transaction
description
string
Yes
Human-readable description of the action being built
action_api_response
object | null
Yes
Protocol-specific metadata. See Simulation warnings for the warning keys
simulation_status
boolean | string
When simulated
true if the Tenderly simulation succeeded; may also be an error string on failure
tenderly_simulation_url
string | null
When simulated
Link to the Tenderly simulation
simulation_logs
array
When simulated
Logs emitted during the simulation (when available)
simulation_gas_used
number | null
When simulated
Gas used during the simulation (when available)
simulation_gas_cost_eth
string | null
When verbose
Estimated gas cost denominated in ETH
token_transfers
array
When verbose
Structured list of tokens moved during the simulation (see below)
simulation_skipped
boolean
When skipped
Present and true when skip_sim: true was passed
Token transfers
When verbose: true, the response includes a token_transfers array with one entry per token movement observed during the simulation:
token
string
Token symbol (e.g. USDC)
token_address
string
Token contract address
amount
string
Human-readable amount in display units
raw_amount
string
Amount in the token's smallest unit (wei / base unit)
direction
"in" | "out"
Whether the vault receives or sends the token
dollar_value
string | number | null
Estimated USD value, when a price is available
Example response
The token_transfers and simulation_gas_cost_eth fields are only present when the request includes verbose: true. Without it, you still get simulation_status, simulation_gas_used, and tenderly_simulation_url.
4. Build multiple actions (atomic batch)
Build a single atomic transaction that runs several actions in order. The response is one piece of calldata that calls the Manager with all actions packed together — recommended for any rebalance that involves more than one step (e.g. swap then supply, withdraw from one position and deposit into another).
Request body
actions
array of objects
—
One entry per action. Each is { "route": string, "params": object }.
verbose
boolean
false
Return detailed simulation output — token transfers, gas cost in ETH, and per-action metadata.
skip_sim
boolean
false
Skip the Tenderly simulation
An empty actions array is rejected with 400 No actions provided.
Example request
Swap 1,000 USDC into USDT via 1Inch, then supply 500 USDC into Aave V3 — in a single onchain transaction:
Response structure
Same shape as /execute, with two differences:
descriptionis always"Multiple actions execution"action_api_responseis an array — one entry per action, in the same order asactions
Example response
Error handling
The API returns standard HTTP status codes with JSON error bodies. The error shape varies — handle both forms:
Structured error (most common for 400 / 422):
String error (some 404 and 500 responses):
FastAPI validation error (422 from Pydantic):
When parsing errors, check typeof detail — it can be a string, an object with error/details keys, or an array of validation errors. Some responses use top-level error or message keys instead of detail.
Additionally, the execute response itself may include error and details fields alongside a successful encoded_tx_data — for example, when the calldata was built but the simulation failed. Always check simulation_status even when the HTTP status is 200.
Common errors
400
Missing or invalid parameters; empty actions array; unknown route in a batch
401
Missing, expired, or revoked API key
404
Unknown vault, strategist, or route (and on /constraints, a route that has no constraints)
422
Parameter validation failed (e.g. value not in choices, type mismatch)
500
Internal error — includes the offending action for batch failures
Last updated