Skip to main content
A wallet belongs to an identity — at most one live wallet per identity per network. It holds USDC on Base (the test network by default; mainnet is enabled per organization by its owner) at a custody provider that keeps the key: Vetta holds the public address, the policy and the ledger, and asks the provider to sign. An agent can spend only when its session selected the identity that owns the wallet.

Testnet and mainnet

Every identity starts on the test network (eip155:84532, funded from a faucet). Once the organization’s owner has enabled mainnet, the same identity may hold a second wallet on Base (eip155:8453) with real USDC. The two wallets are independent — separate address, balance, caps, frozen state and ledger — and every surface says which one it means: ?network= on the API, a trailing { network } in the SDK, --network base-testnet | base in the CLI, an optional network on the agent tools, and a Testnet | Mainnet switch at the top of the wallet page. Nothing ever falls back to the other network: with Mainnet selected the page shows the mainnet wallet or an empty state to create one, never the testnet balance, and a sibling transfer lands in the recipient’s wallet on the sender’s network or is refused.

Wallet vs. credits — two different moneys

The two never draw from each other: a short wallet balance is validation_failed, never insufficient_credits.

How it works

  1. POST /v1/identities/{id}/wallet provisions the wallet. The policy — per-transaction cap (default $0.50), daily cap — is attached at the provider before the wallet exists.
  2. Fund it with POST …/wallet/fund: the test faucet (testnet only, a fixed 1 USDC per request) or the organization’s treasury once the owner has provisioned one.
  3. The agent probes a paywalled URL with wallet.quote (no side effects) and pays with wallet.pay, which spends the smaller of its request ceiling and the per-transaction cap, reserves the daily budget, retries the request with the payment attached and records a receipt. Each tool takes an optional network and works on the testnet wallet without one.
  4. Every fund, transfer, payment and sweep is a wallet_transaction under GET …/wallet/transactions; receipts are ?kind=pay.
  5. freeze stops spending at the provider; sweep drains the balance and retires the wallet as swept. A retired wallet stays in the ledger and a fresh one may be provisioned in its place.
The caps are enforced twice: the provider refuses to sign any payment above the per-transaction cap (so a cap holds even if Vetta is wrong), and Vetta’s own durable daily counter refuses a spend that would cross the daily cap before anything is signed. A wallet’s balance is read live from the provider on every read; Vetta never caches it.

Agent tools

wallet.balance, wallet.transactions, wallet.receipts and wallet.quote are reads and run under the agent’s ordinary policy. wallet.pay and wallet.transfer default to ask, including when the agent’s default tool policy is allow: the session pauses, the operator sees the URL or the recipient and the amount in micro-USD, and nothing is signed until they approve. Provisioning, policy, funding and sweeping are operator actions with no tool. The tools work on the wallet of the identity the session selected, and only when the deployment has a custody provider bound — otherwise the agent simply has no wallet tools. Each tool answers the same safe projection the API does: an address, a policy, a ledger, never a key.

In a blueprint

Each declaration is the body of POST /v1/identities/{id}/wallet — one object, or a list with at most one per network. naive up creates the wallet on that network if the identity has none there and patches policy when a declared cap differs; it never funds, freezes or sweeps one, a frozen wallet’s policy is refused until it is unfrozen, and a wallet on a network the declaration does not name is never read or touched. A mainnet declaration reports as Ava / wallet eip155:8453.

Wallet API

Provision, cap, fund, transfer, sweep, and pay for paywalled resources.