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
Atomic balance ledger
Single-call
holdBalance / debitBalance / refundBalance with SQL-level guards so two concurrent debits can’t double-spend a balance. Every mutation logs to a transaction table for audit.See the per-goal budget endpoints for how this surfaces over the API.Quote cache
Quotes are validated through a Redis cache before the SQL fall-through, with single-use tracking and TTL-driven cleanup. The hot-path lookup stays well under the 50 ms budget.See Pricing and the email quote endpoint.
Receipt ledger + analytics
Every tool call writes a categorized receipt (
commerce, data, verification, communication, infrastructure, agent_to_agent) with provider cost, service fee, and outcome status. Spend rolls up by category, period, or agent without you wiring ClickHouse.See /spend/breakdown, /rocs, and /receipts under the analytics endpoints.Subscription renewer
A daily Cloud Scheduler cron handles period rollover. Idempotent. Auto-debits the player balance on renewal and falls back to
expired when funds are insufficient. Stripe-billed subscriptions are webhook-driven through the same state machine.Pending → active → expired, with dual billing methods (USDC wallet or Stripe ACP).Hot-path budget checks
Before any tool dispatch,
reserveBudget() atomically checks the goal’s remaining budget, reserves the estimated cost, and returns 402 Payment Required if the cap would be exceeded. Spend alerts fire at the 80% threshold.See Compute budget endpoints.x402 settlement, native
Payments settle on Base in USDC via the x402 protocol. The SDK signs an EIP-712
TransferWithAuthorization; the API verifies and settles. Stripe ACP works as an alternate path for LLM agents using SharedPaymentTokens.See Pricing and 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.