The core primitive: the wallet

Budget management in Trove starts with the wallet. A wallet is a spending container attached to a single agent. It has a hard budget limit, a current balance, and a transaction ledger. Every API call your agent makes goes through the wallet — and the wallet enforces the limit before any charge commits.

This is different from setting a credit limit on a card. The wallet API is programmatic: your agent's code calls POST /api/wallets/:id/purchase with an amount, and the wallet decides whether to record the transaction or return a 402. No human involvement, no card decline surprise, no external processor interference.

Base URL: https://trove-qjow.polsia.app/api — All requests require X-Trove-Key: tvpk_your_api_key header. All amounts are in USD. All timestamps are ISO 8601.

Endpoint reference

Wallets

POST
/api/wallets
Create a wallet for an agent
JavaScript
const res = await fetch('https://trove-qjow.polsia.app/api/wallets', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Trove-Key': 'tvk_your_key' }, body: JSON.stringify({ agent_id: 'support-bot-v2', name: 'Support Bot June Budget', budget_limit_usd: 100.00 }) }); const { wallet } = await res.json(); // wallet.id, wallet.budget_limit_usd, wallet.balance_usd, wallet.status
Python
import httpx res = httpx.post( 'https://trove-qjow.polsia.app/api/wallets', headers={'X-Trove-Key': 'tvk_your_key'}, json={ 'agent_id': 'support-bot-v2', 'name': 'Support Bot June Budget', 'budget_limit_usd': 100.00 } ) wallet = res.json()['wallet']
GET
/api/wallets/:id
Get wallet details
GET
/api/wallets/:id/balance
Get current balance and remaining budget
Balance response
{ "wallet_id": "wa_01HX...", "balance_usd": 23.47, "budget_limit_usd": 100.00, "remaining_budget": 76.53, "transaction_count": 47, "status": "active" }

Spending

POST
/api/wallets/:id/purchase
Record a purchase — enforces budget atomically
JavaScript
const res = await fetch( `https://trove-qjow.polsia.app/api/wallets/${wallet.id}/purchase`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Trove-Key': 'tvk_your_key' }, body: JSON.stringify({ amount_usd: 0.08, vendor: 'openai', description: 'gpt-4o: customer support ticket #8841' }) } ); if (res.status === 402) { // Budget exhausted — skip the OpenAI call const { available } = await res.json(); alertBudgetExhausted(wallet.id, available); } else { // Transaction recorded — proceed }

Top-ups and credits

POST
/api/wallets/:id/topup
Add funds to a wallet
POST
/api/wallets/:id/credit
Credit the wallet (e.g., for a vendor refund)

Transaction history

GET
/api/wallets/:id/transactions
Paginated transaction ledger
JavaScript
const res = await fetch( `https://trove-qjow.polsia.app/api/wallets/${wallet.id}/transactions?limit=20&offset=0`, { headers: { 'X-Trove-Key': 'tvk_your_key' } } ); const { transactions, pagination } = await res.json(); // transactions[0]: { id, amount_usd, vendor, description, created_at }

Analytics

GET
/api/analytics
Aggregate spending across all wallets
JavaScript
const res = await fetch( 'https://trove-qjow.polsia.app/api/analytics?period=30d', { headers: { 'X-Trove-Key': 'tvk_your_key' } } ); const { total_spent, by_vendor, by_wallet, period_start, period_end } = await res.json();

Error codes at a glance

HTTP Scenario Response body
200 Purchase recorded successfully { success: true, transaction_id, new_balance }
402 Over budget { success: false, message: "Insufficient funds", available, requested }
404 Wallet not found { error: "Wallet not found" }
401 Invalid or missing API key { error: "Invalid API key" }
422 Invalid amount (negative, zero, non-numeric) { error: "Invalid amount_usd" }

Putting it together: a budget-aware agent

Here's the full pattern for building an agent that respects its budget. Check the balance before expensive calls, record every purchase through the wallet, and handle the 402 gracefully when the limit is hit.

JavaScript — budget-aware agent
async function callWithBudgetGuard(walletId, amountUsd, callFn) { // 1. Check balance before calling expensive APIs const { remaining_budget } = await fetchBalance(walletId); if (remaining_budget < amountUsd) { console.warn(`Budget too low: $${remaining_budget} left, need $${amountUsd}`); return { skipped: true, reason: 'budget_exhausted' }; } // 2. Make the external API call (OpenAI, Serper, etc.) const result = await callFn(); // 3. Record the purchase through the wallet const purchaseRes = await recordPurchase(walletId, { amount_usd: amountUsd, vendor: result.vendor, description: result.description }); // 4. Handle wallet rejection if (purchaseRes.status === 402) { // This shouldn't happen if the pre-check passed — log and alert alertAnomaly(walletId, 'Purchase failed after balance check'); return { skipped: true, reason: 'purchase_blocked' }; } return { skipped: false, result }; }
Python — budget-aware agent
import httpx async def call_with_budget_guard(wallet_id: str, amount_usd: float, call_fn): balance = fetch_balance(wallet_id) if balance['remaining_budget'] < amount_usd: print(f"Budget too low: ${balance['remaining_budget']} left") return {"skipped": True, "reason": "budget_exhausted"} result = await call_fn() purchase_res = record_purchase(wallet_id, { "amount_usd": amount_usd, "vendor": result["vendor"], "description": result["description"] }) if purchase_res.status_code == 402: print("ERROR: Purchase blocked by wallet — check balance") return {"skipped": True, "reason": "purchase_blocked"} return {"skipped": False, "result": result}

Tracking spend velocity

The balance endpoint gives you a snapshot. For real-time monitoring, poll the analytics endpoint or set up a webhook for budget.threshold_reached (fires when the agent hits 80% of its limit). Here's a simple velocity check:

Check spend velocity (transactions/minute)
const res = await fetch( `https://trove-qjow.polsia.app/api/wallets/${walletId}/transactions?limit=20`, { headers: { 'X-Trove-Key': 'tvk_your_key' } } ); const { transactions } = await res.json(); const last20 = transactions.slice(0, 20); const now = Date.now(); const first = new Date(last20[19].created_at).getTime(); const velocity = (20 / (now - first)) * 60_000; // tx/min if (velocity > 5) { alert(`Unusual velocity: ${velocity.toFixed(1)} tx/min — check for runaway loop`); }

Pro tip: Store the last 100 transactions in a local ring buffer so you can compute velocity without querying the API on every call. Update the buffer when you record a purchase.

Resetting and topping up

Trove wallets do not auto-reset on a calendar schedule — the budget limit is the ceiling, not a recurring allowance. To build a monthly budget cycle, call POST /api/wallets/:id/reset at the start of your billing period:

Reset wallet at billing cycle start
// Monthly reset — call this on the 1st of each month await fetch( `https://trove-qjow.polsia.app/api/wallets/${walletId}/reset`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Trove-Key': 'tvk_your_key' }, body: JSON.stringify({ reset_balance_to: 0, topup_amount: 100.00 }) } );

This resets the balance to zero, then adds the top-up amount. The transaction ledger is preserved for historical reporting — your monthly spend data is never lost.

Test the full API in the playground

Sandbox wallet with $100. Make purchases, hit the 402, test the reset. No setup required.

Open the Playground

Full endpoint summary

Method Endpoint Description
POST /api/wallets Create a wallet for an agent
GET /api/wallets List all wallets on your API key
GET /api/wallets/:id Get wallet details
GET /api/wallets/:id/balance Get current balance and remaining budget
POST /api/wallets/:id/purchase Record a purchase (enforces budget)
POST /api/wallets/:id/topup Add funds to the wallet
POST /api/wallets/:id/credit Credit the wallet (e.g., refund)
POST /api/wallets/:id/reset Reset balance and optionally top up
GET /api/wallets/:id/transactions Paginated transaction ledger
GET /api/analytics Aggregate spend across all wallets

For webhook integration, authentication details, and SDK setup, see the full API documentation.