Guides
Selecting UTXOs for Transactions#
Unspent Transaction Outputs (UTXOs) are Cardano's way of tracking value. Unlike account-based blockchains, Cardano tracks individual outputs from previous transactions that haven't been spent yet. When building a transaction, you need to specify which UTXOs to use as inputs.
Test vs Production#
In test environments (preprod, preview), the utxos parameter is optional—Anvil will automatically fetch and select UTXOs from the changeAddress:
// Test environment: No UTXOs needed
const response = await fetch('https://preprod.api.ada-anvil.app/v2/services/transactions/build', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Api-Key': 'YOUR_API_KEY'
},
body: JSON.stringify({
changeAddress: 'addr_test...',
outputs: [{ address: 'addr_test...', lovelace: 5_000_000 }]
})
});Production requires explicit UTXOs. You must provide the utxos parameter when building transactions on mainnet. Multi-account wallets (e.g., Eternl) also require explicit UTXOs in all environments.
The transaction builder accepts two UTXO-related parameters:
utxos— Available UTXOs (hex-CBOR encoded) for the builder to select fromrequiredInputs— Specific UTXOs that must be consumed (useful for smart contracts where a particular UTXO unlocks state or rewards)
// Production: Explicit UTXOs with a required input
body: JSON.stringify({
changeAddress: 'addr...',
utxos: ['8282...', '8282...'], // Pool of available UTXOs
requiredInputs: ['8282...'], // Must be spent (e.g., script UTXO)
outputs: [{ address: 'addr...', lovelace: 5_000_000 }]
})Fetching UTXOs#
Choose your approach based on where your code runs:
| Scenario | Approach | Why |
|---|---|---|
| Browser dApp with connected wallet | Weld | UTXOs from user's wallet, seamless signing |
| Backend service or automation | Anvil API | No browser needed, query any address |
| Hardware wallet signing | Anvil API | Fetch UTXOs server-side, sign offline |
Frontend: Weld#
Weld provides a unified interface for CIP-30 browser wallets (Eternl, Lace, Nami, etc.). UTXOs come directly from the user's connected wallet and are always current.
import { useWallet } from "@ada-anvil/weld";
const wallet = useWallet("isConnected", "handler");
const buildTransaction = async () => {
if (!wallet.isConnected) {
return;
}
const utxos = await wallet.handler.getUtxos();
const changeAddress = wallet.changeAddressBech32;
const response = await fetch('https://preprod.api.ada-anvil.app/v2/services/transactions/build', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-Api-Key': 'YOUR_API_KEY' },
body: JSON.stringify({
changeAddress,
utxos,
outputs: [{ address: 'addr_test1qy...', lovelace: 5_000_000 }]
})
});
const { complete } = await response.json();
const signature = await wallet.handler.signTx(complete);
// Submit signed transaction...
};Backend: Anvil API#
For server-side applications, use Anvil's /wallets/utxos endpoint. UTXOs are returned in the exact hex-CBOR format needed for transaction building.
const API_BASE = 'https://preprod.api.ada-anvil.app/v2/services';
const API_KEY = 'YOUR_API_KEY';
async function getUtxos(address: string): Promise<string[]> {
const response = await fetch(`${API_BASE}/wallets/utxos?address=${address}`, {
headers: { 'X-Api-Key': API_KEY }
});
return response.json();
}
const address = 'addr_test1qz...';
const utxos = await getUtxos(address);
const response = await fetch(`${API_BASE}/transactions/build`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-Api-Key': API_KEY },
body: JSON.stringify({
changeAddress: address,
utxos,
outputs: [{ address: 'addr_test1qy...', lovelace: 5_000_000 }]
})
});Additional options: query by stakeAddress to get UTXOs across all derived addresses, or enable includeMempool for chained transactions. See Wallet Endpoints for full parameter documentation.
Other UTXO sources (BlockFrost, Ogmios, Dolos, etc.) work with Anvil's transaction builder as long as UTXOs are hex-CBOR encoded.
Related: Transaction Building · Wallet Endpoints