Dexter
Dexter
Docs

Budget Accounts

Budget Accounts solve the number one problem with autonomous agent payments: trust. Nobody wants to hand an AI agent a private key without guardrails. Budget Accounts wrap the x402 client with spending controls so agents can pay for APIs within limits you define.

Best Fit

Use Budget Accounts when:

  • an AI agent needs to spend money autonomously
  • you want hard limits on total spend, per-request cost, or hourly rate
  • you need a domain allowlist to restrict which APIs the agent can pay
  • you want a payment ledger for auditing agent spending

Minimal Example

import { createBudgetAccount } from '@dexterai/x402/client';
 
const agent = createBudgetAccount({
  walletPrivateKey: process.env.SOLANA_PRIVATE_KEY,
  budget: { total: '50.00' },
});
 
const response = await agent.fetch('https://api.example.com/data');
console.log(agent.spent);       // '$0.05'
console.log(agent.remaining);   // '$49.95'
console.log(agent.payments);    // 1

What This Does

  1. Wraps wrapFetch with budget enforcement via onPaymentRequired
  2. Before signing any payment, checks: total budget, per-request cap, hourly limit
  3. If any limit is exceeded, throws X402Error with code amount_exceeds_max
  4. After payment, records amount, domain, network, and timestamp in the ledger
  5. Exposes real-time spend tracking via spent, remaining, payments, hourlySpend

Full Configuration

const agent = createBudgetAccount({
  // Wallet keys (same as wrapFetch)
  walletPrivateKey: process.env.SOLANA_PRIVATE_KEY,
  evmPrivateKey: process.env.EVM_PRIVATE_KEY,
 
  // Spending limits
  budget: {
    total: '100.00',      // $100 total budget
    perRequest: '5.00',   // max $5 per single request
    perHour: '25.00',     // max $25 per rolling hour
  },
 
  // Only allow payments to these domains
  allowedDomains: ['api.example.com', 'data.example.com'],
 
  // All wrapFetch options also work
  preferredNetwork: 'eip155:8453',
  verbose: true,
});

Spend Tracking

agent.spent;           // '$12.34' (formatted)
agent.remaining;       // '$87.66' (formatted)
agent.spentAmount;     // 12.34 (raw number)
agent.remainingAmount; // 87.66 (raw number)
agent.payments;        // 5 (count)
agent.hourlySpend;     // 8.50 (rolling 1-hour window)
 
// Full payment history
for (const record of agent.ledger) {
  console.log(`${record.domain}: $${record.amount} on ${record.network}`);
}
 
// Reset budget (clears ledger)
agent.reset();

Error Handling

When a budget limit is hit, the SDK throws before signing — no money is spent:

try {
  await agent.fetch(url);
} catch (err) {
  if (err.code === 'amount_exceeds_max') {
    console.log('Budget limit hit:', err.message);
    // "Budget exceeded. Spent $98.50 of $100.00, payment: $2.50"
    // "Hourly limit ($25.00) exceeded. Spent $24.80 this hour"
    // "$6.00 exceeds per-request limit of $5.00"
  }
}

Domain Allowlist

When allowedDomains is set, the agent can only pay APIs on those domains. Subdomains are included automatically.

const agent = createBudgetAccount({
  walletPrivateKey: key,
  budget: { total: '50.00' },
  allowedDomains: ['api.example.com'],
});
 
await agent.fetch('https://api.example.com/data');      // allowed
await agent.fetch('https://sub.api.example.com/data');  // allowed (subdomain)
await agent.fetch('https://evil.com/data');              // throws: "Domain not in allowed domains"

Combining with Other Features

Budget Accounts work with all SDK features:

const agent = createBudgetAccount({
  walletPrivateKey: key,
  budget: { total: '50.00' },
  accessPass: { preferTier: '1h' },   // buy access passes within budget
  verbose: true,
});

When To Use Something Else

On this page