Economic Authorization
Cost-aware authorization for AI agents that spend money. Budget enforcement, payer validation, and protocol connectors.
Economic authorization adds cost-aware policy enforcement to veto.guard() and veto.wrap(). When a tool call carries a price, Veto validates the payer, checks the cost against scoped budgets, and returns allow, deny, or require_approval.
Three payment protocols are supported out of the box: x402 (HTTP 402), Stripe MPP (Managed Payment Protocol), and Google AP2 (Agent Payments Protocol). Each has a connector that extracts economic context automatically.
Pipeline: cost validation → payer check → budget check → allow / deny / require_approval.
Quick start
Use the @veto/economic-agent policy pack to get sensible defaults:
version: "1.0"
extends: "@veto/economic-agent"Then pass economic context to veto.guard():
import { Veto, type EconomicContext } from 'veto-sdk';
const veto = await Veto.init();
const result = await veto.guard('purchase', { item: 'GPU', quantity: 1 }, {
economic: {
cost: 42.50,
currency: 'USD',
payer: 'team-wallet',
protocol: 'custom',
}
});
if (result.decision === 'deny') {
console.log(result.economicDenial);
// { reason: 'budget_exceeded', budget_scope: 'session', budget_limit: 100, budget_spent: 80, budget_remaining: 20 }
}The economic field on the options object triggers the economic evaluator. Without it, standard policy evaluation runs as usual.
Policy configuration
Add an economic section to your veto.config.yaml:
economic:
budgets:
- scope: session
limit: 100.00
currency: USD
approval_threshold: 25.00
window: session
cost_extraction:
default: "arguments.cost"
overrides:
search_api: "arguments.price_usd"
trade: "arguments.amount"
payer:
required: true
approved: ["team-wallet", "research-budget"]
denial_reasons:
budget_exceeded: "Would exceed {scope} budget ({spent}/{limit} {currency})"
approval_required: "Cost {cost} exceeds threshold {threshold}"
payer_missing: "No payer identified"
payer_unauthorized: "Payer {payer} not approved"Budget scopes
| Scope | Engine | Description |
|---|---|---|
session | LocalBudgetEngine (in-memory) | Resets per SDK session. No server needed. |
agent | CloudBudgetEngine (Veto Cloud) | Tracks across sessions for one agent identity. |
user | CloudBudgetEngine (Veto Cloud) | Tracks across agents for one user. |
global | CloudBudgetEngine (Veto Cloud) | Organization-wide budget. |
session is local-only and works offline. The other three scopes require a Veto Cloud connection to maintain ledger state across processes.
Cost extraction
cost_extraction.default sets the dot-path used to read the cost from tool call arguments when no tool-specific override exists. For example, "arguments.cost" reads args.cost.
cost_extraction.overrides maps individual tool names to their own dot-path. If a tool appears in overrides, its path takes priority over default.
If the resolved value is not a finite non-negative number, the evaluator denies with invalid_cost.
Denial reasons
Seven reason codes the economic evaluator can return:
| Code | When |
|---|---|
budget_exceeded | Cost would push spending over the scope limit. |
approval_required | Cost exceeds the approval_threshold but is within budget. |
payer_missing | No payer identified and payer.required is true. |
payer_unauthorized | Payer not in the approved list. |
currency_mismatch | Tool call currency does not match budget currency. |
invalid_cost | Cost is NaN, Infinity, or negative. |
connector_error | Protocol connector failed to parse economic context. |
All denial reasons can be customized in the denial_reasons section using {variable} interpolation.
Protocol connectors
Connectors extract EconomicContext from protocol-specific signals. They are auto-detected when using wrapFetch(), or you can call extract() manually:
import { createX402Connector, createMPPConnector, createAP2Connector } from 'veto-sdk';
// Manual extraction from an HTTP response
const x402 = createX402Connector();
const context = x402.extract(httpResponse);
if (context) {
const result = await veto.guard('api_call', args, { economic: context });
}| Protocol | Signal | Use case |
|---|---|---|
| x402 | HTTP 402 + X-Payment-* headers | Pay-per-call APIs |
| MPP | Stripe session metadata | SaaS billing, managed payments |
| AP2 | Google mandate constraints | Agent-to-agent payments, spending caps |
Each connector implements the same interface: extract(input) returns an EconomicContext or null if the signal is not present.
Evaluation pipeline
Steps are evaluated in order. The first deny short-circuits — later steps are skipped. require_approval is only returned if no step denied outright.
Related
- Budget Constraints — basic per-session cost limits
- Economic API — cloud API endpoints
- Policy Packs —
@veto/economic-agentpack