The hot-path constraint
SaaS billing can be hours behind. A monthly invoice, reconciled later, is fine when humans drive the system. Agent billing lives in the hot path. Before every tool call, an agent needs to know:- How much credit is left?
- Does this plan allow this action?
- What’s the daily limit?
- Is the price quote still valid?
What OneShot provides
| Capability | What it gives you | Reference |
|---|---|---|
| Atomic balance ledger | Single-call holdBalance / debitBalance / refundBalance with a SQL-level guard so concurrent debits can’t double-spend. Every mutation logged for audit. | Compute budget |
| Quote cache | Redis-backed quote validation with single-use tracking and TTL cleanup. Hot-path lookup well under 50 ms. | Pricing, email quote |
| Receipt ledger | Every paid call writes a categorized receipt — commerce / data / verification / communication / infrastructure / agent_to_agent — with provider cost, service fee, status, and optional memo + decisionContext. Rolls up by category, period, agent without you wiring ClickHouse. | Analytics, Audit Trail |
| Subscription renewer | Daily Cloud Scheduler cron, idempotent. Auto-debits on renewal, falls back to expired when funds run out. Stripe-billed subs are webhook-driven through the same state machine. | — |
| Hot-path budget checks | reserveBudget() atomically reserves the estimated cost before dispatch and returns 402 Payment Required if the cap would be exceeded. Spend alert at 80%. | Compute budget |
| x402 settlement, native | Payments settle on Base in USDC via x402. SDK signs an EIP-712 TransferWithAuthorization; the API verifies and settles. Stripe ACP is the alternate path for LLM agents on SharedPaymentTokens. | Pricing, Stripe ACP |
Latency budget
The 50 ms target sets the ceiling for everything in the request path:| Step | Target |
|---|---|
| Quote lookup (cached) | < 5 ms |
| Balance check + reserve | < 15 ms |
| x402 signature verification | < 20 ms |
| Total before tool dispatch | < 50 ms |
WHERE balance >= amount guard so the check and the debit can’t disagree. Settlement happens on Base after the call returns; the agent never blocks on chain confirmation.
Why this is hard to build
Each piece is straightforward in isolation. The trouble is the seams:- Hold/refund races. Two parallel tool calls reserving against the same budget. Without an atomic SQL guard, you double-book and over-spend a daily limit.
- Period-rollover edge cases. A subscription renews at 00:00 UTC, the renewal cron fires at 00:05, but the agent calls a tool at 00:02. Was that period 1 or period 2? Idempotent renewals + a stable
currentPeriodEndcheck on every tool call answer it. - Subscription state divergence. Stripe says active, your DB says expired (webhook lost). On-chain says paid, your DB says pending (block reorg). Both need a reconciliation step that doesn’t double-credit.
- Receipt taxonomy. “Spent $47 last week” is useless without categorization. Tagging at write time (instead of an offline analytics job) keeps the rollups fast and consistent.
When to use OneShot
Use OneShot when:- Your agents call tools tens of times per task.
- You need per-call budgets, daily limits, or per-tool spend visibility.
- You ship to multiple agent frameworks (LangChain, Virtuals, MCP) and want one billing surface.
- You want to settle in USDC on Base without writing the EIP-712 + x402 plumbing yourself.
- Your agent only makes a handful of paid calls per session.
- Monthly invoicing fits the customer relationship.
- You don’t need crypto rails.