Valta Docs
Build Your First Governed Agent
This tutorial builds a CFO Agent that checks wallet balances and reports on spending. You will create the agent, attach a spending policy, run it, read the audit trail, and clean up.
Prerequisites
valta-sdkinstalled (npm install valta-sdk)VALTA_API_KEYset in your environment
Complete working example
import { ValtaClient } from 'valta-sdk'
const valta = new ValtaClient({
apiKey: process.env.VALTA_API_KEY!,
})
async function main() {
// 1. Create the agent
const agent = await valta.agents.create({
name: 'CFO Agent',
description: 'Monitors wallet balances and reports on spending anomalies',
})
console.log(`✓ Agent created: ${agent.id}`)
// 2. Set a spending policy
await valta.policies.create({
agentId: agent.id,
dailyLimit: 100,
maxPerTransaction: 25,
requireApprovalAbove: 50,
blockedCategories: ['gambling', 'adult'],
})
console.log('✓ Policy set')
// 3. Check the wallet
const wallet = await valta.wallets.get(agent.id)
console.log(`✓ Wallet: ${wallet.balance} ${wallet.currency}`)
// 4. Run the agent
const run = await valta.agents.run(agent.id, {
task: 'Check the current wallet balance and write a one-sentence summary of the financial position.',
})
if (run.status === 'completed') {
console.log(`✓ Run completed in ${run.durationMs}ms`)
console.log(` Output: ${run.summary}`)
} else if (run.status === 'failed') {
console.log(`✗ Run failed: ${run.error}`)
} else if (run.status === 'awaiting_approval') {
console.log('! Approval required before agent can continue')
// Approve or deny via dashboard or API
}
// 5. Prove the policy is real: deliberately send a spend over the $25
// per-transaction limit and watch it get denied BEFORE any money moves.
const denied = await valta.spend({
agent: agent.id,
amount: 30,
purpose: 'over-limit test',
})
console.log(`✓ Over-limit spend approved: ${denied.approved}`) // false
console.log(` Reason: ${denied.reason}`)
// 6. Read the audit trail — the deny above wrote a real entry
const { data: entries } = await valta.audit.list({ agentId: agent.id })
console.log(`✓ Audit trail: ${entries.length} entries`)
for (const entry of entries.slice(0, 3)) {
console.log(` ${new Date(entry.createdAt).toLocaleTimeString()} — ${entry.action}`)
}
// 7. Clean up (optional)
await valta.agents.delete(agent.id)
console.log('✓ Agent deleted')
}
main().catch(console.error)
What each step does
Step 1 — Create the agent. Valta allocates an isolated USDC wallet and returns an agent ID. The agent is active and ready to receive a policy.
Step 2 — Set a spending policy. The policy is stored in the Valta backend, not in a prompt. The agent cannot spend more than $25 in a single transaction or $100 in a day. Any action above $50 pauses and waits for your explicit approval.
Step 3 — Check the wallet. The wallet starts with a zero balance. You can fund it via the dashboard or the deposits API. The CFO Agent can report on whatever balance is present.
Step 4 — Run the agent. Valta runs the agent, enforces the policy on every attempted action, and returns a result. The status field will be one of completed, failed, or awaiting_approval.
Step 5 — Prove the policy is real. Setting a limit and never testing it is just a number in a database. Deliberately requesting $30 against a $25 per-transaction limit forces a real deny — the request is rejected before any balance is touched, and reason tells you exactly which limit was hit.
Step 6 — Read the audit trail. Every run, tool call, policy check, and blocked action is recorded in the hash-chained audit trail — including the deny from Step 5. The entries you see here are the raw evidence of what the agent did.
Step 7 — Clean up. Deleting the agent removes it from your account but does not erase the audit trail. Audit records are retained according to your plan's retention policy.
Expected output
This is real output — action entries on Valta are human-readable sentences generated at the moment of the decision, not a fixed set of event-type codes. Yours will differ in exact wording/amount but will follow this shape:
✓ Agent created: agt_01j...
✓ Policy set
✓ Wallet: 0.00 USDC
✓ Run completed in 1842ms
Output: The CFO Agent wallet currently holds a zero balance with no active spending.
✓ Over-limit spend approved: false
Reason: Amount $30 exceeds per-transaction limit of $25 on wallet "CFO Agent"
✓ Audit trail: 1 entries
09:14:05 — Spend of $30 denied by spending policy
✓ Agent deleted
What the audit trail contains
Each entry includes an action string (a real sentence describing exactly what happened, not a machine code), a timestamp, the agent ID, and a hash linking it to the previous entry. Real examples, pulled directly from the actual route handlers rather than invented for this page:
Spend of $30 denied by spending policySpend of $25 approved from wallet "CFO Agent"Spend of $50 requires approvalSpend of $10 denied — insufficient balance
There is no fixed enum of action strings to parse against — treat action as a human-readable audit line, and use reason/status on the API response itself for anything your code needs to branch on programmatically.